用 drawContours 填充角色的内部区域

Fill inner area of a character with drawContours

我有一个输入图像:

我使用了几个函数来查找此图像中的轮廓:

cv::Mat srcImg = cv::imread("input.png");
cv::Mat grayImg{};
cv::cvtColor(srcImg, grayImg, cv::COLOR_BGR2GRAY);
cv::Mat threshImg;
cv::adaptiveThreshold(grayImg, threshImg, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, 11, 2);

我的阈值处理后的图片如下:

现在我要找等高线:

std::vector<std::vector<cv::Point>> ptContours{};
cv::findContours(threshImg, ptContours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

这是我的问题:如何使用 drawContours() 填充字符 A 的内部区域?

我想实现这样的目标:

如果您通过 Otsu Thresholding 获得二进制图像,您会得到一个没有任何“填充问题”的漂亮二进制 blob:

// Read the input image:
std::string imageName = "D://opencvImages//UZUd5.png";
cv::Mat testImage =  cv::imread( imageName );

// Convert BGR to Gray:
cv::Mat grayImage;
cv::cvtColor( testImage, grayImage, cv::COLOR_RGB2GRAY );

// Get Binary via Otsu:
cv::Mat binaryImage;
cv::threshold( grayImage, binaryImage, 0, 255, cv::THRESH_OTSU );

这是结果:

如果您不想使用 Otsu,而是使用您当前的方法,这是一种填充 blob 的可能方法。它基本上按区域和层次过滤每个轮廓。我寻找最外面和最里面的轮廓,并相应地执行一些 flood-fills - 在外部轮廓之外,填充 canvas 并在内部轮廓内填充:

// Get Binary via Adaptive Thresh:
cv::Mat binaryImage;
cv::adaptiveThreshold( grayImage, binaryImage, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, 11, 2 );

// Containers:
std::vector< std::vector<cv::Point> > contours;
std::vector< cv::Vec4i > hierarchy;

// Create a new matrix where things will be drawn:
cv::Mat filledBlob = cv::Mat::ones( binaryImage.size(), CV_8UC3 );

// Find contours:
cv::findContours(binaryImage, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);

// Filling colors:
cv::Scalar fillColor = cv::Scalar( 0,0,0 );
cv::Scalar canvasColor = cv::Scalar( 255,255,255 );

for( int i = 0; i < (int)contours.size(); i++ ){
    // Get Blob area:
    float blobArea = cv::contourArea( contours[i] );
    // Filter smaller blobs:
    int minArea = 3000;
    if ( blobArea > minArea) {

        // Get contour heirarchy:
        int contourHierarchy = hierarchy[i][3];

        // Process the child contour:
        if ( contourHierarchy != -1 ){

            // Draw "hole":
            cv::drawContours( filledBlob, contours, (int)i, fillColor, 1, cv::LINE_8, hierarchy, 0 );
            // Get bounding rectangle:
            cv::Rect bBox = cv::boundingRect(contours[i]);
            // Compute centroid:
            cv::Point centroid;
            centroid.x = bBox.x + 0.5*bBox.width;
            centroid.y = bBox.y + 0.5*bBox.height;
            // Flood-fill at centroid with canvas color:
            cv::floodFill( filledBlob, centroid, canvasColor, (cv::Rect*)0, cv::Scalar(), 0);

        }else{

             // Process the parent contour:
            if ( contourHierarchy == -1 ){
                // Draw outline:
                cv::drawContours( filledBlob, contours, (int)i, fillColor, 1, cv::LINE_8, hierarchy, 0 );
                // Flood-fill at canvas (outside of contour):
                cv::floodFill( filledBlob, cv::Point( 1, 1 ), canvasColor, (cv::Rect*)0, cv::Scalar(), 0);
            }
        }

        // Show image
        cv::imshow( "Filled Blob", filledBlob );
        cv::waitKey(0);
    }
}

生成这张图片:

如果你想要倒像,减去255 - filledBlob:

cv::subtract( 255, filledBlob, filledBlob );