使用 OpenCV 在 2D 图像中感知 Cuboid 的尺寸(或突出点)
Posted
技术标签:
【中文标题】使用 OpenCV 在 2D 图像中感知 Cuboid 的尺寸(或突出点)【英文标题】:Perceive Dimensions (or prominent points) of a Cuboid in a 2D image using OpenCV 【发布时间】:2017-05-30 23:20:20 【问题描述】:我想知道是否可以在如下图所示的图像中找到立方体/长方体的尺寸(以像素为单位)?
我知道这几乎是不可能的,因为没有关于深度、视角等的信息。但至少可以找到立方体的合适角,以便近似计算长度、宽度和高度吗?
任何类型的帮助或信息将不胜感激。
提前致谢。
【问题讨论】:
【参考方案1】:我想我可以为问题的“至少”部分提出解决方案。您可以通过查找图像中的线条来找到立方体的角。
首先,找到图像中的边缘。如果目标图像与提供的图像一样清晰,则查找边缘必须直截了当。使用cv::Canny()
。
cv::Mat img = cv::imread("cube.png");
cv::Mat edges;
cv::Canny(img, edges, 20, 60);
其次,在边缘图像中,检测直线。使用cv::HoughLines()
或cv::HoughLinesP()
。在这里,我继续前一个:
std::vector<cv::Vec2f> lines;
cv::HoughLines(edges, lines, 0.6, CV_PI / 120, 50);
请参阅霍夫线的OpenCV documentation。我还从那里获取了可视化代码。
cv::HoughLines()
函数检测直线,并为每条直线返回 2 个值(ρ - 距离和 θ - 旋转角度),这些值在极坐标中定义了这条直线的方程。这个函数通常会为一个源边返回几行(就像这里的几行一样)。在我们的例子中,我们可以通过过滤具有非常接近 ρ 值的行来删除此类重复。
我们案例的好处是立方体的每个维度(长度、宽度和高度)的边在找到的线方程中将具有相同的旋转角 θ。例如,我们可以期望立方体的垂直边(负责高度维度)保持垂直并且它们的 θ 接近 0 或 π(参见 OpenCV 文档)。我们可以在检测到的霍夫线的向量中找到这样的线:
std::vector<cv::Vec2f> vertical_lines;
std::copy_if(lines.begin(), lines.end(), std::back_inserter(vertical_lines), [](cv::Vec2f line)
//copy if θ is near 0 or CV_PI
return ((0 < line[1]) && (line[1] < 0 + CV_PI / 10)) ||
((line[1] < CV_PI) && (line[1] > CV_PI - CV_PI / 10));
);
同样的推理也适用于寻找立方体其余边的线。只需通过适当的 θ 过滤找到的霍夫线即可。
现在我们有了我们感兴趣的线条的方程,我们可以找到它们对应的边缘像素(下面不是最佳代码,只是演示):
std::vector<cv::Point> non_zero_points;
cv::findNonZero(edges, non_zero_points);
std::vector<std::vector<cv::Point>> corresponding_points(vertical_lines.size());
for (int i = 0; i < vertical_lines.size(); ++i)
for (auto point : non_zero_points)
if (abs(cos(vertical_lines[i][1])*point.x + sin(vertical_lines[i][1])*point.y - vertical_lines[i][0]) < 2)
corresponding_points[i].push_back(point);
现在,为每个找到的簇找到最顶部、最底部的点(或其他边的最左侧/最右侧)并获取立体角。
请注意我用感叹号表示的像素。它意外地排序到垂直霍夫线之一,但它实际上属于非垂直顶面。它需要通过一些异常值检测或通过相应像素搜索的其他方法来删除。
关于检索边的实际长度:据我所知,这确实是一个不平凡的问题。也许this SO question 是个不错的起点。
【讨论】:
这是一个非常好的方法。实际上,我正在考虑进行角点检测。您对此有何看法? 这听起来像是一个解决方案,但在我手中cornerHarris()
总是会丢失一些真正的角并在立方体边缘找到假角。我的猜测,这是因为立方体的绿色轮廓在引擎盖下混淆了Sobel()
。线路检测可能很笨重,但对我来说感觉更强大。但是,可以肯定的是,有一种方法可以使角点检测也能稳健地工作。
它刚刚击中我:您可以将cornerHarris()
应用于Canny()
输出。我已经设法调整了它的参数,以便它产生准确的角落——它是cornerHarris(canny,dst,7,7,0.04)
。尽管其他图像可能需要不同的参数。但是,回顾一下,角点检测很可能是另一种方法。
感谢您的帮助。我将角和线都用于相关矩阵,以获得立方体的准确角。之后,只需基本的几何规则即可构建 3D 模型。谢谢以上是关于使用 OpenCV 在 2D 图像中感知 Cuboid 的尺寸(或突出点)的主要内容,如果未能解决你的问题,请参考以下文章
python使用openCV图像加载(转化为灰度图像)使用filter2D函数对图像进行锐化(Sharpen Images)
OpenCV(C ++) - 根据已知的3D对象和摄像机位置计算图像的2D坐标