10

我正在使用精明的边缘检测和寻找轮廓功能(都是 OpenCV)来为分水岭变换创建标记。一切正常,但我对结果不是 100% 满意。原因是缺少一些边缘,因此丢失了重要信息。更详细地说,我得到了一堆窗口(前视图),它们是矩形,在分水岭变换之后,我最终得到了这样的结果:

在此处输入图像描述 在此处输入图像描述 但我宁愿有漂亮的矩形,它们是完整的,不是向一侧开放的。在保持不规则形状的同时(房子前面的灌木丛,汽车..)有什么想法可以解决这个问题吗?我想过用网格覆盖整个图像,但我不能让它工作。

非常感谢。

这是我的代码:

Mat gray;
cvtColor(im, gray, CV_BGR2GRAY);

// Use Canny instead of threshold to catch squares with gradient shading
Mat bw;
Canny(gray, bw, 0, 100, 5, true);

// Find contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;

findContours( bw, contours, hierarchy,
    CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );


// watershed
Mat markers(bw.size(), CV_32S);
markers = Scalar::all(0);
int idx = 0;
int compCount = 0;
for( ; idx >= 0; idx = hierarchy[idx][0], compCount++ ) {
    if (fabs(contourArea(contours[compCount])) < min_size )
        continue;
    drawContours(markers, contours, idx, Scalar::all(compCount+1), 1, 8, hierarchy, INT_MAX);
}
watershed( im, markers );

根据要求,这是原始图像、我想要获取的图像和我的输出: 在此处输入图像描述

我想要这样的分割(虽然过度分割并没有什么坏处,我只需要确保,我得到了所有的细节):

在此处输入图像描述

虽然我得到这样 在此处输入图像描述 的东西:(请忽略颜色,它们对于这个问题并不重要,只是我整个程序的结果)。这只是一个例子,如果你愿意,我可以向你展示更多,也请看一下 etrims 数据集,我所有的图片都来自那里。

4

2 回答 2

7

两件事情 -

1) 如前所述,边缘检测会导致拾取虚假边缘。

2)使用这些边缘作为分水岭分割的标记会导致过度分割,因为每个标记都会在输出中产生一个分割区域

战略 -

(i) 预处理:对图像进行大量平滑(通过重建的形态开口可用于均匀化强度,而不会显着影响您感兴趣的边缘)。

(ii) 标记:我不会使用边缘作为种子,而是使用局部极值。理想情况下,我们希望每个要分割的区域都有一个标记。

(iii) 分割:从步骤 (i) 中找到图像的梯度幅度(范围滤波也是一个不错的选择),并将其用作分割函数。

使用这种策略,我得到以下分割。

在此处输入图像描述

或者,在步骤 (i) 之后,您可以使用 Canny 边缘检测并进行一些形态学清理(以填充轮廓并移除剩余的边缘)。这就是我得到的。

在此处输入图像描述

这些并不完全是预期的分割(未检测到汽车等某些对象),但这是一个好的开始。

编辑:用于生成图像的 MATLAB 代码 -

% convert to grayscale
img = rgb2gray(origImg);

% create an appropriate structuring element
w_size = 20;
seSquare = strel('square', w_size);

% opening by reconstruction - to smooth dark regions
imgEroded = imerode(img, seSquare);
imgRecon = imreconstruct(imgEroded, img);

% invert and repeat - to smooth bright regions
imgReconComp = imcomplement(imgRecon);
imgEroded2 = imerode(imgReconComp, seSquare);
imgRecon2 = imreconstruct(imgEroded2, imgReconComp);

% get foreground markers
fgm = imregionalmax(imgRecon2);

% get background markers - this step can be skipped 
% in which case only fgm would be the marker image 
% and the segmentation would be different 
distTrans = bwdist(fgm);
wLines= watershed(distTrans);
bgm = wLines == 0;

% get the segmentation function and impose markers
% perform watershed segmentation
seSquare3 = strel('square', 3);
rangeImg = rangefilt(imgRecon2, getnhood(seSquare3));
segFunc = imimposemin(rangeImg, fgm | bgm);
grayLabel = watershed(segFunc);

rgbLabel= label2rgb(grayLabel);
figure, imshow(rgbLabel); title('Output using Watershed')

% alternatively, extract edges from the preprocessed image
% perform morph cleanup
bwEdges = edge(imgRecon2, 'canny');
bwFilled = imfill(bwEdges, 'holes');
bwRegions = imopen(bwFilled, seSquare3);
grayLabel = bwlabel(bwRegions);

rgbLabel = label2rgb(grayLabel, 'jet', 'k');
figure, imshow(rgbLabel); title('Output using Canny')
于 2015-05-14T17:00:50.800 回答
0

from the looks of the desired output and the program's output, it seems that the edge detector is finding spurious edges. Canny edge detector contains a low-pass filter, but it might help for you to do a separate Gaussian low-pass filtering step before you actually run the Canny edge detector.

Other than that, it is difficult to achieve the desired result. For e.g., look at the top-most windows in the picture. They have distinct colors --- the frame, the shadow of the frame, and the window. The boundaries of these colors will be detected as edges by the Edge detector.

于 2014-01-11T22:00:09.493 回答