Python: обнаружение текстового блока и удаление его из изображения (OpenCV) - PullRequest
0 голосов
/ 28 марта 2020

В настоящее время я пытаюсь выяснить, как определить текстовый абзац на изображении, чтобы удалить его.

example

Я получаю входное изображение, которое аналогично изображенному выше. С этого момента я хочу обнаружить текст комментария / сообщения комментария. Лайки, Имя пользователя и Аватар не нужны и должны игнорироваться. Затем тело должно быть удалено из комментария, а остальное должно остаться.

comment

Я добавил пороговое значение и нашел контуры. Проблема в том, что тело комментария обнаруживается не как одна часть, а как различные контуры. Как мне их объединить? Кроме того, я хочу удалить его с изображения, как только найду его контур. Цвет фона - RGB (17, 17, 17), . Есть ли способ закрасить его или как он работает в OpenCv? Я довольно новичок в этом.

img = cv2.imread("Comment.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, threshold = cv2.threshold(gray, 80, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

Результат должен выглядеть следующим образом

result

Помощь приветствуется, спасибо в заранее!

1 Ответ

3 голосов
/ 28 марта 2020

Идея действительно проста. Используйте morphology , чтобы выделить текст, который вы хотите обнаружить. Используя это изображение, создайте маску , чтобы удалить интересующую область на входном изображении и получить окончательное изображение. Все через морфологию. Мой ответ на C ++, но реализация очень проста:

//Read input image:
std::string imagePath = "C://opencvImages//commentImage.png";
cv::Mat imageInput= cv::imread( imagePath );

//Convert it to grayscale:
cv::Mat grayImg;
cv::cvtColor( imageInput, grayImg, cv::COLOR_BGR2GRAY );

//Get binary image via Otsu:
cv::threshold( grayImg, grayImg, 0, 255 , cv::THRESH_OTSU );

До этого момента вы генерировали двоичное изображение. Теперь давайте dilate изображение, используя rect angular структурирующий элемент (SE) шире, чем выше. Идея состоит в том, что я хочу соединить весь текст по горизонтали И по вертикали (чуть-чуть). Если вы видите входное изображение, текст «TEST132212» немного отделен от комментария, кажется, этого достаточно, чтобы пережить операцию dilate. Давайте посмотрим, здесь я использую SE размера 9 x 6 с 2 итерациями:

cv::Mat morphKernel = cv::getStructuringElement( cv::MORPH_RECT, cv::Size(9, 6) );
int morphIterations = 2;
cv::morphologyEx( grayImg, grayImg, cv::MORPH_DILATE, morphKernel, cv::Point(-1,-1), morphIterations );

Это результат:

enter image description here

Я получил уникальный блок, где был оригинальный комментарий - Отлично! Теперь это самый большой шарик на изображении. Если я вычту его в исходное двоичное изображение, я должен сгенерировать маску , которая успешно изолирует все, что не является «комментарием»:

cv::Mat bigBlob = findBiggestBlob( grayImg );

Я получаю это:

enter image description here

Теперь двоичная маска поколение:

cv::Mat binaryMask = grayImg - bigBlob;

//Use the binaryMask to produce the final image:
cv::Mat resultImg;
imageInput.copyTo( resultImg, binaryMask );

Создает замаскированное изображение:

enter image description here

Теперь вы должны были отметить функцию findBiggestBlob. Это функция, которую я сделал, которая возвращает самый большой двоичный объект в двоичном изображении. Идея состоит в том, чтобы просто рассчитать все контуры входного изображения, вычислить их площадь и сохранить контур с наибольшей площадью сгустка. Это реализация C ++:

//Function to get the largest blob in a binary image:
cv::Mat findBiggestBlob( cv::Mat &inputImage ){

    cv::Mat biggestBlob = inputImage.clone();

    int largest_area = 0;
    int largest_contour_index=0;

    std::vector< std::vector<cv::Point> > contours; // Vector for storing contour
    std::vector<cv::Vec4i> hierarchy;

    // Find the contours in the image
    cv::findContours( biggestBlob, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); 

    for( int i = 0; i< (int)contours.size(); i++ ) {            

        //Find the area of the contour            
        double a = cv::contourArea( contours[i],false);
        //Store the index of largest contour:
        if( a > largest_area ){
            largest_area = a;                
            largest_contour_index = i;
        }

    }

    //Once you get the biggest blob, paint it black:
    cv::Mat tempMat = biggestBlob.clone();
    cv::drawContours( tempMat, contours, largest_contour_index, cv::Scalar(0),
                  CV_FILLED, 8, hierarchy );

    //Erase the smaller blobs:
    biggestBlob = biggestBlob - tempMat;
    tempMat.release();
    return biggestBlob;
}
...