我有一个binary image:在这张图片中,我可以轻松地使用重载的std::sort
对从上到下和从左到右找到的轮廓进行排序。
我首先从上到下排序:
sort(contours.begin(), contours.end(), top_to_bottom_contour_sorter());
然后我从左到右排序:
for (int i = 0; i < contours.size(); i = i + no_of_contours_horizontally)
{
sort(i, i + no_of_contours_horizontally, left_to_right_contour_sorter);
}
其中top_to_bottom
和left_to_right
是我传递给sort函数的单独函数。而no_of_contours_horizontally
相对于第一张图像是三(3)。
但是这只有在我知道水平轮廓的数量时才有效。如果我正在使用的图像将在水平方向上具有不同数量的轮廓,就像在此图像中一样。 contours_sample。该计划失败。我可以蛮力并定义一个特定的索引来改变找到的轮廓的数量。但是,它会限制程序在特定输入上运行而不是灵活。我正在考虑创建我可以叠加在图像顶部的rects或line,并计算内部轮廓的数量,这样我就可以获得水平轮廓数量的值。如果有一个更优雅的解决方案,我会很感激。
这是我的排序功能
bool top_to_bottom_contour_sorter(const std::vector<Point> &lhs, const std::vector<Point> &rhs)
{
Rect rectLhs = boundingRect(Mat(lhs));
Rect rectRhs = boundingRect(Mat(rhs));
return rectLhs.y < rectRhs.y;
}
bool left_to_right_contour_sorter(const std::vector<Point> &lhs, const std::vector<Point> &rhs)
{
Rect rectLhs = boundingRect(Mat(lhs));
Rect rectRhs = boundingRect(Mat(rhs));
return rectLhs.x < rectRhs.x;
}
编辑这是我当前的输出和每个图像的所需输出。使用第一个图像和我当前的工作代码。 Current_Output
我想要的第二张图像的输出。 Desired_Output
我猜,你唯一的问题是不尊重其中一个坐标的平等!?
开始了:
// Custom sorter.
bool sortContour(std::vector<cv::Point> a, std::vector<cv::Point> b)
{
cv::Rect rectA = cv::boundingRect(a);
cv::Rect rectB = cv::boundingRect(b);
if (rectA.y == rectB.y)
return (rectA.x < rectB.x);
return (rectA.y < rectB.y);
}
int main()
{
// Load image.
cv::Mat image = cv::imread("contours.jpg", cv::IMREAD_GRAYSCALE);
// There are some artifacts in the JPG...
cv::threshold(image, image, 128, 255, cv::THRESH_BINARY);
// Find contours.
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(image, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
// Output unsorted contours.
cv::Mat imageUnsorted = image.clone();
for (int i = 0; i < contours.size(); i++)
{
cv::Rect rect = cv::boundingRect(contours[i]);
cv::putText(imageUnsorted, std::to_string(i), cv::Point(rect.x - 10, rect.y - 10), cv::FONT_HERSHEY_COMPLEX, 0.5, cv::Scalar(255));
}
cv::imwrite("unsorted.png", imageUnsorted);
// Sort using custom sorter.
std::sort(contours.begin(), contours.end(), sortContour);
// Output sorted contours.
cv::Mat imageSorted = image.clone();
for (int i = 0; i < contours.size(); i++)
{
cv::Rect rect = cv::boundingRect(contours[i]);
cv::putText(imageSorted, std::to_string(i), cv::Point(rect.x - 10, rect.y - 10), cv::FONT_HERSHEY_COMPLEX, 0.5, cv::Scalar(255));
}
cv::imwrite("sorted.png", imageSorted);
}
未分类的轮廓:
排序的轮廓:
正如你所看到的,人们也可以反转原始顺序,因为cv::findContours
只是朝相反的方向发展。 ;-)
一个很大的警告:如果扫描(或者你获得调查)甚至逆时针稍微旋转,这个程序将失败。因此,应预先检查整个扫描(或......)的角度。
一个简单实用的解决方案是排序
y*100 + x
在旋转输入的情况下,更复杂的东西也可以使用
(dx, dy)
的向量(x*dx + y*dy)*100 + (x*dy - y*dx)
排序输出将是“网格”顺序(可能是您想要的或旋转90度,但旋转输入问题是不适合的,您应该使用一些规则在两者之间进行选择)。