从图像中对OpenCV中的轮廓进行排序

时间:2018-05-28 09:48:35

标签: c++ visual-studio opencv opencv-contour

我正在开发一个可以检测和识别角色的程序。识别工作正常,但在排序轮廓时我遇到了问题。我必须从左到右,从上到下对它们进行排序,以便从图像中获得正确的单词,但由于轮廓具有不同的高度,我无法以正确的顺序获得它们。问题在于我的排序功能。

以下是轮廓的外观:

The image I with contours.

这是我的有效轮廓类,其中包含排序功能:

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);
}

2 个答案:

答案 0 :(得分:0)

我的猜测如下:您使用std::sort算法按X排序字符,然后按Y排序,但此算法不保证稳定。也就是说,存在一些不期望的交换,因为Y坐标具有不同的排序。

尝试使用std::stable_sort算法并执行Jeru Luke在评论中提出的建议 - 使用X进行stable_sort,然后按Y进行稳定排序。

另一种修改可能是尝试首先将所有字符分割成行(即,收集具有大致相似Y坐标的所有字符),然后仅将这些字符行按X排序。

答案 1 :(得分:0)

正确的方法是:

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