我正在使用canny边缘检测和发现轮廓函数(均为OpenCV)来创建分水岭变换的标记。一切正常,但我对结果不满意100%。原因是缺少某些边缘,因此丢失了重要信息。更详细地讲,在分水岭变换之后,我得到了一堆矩形的窗口(正 View ),最终得到的是这样的东西:


但我宁愿有一个不错的矩形,该矩形是完整的并且不向一侧敞开。在保持不规则形状的同时(房屋前,汽车前的灌木丛中。)关于如何解决此问题的任何想法?我曾考虑过用网格覆盖整个图像,但我无法使其正常工作。

非常感谢你。

这是我的代码:

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 );

根据要求,这是原始图像,我想要获取的图像以及我的输出:

我想进行这样的 segmentation (尽管过度 segmentation 不会造成伤害,但我只需要确保获得所有详细信息即可):

虽然我得到这样的东西:

(请忽略颜色,它们对于这个问题并不重要,而仅仅是我整个程序的结果)。这只是一个示例,如果您愿意,我可以显示更多,还请查看etrims数据集,我所有的图片都来自此。

最佳答案

两件事情 -

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

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

战略 -

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

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

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

使用此策略,我得到以下 segmentation 。

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

这些并非完全是预期的 segmentation (未检测到某些对象,例如汽车),但这是一个良好的开端。

编辑:用于生成图像的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')

关于c++ - OpenCV Canny +分水岭,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21060804/

10-08 21:09