Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

I would use binary threshold, morphology and contours to solve this problem.

Step 1 : get the copy with signature

cv::Mat const map_01 = cv::imread("map01.jpg");

image description

Step 2 : blur the image and convert it to binary image

cv::Mat binarize;
cv::cvtColor(map_01, binarize, CV_BGR2GRAY);
cv::GaussianBlur(map_01, map_01, {5,5}, 3,3);
cv::threshold(binarize, binarize, 0, 255,
cv::THRESH_BINARY_INV | cv::THRESH_OTSU);

Step 3 : Use morphology to remove small blobs and make text blobs more obvious

auto mrect = cv::getStructuringElement(cv::MORPH_RECT, {3,3});
cv::erode(binarize, binarize, mrect);
mrect = cv::getStructuringElement(cv::MORPH_RECT, {7,5});
cv::morphologyEx(binarize, binarize, cv::MORPH_DILATE, mrect, {-1,-1}, 7);

Step 4 : find contours and remove those with invalid aspect ratio

std::vector<std::vector<cv::Point>> contours;
cv::findContours(binarize.clone(), contours, CV_RETR_EXTERNAL,
                 CV_CHAIN_APPROX_SIMPLE);
auto rit = std::remove_if(std::begin(contours), std::end(contours),
               [](auto const &ct)
{
    auto const rect = cv::boundingRect(ct);
    return rect.height > rect.width;
});
contours.erase(rit, std::end(contours));

Step 5 : Find the data of each rectangle

for(auto const &ct : contours){
    //get the information of each rect
    cv::Mat temp = map_01.clone();
    std::cout<<cv::boundingRect(ct)<<std::endl;
    cv::rectangle(temp, cv::boundingRect(ct), {255,0,0});
    cv::imshow("temp", temp);
    cv::waitKey();
    cv::destroyAllWindows();       
}

The bounding rects found by this solution are

image description

Step 6 : Extract text location according to the location and size of the bounding rects, this step is quite tedious.

Not a very good one, I believe there exist better solution, like find the difference between two images.

Source codes locate at github.

I would use binary threshold, morphology and contours to solve this problem.

Step 1 : get the copy with signature

cv::Mat const map_01 = cv::imread("map01.jpg");

image description

Step 2 : blur the image and convert it to binary image

cv::Mat binarize;
cv::cvtColor(map_01, binarize, CV_BGR2GRAY);
cv::GaussianBlur(map_01, map_01, {5,5}, 3,3);
cv::threshold(binarize, binarize, 0, 255,
cv::THRESH_BINARY_INV | cv::THRESH_OTSU);

Step 3 : Use morphology to remove small blobs and make text blobs more obvious

auto mrect = cv::getStructuringElement(cv::MORPH_RECT, {3,3});
cv::erode(binarize, binarize, mrect);
mrect = cv::getStructuringElement(cv::MORPH_RECT, {7,5});
cv::morphologyEx(binarize, binarize, cv::MORPH_DILATE, mrect, {-1,-1}, 7);

Step 4 : find contours and remove those with invalid aspect ratio

std::vector<std::vector<cv::Point>> contours;
cv::findContours(binarize.clone(), contours, CV_RETR_EXTERNAL,
                 CV_CHAIN_APPROX_SIMPLE);
auto rit = std::remove_if(std::begin(contours), std::end(contours),
               [](auto const &ct)
{
    auto const rect = cv::boundingRect(ct);
    return rect.height > rect.width;
});
contours.erase(rit, std::end(contours));

Step 5 : Find the data of each rectangle

for(auto const &ct : contours){
    //get the information of each rect
    cv::Mat temp = map_01.clone();
    std::cout<<cv::boundingRect(ct)<<std::endl;
    cv::rectangle(temp, cv::boundingRect(ct), {255,0,0});
    cv::imshow("temp", temp);
    cv::waitKey();
    cv::destroyAllWindows();       
}

The bounding rects found by this solution are

image description

Step 6 : Extract text location according to the location and size of the bounding rects, this step is quite tedious.

Not a very good one, I believe there exist better solution, like find the difference between two images.

Source codes locate at github.

Edit : If the format and size of the are always the same, you can predefined the bounding rect of text candidates, extract the roi from predefined bounding rect, detect the binary value of those roi to find out the regions filled or not.