我正在使用canny边缘检测和查找轮廓功能(两个OpenCV)来创建分水岭变换的标记。一切正常,但我对结果并不是百分之百满意。原因是缺少一些边缘,因此丢失了重要信息。更详细的说,我得到了一堆窗口(前视图),它们是矩形,在分水岭变换之后我最终得到了这样的东西:
但我宁愿有漂亮的矩形,这些矩形是完整的,不向一边开放。同时保持不规则的形状(房子前面的灌木,汽车..)任何想法如何解决这个问题?我想用网格覆盖整个图像,但我不能让它工作。
非常感谢。
这是我的代码:
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数据集,我的所有图片都来自那里。
答案 0 :(得分:5)
两件事 -
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')
答案 1 :(得分:0)
从所需输出和程序输出的外观来看,边缘检测器似乎正在寻找假边缘。 Canny边缘检测器包含一个低通滤波器,但在实际运行Canny边缘检测器之前,它可能有助于您执行单独的高斯低通滤波步骤。
除此之外,很难达到预期的效果。例如,查看图片中最顶部的窗口。它们有不同的颜色 - 框架,框架的阴影和窗口。这些颜色的边界将被边缘检测器检测为边缘。