从图像中对 OpenCV 中的轮廓进行排序
Sorting contours in OpenCV from an image
我正在开发一个可以检测和识别字符的程序。识别工作正常,但在排序轮廓时遇到问题。我必须从左到右,从上到下对它们进行排序,才能从图像中得到正确的单词,但由于轮廓的高度不同,我无法按正确的顺序排列它们。问题出在我的排序功能上。
轮廓如下所示:
这是我的有效轮廓class,其中包含排序功能:
class ContourWithData {
public:
std::vector<cv::Point> ptContour;
cv::Rect boundingRect;
float fltArea;
bool checkIfContourIsValid() {
if (fltArea < MIN_CONTOUR_AREA) return false;
return true;
}
static bool sortByBoundingRectXPosition(const ContourWithData& cwdLeft, const ContourWithData& cwdRight) {
if (cwdLeft.boundingRect.y == cwdRight.boundingRect.y) {
return(cwdLeft.boundingRect.x + 1000 * cwdLeft.boundingRect.y < cwdRight.boundingRect.x + 1000 * cwdRight.boundingRect.y);
} else if (cwdLeft.boundingRect.height > cwdRight.boundingRect.height) {
int sub = cwdLeft.boundingRect.height - cwdRight.boundingRect.height;
return(cwdLeft.boundingRect.x + 1000 * cwdLeft.boundingRect.y < cwdRight.boundingRect.x + 1000 * (cwdRight.boundingRect.y - sub));
} else {
int sub = cwdRight.boundingRect.height - cwdLeft.boundingRect.height;
return(cwdLeft.boundingRect.x + 1000 * (cwdLeft.boundingRect.y - sub) < cwdRight.boundingRect.x + 1000 * cwdRight.boundingRect.y);
}
}
};
这是我的控制台输出:
domainocmlsroudtosonsorma0rleauehacklnppjggandethirmissiontoemowerstudenthackersar0undpteworlhdyouarethenextenerati0nofudmgpancong0rathtosuccesssaswihvttdthkersyurloppgresselndomnnamereatnaikdcnaaueaihlejoarmaggg
像 p 和 g 这样的字符放在最后..¸
试过质心:
static bool sortByBoundingRectXPosition(const ContourWithData& cwdLeft, const ContourWithData& cwdRight) { // this function allows us to sort
Mat left = Mat(srcImg, cwdLeft.boundingRect);
Mat right = Mat(srcImg, cwdRight.boundingRect);
Point massCenterLeft = findMassCenter(left);
Point massCenterRight = findMassCenter(right);
return (massCenterLeft.x + massCenterLeft.y < massCenterRight.x + massCenterRight.y);
}
和质心函数:
Point findMassCenter(Mat src)
{
int totalX = 0, totalY = 0;
int cnt = 0;
for (int x = 0; x < src.cols; x++)
{
for (int y = 0; y < src.rows; y++)
{
int val = src.at<uchar>(Point(x, y));
if (val < 240)
{
totalX += x;
totalY += y;
cnt++;
}
}
}
return Point(totalX / cnt, totalY / cnt);
}
我的猜测如下:您正在使用 std::sort
算法对字符按 X 排序,然后按 Y 排序,但不保证该算法稳定。也就是说,有一些不希望的交换,因为 Y 坐标具有不同的顺序。
尝试使用 std::stable_sort
算法并执行 Jeru Luke 在他的评论中建议的操作 - stable_sort 按 X,然后按 Y 稳定排序。
另一种修改可能是尝试首先将所有字符拆分为行(即,收集具有大致相似的 Y 坐标的所有字符),然后才按 X 对这些字符行进行排序。
正确的做法是:
- 找到线轮廓(复制原图和灰度,阈值,膨胀)然后从上到下按y对线轮廓进行排序。
- 从找到的行中取出矩形并从原始图像中裁剪出相同的矩形。然后在裁剪出来的图片中找到轮廓,挑出有效的,然后按x从左到右排序。
我正在开发一个可以检测和识别字符的程序。识别工作正常,但在排序轮廓时遇到问题。我必须从左到右,从上到下对它们进行排序,才能从图像中得到正确的单词,但由于轮廓的高度不同,我无法按正确的顺序排列它们。问题出在我的排序功能上。
轮廓如下所示:
这是我的有效轮廓class,其中包含排序功能:
class ContourWithData {
public:
std::vector<cv::Point> ptContour;
cv::Rect boundingRect;
float fltArea;
bool checkIfContourIsValid() {
if (fltArea < MIN_CONTOUR_AREA) return false;
return true;
}
static bool sortByBoundingRectXPosition(const ContourWithData& cwdLeft, const ContourWithData& cwdRight) {
if (cwdLeft.boundingRect.y == cwdRight.boundingRect.y) {
return(cwdLeft.boundingRect.x + 1000 * cwdLeft.boundingRect.y < cwdRight.boundingRect.x + 1000 * cwdRight.boundingRect.y);
} else if (cwdLeft.boundingRect.height > cwdRight.boundingRect.height) {
int sub = cwdLeft.boundingRect.height - cwdRight.boundingRect.height;
return(cwdLeft.boundingRect.x + 1000 * cwdLeft.boundingRect.y < cwdRight.boundingRect.x + 1000 * (cwdRight.boundingRect.y - sub));
} else {
int sub = cwdRight.boundingRect.height - cwdLeft.boundingRect.height;
return(cwdLeft.boundingRect.x + 1000 * (cwdLeft.boundingRect.y - sub) < cwdRight.boundingRect.x + 1000 * cwdRight.boundingRect.y);
}
}
};
这是我的控制台输出:
domainocmlsroudtosonsorma0rleauehacklnppjggandethirmissiontoemowerstudenthackersar0undpteworlhdyouarethenextenerati0nofudmgpancong0rathtosuccesssaswihvttdthkersyurloppgresselndomnnamereatnaikdcnaaueaihlejoarmaggg
像 p 和 g 这样的字符放在最后..¸
试过质心:
static bool sortByBoundingRectXPosition(const ContourWithData& cwdLeft, const ContourWithData& cwdRight) { // this function allows us to sort
Mat left = Mat(srcImg, cwdLeft.boundingRect);
Mat right = Mat(srcImg, cwdRight.boundingRect);
Point massCenterLeft = findMassCenter(left);
Point massCenterRight = findMassCenter(right);
return (massCenterLeft.x + massCenterLeft.y < massCenterRight.x + massCenterRight.y);
}
和质心函数:
Point findMassCenter(Mat src)
{
int totalX = 0, totalY = 0;
int cnt = 0;
for (int x = 0; x < src.cols; x++)
{
for (int y = 0; y < src.rows; y++)
{
int val = src.at<uchar>(Point(x, y));
if (val < 240)
{
totalX += x;
totalY += y;
cnt++;
}
}
}
return Point(totalX / cnt, totalY / cnt);
}
我的猜测如下:您正在使用 std::sort
算法对字符按 X 排序,然后按 Y 排序,但不保证该算法稳定。也就是说,有一些不希望的交换,因为 Y 坐标具有不同的顺序。
尝试使用 std::stable_sort
算法并执行 Jeru Luke 在他的评论中建议的操作 - stable_sort 按 X,然后按 Y 稳定排序。
另一种修改可能是尝试首先将所有字符拆分为行(即,收集具有大致相似的 Y 坐标的所有字符),然后才按 X 对这些字符行进行排序。
正确的做法是:
- 找到线轮廓(复制原图和灰度,阈值,膨胀)然后从上到下按y对线轮廓进行排序。
- 从找到的行中取出矩形并从原始图像中裁剪出相同的矩形。然后在裁剪出来的图片中找到轮廓,挑出有效的,然后按x从左到右排序。