我想知道是否有可能找到像下图所示的图像中立方体/长方体的尺寸(以像素为单位)?
我知道它几乎不可能,因为没有关于深度,视角等的信息。但至少可以找到立方体的适当角落,以便可以近似长度,宽度和高度?
任何类型的帮助或信息都将受到赞赏。
提前致谢。
答案 0 :(得分: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);
Plaese指的是霍夫线上的OpenCV documentation。我还从那里获取了可视化的代码。
cv::HoughLines()
函数检测直线,并且对于每一行,返回2个值(ρ - 距离和θ-旋转角度),它们在极坐标中定义该线的方程。这个函数通常会为一个源边缘返回几行(就像这里的几行一样)。在我们的例子中,我们可以通过过滤非常接近的ρ值来删除这些重复项。
我们的案例的好处是,对于每个维度(长度,宽度和高度),立方体的侧面将在所找到的线性方程中具有相同的旋转角度θ。例如,我们可以预期立方体的垂直边(负责高度尺寸)保持垂直并使其θ接近0或π(参见OpenCV文档)。我们可以在检测到的Hough线的矢量中找到这样的线:
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));
});
同样的推理适用于找到其余立方体边的线条。只需用适当的θ过滤找到的Hough线。
现在我们有了我们感兴趣的线的方程,我们可以找到它们相应的边缘像素(下面不是最佳代码,只是演示):
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);
现在,对于每个找到的群集,找到最顶部,最底部的点(或其他边的最左侧/最右侧)并获得您的立方角。
请注意我用感叹号表示的像素。它意外地被分类到垂直的Hough线之一,但它实际上属于非垂直的顶部。需要通过一些异常检测或相应的像素搜索的其他方法来删除它。
关于修复双方的实际长度:据我所知,这确实是一个非常重要的问题。也许this SO question将是一个很好的起点。