如何在OpenCV C++中给轮廓文本上色?

huangapple go评论72阅读模式
英文:

how to color in outlined text in opencv C++

问题

我想给图像中显示的字符上色。我尝试过使用 findContours() 来获取字符的轮廓。然后我循环遍历图像的每一个点,使用 pointPolygonTest() 检查点是否位于字符轮廓内。如果为真,就给该点上色。然而,pointPolygonTest() 似乎始终返回假,因为最终没有添加颜色。

英文:

I would like give color to the character shown in the image.enter image description here

Something I've tried is using findcontours() to gather contours of the characters. Then I loop through every single point of the image to check if a point lies in the character contours using pointpolygontest(). If true, assign color to the point. However, pointpolygontest() seems to return false all the time because no color was added after all.

答案1

得分: 3

以下是您要翻译的部分:

  • If you think of the lines in your input image as connected components, the areas we want to fill are holes in the connected components. Specifically they are the top-level holes; i.e., we do not want to fill in features like the internal lines in the letter O or D, etc. Our general strategy will be to find these holes with cv::findContours and then fill them with cv::floodFill.

  • findContours expects one channel input that is white on a black background. Your input has three channels, is black on white, and is anti-aliased, so we must clean up the image with various color conversion, thresholding, and inversion calls. Once we have a binary image that is white on black, we call findContours in RETR_TREE mode. We need the full hierarchy tree because we need to find the top-level holes. findContours returns hierarchy information as a vector of quadruples listing the indices of the nth contour's previous, next, first child, and parent contours. To find the "top-level holes" we want any contour that has a parent but that does not have a grandparent.

  • To actually fill in these holes we are going to use floodFill but that means we need a seed that is definitely in each area we want to fill. Because the contour coordinates will be lists of "on" pixel locations, a topmost point (x,y) on some hole contour will be above the actual hole, but (x,y+1) will be a suitable seed for flood-filling.

  • We then convert the uninverted binary image back to three channels and flood-fill at our seed locations in red. How you prepare your output here depends on your actual use case. In this case, I am making sample output for a StackOverflow answer so I do something simple. You may want to preserve the anti-aliasing in the original image, etc., and do something more complicated, but the following generates an aliased image as a proof-of-concept:

这是您要翻译的代码部分:

#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <limits>

cv::Point find_top_hole_point(const std::vector<cv::Point>& hole_pts) {
    cv::Point top_point = { 0, std::numeric_limits<int>::max() };
    for (const auto& pt : hole_pts) {
        if (pt.y < top_point.y) {
            top_point = pt;
        }
    }
    return top_point + cv::Point(0, 1);
}

std::vector<cv::Point> get_point_in_holes(cv::Mat img) {
    // invert for findContours call
    cv::Mat work;
    cv::bitwise_not(img, work);

    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(work, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

    std::vector<cv::Point> hole_points;
    for (int i = 0; i < static_cast<int>(contours.size()); ++i) {
        auto parent = hierarchy[i][3];

        // toplevel holes have a parent but no grandparent...
        if ((parent >= 0) && (hierarchy[parent][3] < 0)) {
            hole_points.push_back(find_top_hole_point(contours[i]));
        }
    }
    return hole_points;
}

int main() {
    cv::Mat img = cv::imread("C:\\test\\alphabet.png");

    // convert to 3-channel gray scale
    cv::Mat work;
    cv::cvtColor(img, work, cv::COLOR_BGR2GRAY);

    // convert to 1-channel black and white
    cv::threshold(work, work, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

    // get seeds for flood-filling
    // (topmost points in top-level holes)
    auto hole_points = get_point_in_holes(work);

    // convert back to 3-channel color;
    cv::cvtColor(work, work, cv::COLOR_GRAY2BGR);

    // fill top-level holes with red
    for (const auto& pt : hole_points) {
        cv::floodFill(work, pt, cv::Scalar(0, 0, 255));
    }

    cv::imshow("output_image", work);
    cv::waitKey(0);
}

希望这对您有所帮助。

英文:

If you think of the lines in your input image as connected components, the areas we want to fill are holes in the connected components. Specifically they are the top-level holes; i.e., we do not want to fill in features like the internal lines in the letter O or D, etc. Our general strategy will be to find these holes with cv::findContours and then fill them with cv::floodFill.

findContours expects one channel input that is white on a black background. Your input has three channels, is black on white, and is anti-aliased, so we must clean up the image with various color conversion, thresholding, and inversion calls. Once we have a binary image that is white on black, we call findContours in RETR_TREE mode. We need the full hierarchy tree because we need to find the top-level holes. findContours returns hierarchy information as a vector of quadruples listing the indices of the nth contour's previous, next, first child, and parent contours. To find the "top-level holes" we want any contour that has a parent but that does not have a grandparent.

To actually fill in these holes we are going to use floodFill but that means we need a seed that is definitely in each area we want to fill. Because the contour coordinates will be lists of "on" pixel locations, a topmost point (x,y) on some hole contour will be above the actual hole, but (x,y+1) will be a suitable seed for flood-filling.

We then convert the uninverted binary image back to three channels and flood-fill at our seed locations in red. How you prepare your output here depends on your actual use case. In this case I am making sample output for a StackOverflow answer so I do something simple. You may want to preserve the anti-aliasing in the original image, etc., and do something more complicated, but the following generates an aliased image as a proof-of-concept:如何在OpenCV C++中给轮廓文本上色?

Code below:
<!-- language: C++ -->
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <limits>

cv::Point find_top_hole_point(const std::vector&lt;cv::Point&gt;&amp; hole_pts) {
cv::Point top_point = { 0,std::numeric_limits&lt;int&gt;::max() };
for (const auto&amp; pt : hole_pts) {
if (pt.y &lt; top_point.y) {
top_point = pt;
}
}
return top_point + cv::Point(0, 1);
}
std::vector&lt;cv::Point&gt; get_point_in_holes(cv::Mat img) {
// invert for findContours call
cv::Mat work;
cv::bitwise_not(img, work);
std::vector&lt;std::vector&lt;cv::Point&gt;&gt; contours;
std::vector&lt;cv::Vec4i&gt; hierarchy;
cv::findContours(work, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
std::vector&lt;cv::Point&gt; hole_points;
for (int i = 0; i &lt; static_cast&lt;int&gt;(contours.size()); ++i) {
auto parent = hierarchy[i][3];
// toplevel holes have a parent but no grandparent...
if ((parent &gt;= 0) &amp;&amp; (hierarchy[parent][3] &lt; 0)) {
hole_points.push_back(find_top_hole_point(contours[i]));
}
}
return hole_points;
}
int main() {
cv::Mat img = cv::imread(&quot;C:\\test\\alphabet.png&quot;);
// convert to 3-channel gray scale
cv::Mat work;
cv::cvtColor(img, work, cv::COLOR_BGR2GRAY);
// convert to 1-channel black and white
cv::threshold(work, work, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
// get seeds for flood-filling
// (topmost points in top-level holes)
auto hole_points = get_point_in_holes(work);
// convert back to 3-channel color;
cv::cvtColor(work, work, cv::COLOR_GRAY2BGR);
// fill top-level holes with red
for (const auto&amp; pt : hole_points) {
cv::floodFill(work, pt, cv::Scalar(0, 0, 255));
}
cv::imshow(&quot;output_image&quot;, work);
cv::waitKey(0);
}

huangapple
  • 本文由 发表于 2023年4月7日 03:23:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/75953075.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定