从图像中对 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 对这些字符行进行排序。

正确的做法是:

  1. 找到线轮廓(复制原图和灰度,阈值,膨胀)然后从上到下按y对线轮廓进行排序。
  2. 从找到的行中取出矩形并从原始图像中裁剪出相同的矩形。然后在裁剪出来的图片中找到轮廓,挑出有效的,然后按x从左到右排序。