1

这是我的源图像(忽略这些点,它们是稍后手动添加的):

在此处输入图像描述

我的目标是获得两只手的粗略多边形近似。像这样的东西:

在此处输入图像描述

我对如何做到这一点有一个大致的想法;我想用它cvCanny来寻找边缘,cvFindContours寻找轮廓,然后cvApproxPoly.

我面临的问题是我不知道如何正确使用cvCanny,特别是最后3个参数(threshold1&2,apertureSize)我应该使用什么?我试着做:

cvCanny(source, cannyProcessedImage, 20, 40, 3);

但结果并不理想。左手看起来比较好,但右手检测得很少:

在此处输入图像描述

一般来说,它不像我想要的那样可靠。有没有办法猜测 Canny 的“最佳”参数,或者至少对他们所做的事情进行详细解释(初学者可以理解),以便我可以做出有根据的猜测?或者也许有更好的方法来完全做到这一点?

4

2 回答 2

6

看来你必须降低你的门槛。

Canny 算法在滞后阈值上工作:如果至少一个像素与最大阈值一样亮,则它选择一个轮廓,如果它们高于下阈值,则取所有连接的轮廓像素。

论文建议以 2:1 或 3:1 的比例取两个阈值(例如 10 和 30,或 20 和 60 等)。对于某些应用程序,手动确定和硬编码的阈值就足够了。它也可能是你的情况。我怀疑如果你降低阈值,你会得到很好的结果,因为图像并不那么复杂。

已经提出了许多自动确定最佳精明阈值的方法。他们中的大多数依靠梯度幅度来估计最佳阈值。

脚步:

  • 提取梯度(Sobel 是一个不错的选择)
  • 您可以将其转换为 uchar。梯度理论上可以有比 255 更大的数值,但这没关系。opencv 的 sobel 返回 uchars。
  • 制作结果图像的直方图。
  • 在直方图的第 95 个百分位处取最大阈值,将较低的阈值设为 high/3。
  • 您可能应该根据您的应用程序调整百分位值,但结果将比硬编码的高值和低值更稳健

注意:在 Matlab 中实现了一个出色的阈值检测算法。它基于上面的想法,但更复杂一些。

注意 2:如果图像区域之间的轮廓和光照变化不大,则此方法将起作用。如果图像的某个部分的轮廓更清晰,那么您需要局部自适应阈值,这是另一回事。但是看你的照片,应该不是这样的。

于 2012-07-17T06:00:32.280 回答
4

也许最简单的解决方案之一是对灰度图像进行 Otsu 阈值化,在二值图像上找到轮廓,然后对其进行近似。这是代码:

Mat img = imread("test.png"), gray;
vector<Vec4i> hierarchy;
vector<vector<Point2i> > contours;

cvtColor(img, gray, CV_BGR2GRAY);
threshold(gray, gray, 0, 255, THRESH_OTSU);
findContours(gray, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

for(size_t i=0; i<contours.size(); i++)
{
    approxPolyDP(contours[i], contours[i], 5, false);
    drawContours(img, contours, i, Scalar(0,0,255));
}

imshow("result", img);
waitKey();

这是结果:

在此处输入图像描述

于 2012-07-17T06:51:26.487 回答