查找填充网格元素

1 投票
1 回答
778 浏览
提问于 2025-04-18 02:18

我正在尝试找到网格中的一些元素,比如里面有圆圈、叉号或者其他填充的东西。我使用了这里的代码来构建我的逻辑。

逻辑是这样的:首先找到网格的坐标 -> 使用每个矩形块的左上角和右下角坐标提取子图像 -> 计算非零像素的数量 -> 如果矩形的填充面积超过50%,就认为它是填充的。

如果网格是空的,我能成功找到所有的网格坐标。然而,如果任何网格元素被填充,事情就不会像预期那样工作,正如你在图片中看到的那样。我该如何修复这段代码,以确保每次都能成功确定所有网格坐标呢?

image.png res2.png res3.png res4.png res5.png res6.png

import cv2
import cv
import numpy as np
import operator
from PIL import Image
import math


region = cv2.imread("image.png")
img = cv2.GaussianBlur(region,(5,5),0)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
mask = np.zeros((gray.shape),np.uint8)
kernel1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(11,11))

close = cv2.morphologyEx(gray,cv2.MORPH_CLOSE,kernel1)
div = np.float32(gray)/(close)
res = np.uint8(cv2.normalize(div,div,0,255,cv2.NORM_MINMAX))
res2 = cv2.cvtColor(res,cv2.COLOR_GRAY2BGR)

##finding rectangles & creating mask image
thresh = cv2.adaptiveThreshold(res,255,0,1,19,2)
contour,hier = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

max_area = 0
best_cnt = None
for cnt in contour:
    area = cv2.contourArea(cnt)
    if area > 1000:
        if area > max_area:
            max_area = area
            best_cnt = cnt

cv2.drawContours(mask,[best_cnt],0,255,-1)
cv2.drawContours(mask,[best_cnt],0,0,2)

res = cv2.bitwise_and(res,mask)
cv2.imwrite("res2.png",res)

##Finding vertical lines
kernelx = cv2.getStructuringElement(cv2.MORPH_RECT,(2,10))

dx = cv2.Sobel(res,cv2.CV_16S,1,0)
dx = cv2.convertScaleAbs(dx)
cv2.normalize(dx,dx,0,255,cv2.NORM_MINMAX)
ret,close = cv2.threshold(dx,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
close = cv2.morphologyEx(close,cv2.MORPH_DILATE,kernelx,iterations = 1)

contour, hier = cv2.findContours(close,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for cnt in contour:
    x,y,w,h = cv2.boundingRect(cnt)
    if h/w > 5:
        cv2.drawContours(close,[cnt],0,255,-1)
    else:
        cv2.drawContours(close,[cnt],0,0,-1)
close = cv2.morphologyEx(close,cv2.MORPH_CLOSE,None,iterations = 2)
closex = close.copy()
cv2.imwrite("res3.png",closex)

##Finding horizontal lines
kernely = cv2.getStructuringElement(cv2.MORPH_RECT,(10,2))
dy = cv2.Sobel(res,cv2.CV_16S,0,2)
dy = cv2.convertScaleAbs(dy)
cv2.normalize(dy,dy,0,255,cv2.NORM_MINMAX)
ret,close = cv2.threshold(dy,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
close = cv2.morphologyEx(close,cv2.MORPH_DILATE,kernely)

contour, hier = cv2.findContours(close,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for cnt in contour:
    x,y,w,h = cv2.boundingRect(cnt)
    if w/h > 5:
        cv2.drawContours(close,[cnt],0,255,-1)
    else:
        cv2.drawContours(close,[cnt],0,0,-1)

close = cv2.morphologyEx(close,cv2.MORPH_DILATE,None,iterations = 2)
closey = close.copy()
cv2.imwrite("res4.png",closey)

##Finding grid points
res = cv2.bitwise_and(closex,closey)
cv2.imwrite("res5.png",res)

1 个回答

0

使用霍夫变换来检测线条,具体可以参考OpenCV的霍夫变换。这种方法对遮挡和光照变化很有抵抗力。你还可以假设水平线和垂直线之间的距离是相等的,所以只需要检测两条水平线和两条垂直线就可以了。

撰写回答