我想知道是否可以在如下图所示的图像中找到立方体/立方体的尺寸(以像素为单位)?
我知道它几乎是不可能的,因为没有有关深度,视角等的信息。但是至少可以找到立方体的适当角以使长度,宽度和高度可以近似吗?
任何类型的帮助或信息,将不胜感激。
提前致谢。
最佳答案
我想我可以建议解决问题的“至少”部分。您可以通过找到图像中的线来找到立方体的角。
首先,找到图像中的边缘。如果目标图像与提供的图像一样清晰明了,则寻找边缘必须是直截了当的。使用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);
Plaese是指Hough行上OpenCV documentation上的。我还从那里获取了可视化代码。
cv::HoughLines()
函数检测直线,对于每条直线,返回2个值(ρ-距离和θ-旋转 Angular ),这些值在极坐标中定义了这条线的方程式。该函数通常会为一个源边返回几行(就像这里的两行一样)。在我们的情况下,我们可以通过过滤具有非常接近的ρ值的行来删除此类重复项。我们这种情况的好处是,在找到的线方程中,可用于每个尺寸(长度,宽度和高度)的多维数据集的边将具有相同的旋转角θ。例如,我们可以期望立方体的垂直边(负责高度尺寸)保持垂直,并且其θ接近0或π(请参阅OpenCV文档)。我们可以在检测到的霍夫线的 vector 中找到这样的线:
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是一个不错的起点。