检测多模灰度图像上的模糊矩形

时间:2012-10-30 22:03:56

标签: image-processing opencv feature-detection

我有以下图片rectangle pattern board

我正在尝试找到主矩形的像素坐标(白线之间的像素坐标)。我尝试了一些东西,但我无法获得足够好的解决方案。如果没有检测到所有矩形(特别是那些非常小的矩形),解决方案就不一定非常完美。虽然角落位置必须尽可能精确,特别是那些更大的模糊(我正在尝试编写一些简单的AR引擎)。

我可以澄清只有4级灰阶:0,110,180和255(打印时,没有屏幕会因闪电和阴影而变化)

到目前为止,我尝试过几件事:

  1. 手动多级阈值处理(因为阴影和不同的闪电不起作用)
  2. 自适应阈值处理:2个问题:
    • 它将180和255种颜色组合成白色,将0,110组合成黑色
    • 模糊(较大)矩形的边缘/角落位置不准确(它会增加矩形区域的模糊)
  3. sobel边缘检测(模糊矩形的角更尖锐,但它也检测矩形的内边缘,这些边缘轮廓也不总是关闭
  4. 看起来将两者结合起来会以某种方式产生更好的结果。或者也许有人有不同的想法?

    我还在考虑做洪水填充,但很难找到确定好的种子点和阈值(背景中可能还有其他一些白色物体)。此外,我希望稍后对GPU进行优化,而泛洪算法则不适合这种情况。

    以下是我到目前为止尝试的一些示例代码:

    image = cv2.imread('data/image.jpg');
    gray  = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    cv2.imshow('image', gray) 
    
    
    adaptive = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 601, 0)
    cv2.imshow('adaptive', adaptive)
    
    
    gradx = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=3)
    grady = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=0, dy=1, ksize=3)
    abs_gradx = cv2.convertScaleAbs(grady)
    abs_grady = cv2.convertScaleAbs(grady)
    grad = cv2.addWeighted(abs_gradx, 0.5, abs_grady, 0.5, 0)
    
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
    grad = cv2.morphologyEx(grad, cv2.MORPH_OPEN, kernel)
    grad = cv2.morphologyEx(grad, cv2.MORPH_CLOSE, kernel)
    cv2.imshow('sobel',grad)
    
    
    #kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(7,7))
    #grad = cv2.morphologyEx(grad, cv2.MORPH_OPEN, kernel)
    retval, grad = cv2.threshold(grad, 10, 255, cv2.THRESH_BINARY)
    cv2.imshow('sobel+morph+thrs',grad)
    
    cv2.waitKey()
    

2 个答案:

答案 0 :(得分:3)

我相信你的答案在于使用Hough变换来检测线条,延伸这些线条以跨越较暗的正方形之间的断点,然后寻找标记出角落的交叉点。我已经在Matlab中快速发挥并提出了以下内容,它并不完美,但应该显示出潜力:

% Open image
i = imread('http://i.stack.imgur.com/kwcXm.jpg');

% Use a sharpening filter to enhance some of the edges
H = fspecial('unsharp');
i = imfilter(i, H, 'replicate');
% Detect edge segments using canny
BW = edge(i, 'canny');

% Apply hough transform to edges
[H, T, R] = hough(BW, 'RhoResolution', 0.5, 'Theta', -90:0.5:89.5);
% Find peaks in hough transform
P = houghpeaks(H, 5, 'threshold', ceil(0.1*max(H(:))));
% Extract lines from peaks, extending partial lines
lines = houghlines(BW, T, R, P, 'FillGap', 100, 'MinLength', 5);

% Plot detected lines on image
imshow(i); hold on;
for k = 1:length(lines)
   xy = [lines(k).point1; lines(k).point2];
   plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');
end

最终结果:

Final Result

显然还有改进的余地,还有许多线路要检测,但是如果调整各种参数不起作用,你可以采取初始结果并搜索更多具有相似角度的线条以获得更完整的设置。然后可以从交叉点找到角点,这应该足够简单以便提取。

答案 1 :(得分:0)

我会尝试以下方法:

  • Hough transform检测所有直线
  • 查找以下平行线组:
    • 相隔足够的距离
    • 以浅色分开

有一些事情会让你的问题变得比它需要的更棘手:

  • 透视失真
  • 灯光,小阴影的变化

如果你可以尽量减少上述问题,它可能有助于解决问题。