我有一个包含正方形的图像,我需要提取该正方形中包含的区域。 应用 squares.c 脚本(在每个OpenCV发行版的示例中都可用)后,我获得了一个正方形向量,然后我需要为每个正方形保存一个图像。
用户 karlphillip 建议:
for (size_t x = 0; x < squares.size(); x++)
{
Rect roi(squares[x][0].x, squares[x][0].y,
squares[x][1].x - squares[x][0].x,
squares[x][3].y - squares[x][0].y);
Mat subimage(image, roi);
}
为原始图像中检测到的所有方块生成一个名为subimage的新Mat,
正如卡尔记得的那样,图像中检测到的点可能并不代表一个完美的正方形(如上图所示),但我刚给你建议的代码假设他们这样做了。
实际上我收到了这个错误:
OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width &&
roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height &&
roi.y + roi.height <= m.rows) in Mat, file /usr/include/opencv/cxmat.hpp,
line 187
terminate called after throwing an instance of 'cv::Exception'
what(): /usr/include/opencv/cxmat.hpp:187: error: (-215) 0 <= roi.x &&
0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y &&
0 <= roi.height && roi.y + roi.height <= m.rows in function Mat
Aborted
建议脚本接受非完美正方形?
答案 0 :(得分:11)
我觉得我需要澄清一些关于该代码的事情。
首先,它假定检测到的区域是完美的正方形,因为它忽略squares[x]
内的某些点以创建新的Mat
。
第二,它还假设从顺时针方向检测到构成该区域的点,从图像左上角的p0
开始:
(p0) 1st----2nd (p1)
| |
| |
(p3) 4th----3rd (p2)
对于检测到的所有区域可能都不是这样。这意味着这段代码:
Rect roi(squares[x][0].x, squares[x][0].y,
squares[x][1].x - squares[x][0].x,
squares[x][3].y - squares[x][0].y);
可能会生成包含无效维度的投资回报率,例如负宽度和高度值,这就是为什么OpenCV会在cv::Exception
向您发出Mat subimage(image, roi);
。
您应该做的是编写一个代码,该代码将识别该区域的左上角并将其称为p0
,然后它就在右侧最近的右侧p1
,然后找到该区域的右下角并将其命名为p2
,然后剩下的是p3
。在此之后,组装ROI很容易:
Rect roi(p0.x, p0.y,
p1.x - p0.x,
p3.y - p0.y);
修改强>:
我在阅读OpenCV v2.3的documentation时找到了优秀解决方案。它使我之前描述的过程自动化,使事情变得如此简单和干净。您可以使用此技巧将向量中的4个点排序为有意义的Rect
结构:
// Data returned and filled by findSquares(). Check the example squares.cpp for more info on this function.
vector<vector<Point> > squares;
for (size_t i = 0; i < squares.size(); i++)
{
Rect rectangle = boundingRect(Mat(squares[i]));
cout << "#" << i << " rectangle x:" << rectangle.x << " y:" << rectangle.y << " " << rectangle.width << "x" << rectangle.height << endl;
}