сегмент python изображение текста по строке [дубликат]

В случае, если это полезно для всех, большинство решений в этом потоке были обертыванием текста на несколько строк, формы e.

Но потом я нашел это, и он работал:

https://github.com/chunksnbits/jquery-quickfit

Пример использования:

$('.someText').quickfit({max:50,tolerance:.4})

18
задан Alex 24 January 2016 в 21:53
поделиться

2 ответа

Из вашего входного изображения вам нужно сделать текст белым, а фон - черным

Затем вам нужно вычислить угол поворота ваш счет. Простой подход - найти minAreaRect всех белых точек (findNonZero), и вы получите:

Затем вы можете повернуть чтобы текст был горизонтальным:

Теперь вы можете вычислить горизонтальную проекцию (reduce). Вы можете взять среднее значение в каждой строке. Примените порог th на гистограмме, чтобы учесть некоторый шум на изображении (здесь я использовал 0, т. Е. Никакого шума). Линии с только фоном будут иметь значение >0, текстовые строки будут иметь значение 0 в гистограмме. Затем возьмите среднюю координату бина каждой непрерывной последовательности белых бункеров на гистограмме. Это будет координата y ваших линий:

Здесь код. Это в C ++, но поскольку большая часть работы связана с функциями OpenCV, она должна быть легко конвертируемой в Python. По крайней мере, вы можете использовать это как ссылку:

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int main()
{
    // Read image
    Mat3b img = imread("path_to_image");

    // Binarize image. Text is white, background is black
    Mat1b bin;
    cvtColor(img, bin, COLOR_BGR2GRAY);
    bin = bin < 200;

    // Find all white pixels
    vector<Point> pts;
    findNonZero(bin, pts);

    // Get rotated rect of white pixels
    RotatedRect box = minAreaRect(pts);
    if (box.size.width > box.size.height)
    {
        swap(box.size.width, box.size.height);
        box.angle += 90.f;
    }

    Point2f vertices[4];
    box.points(vertices);

    for (int i = 0; i < 4; ++i)
    {
        line(img, vertices[i], vertices[(i + 1) % 4], Scalar(0, 255, 0));
    }

    // Rotate the image according to the found angle
    Mat1b rotated;
    Mat M = getRotationMatrix2D(box.center, box.angle, 1.0);
    warpAffine(bin, rotated, M, bin.size());

    // Compute horizontal projections
    Mat1f horProj;
    reduce(rotated, horProj, 1, CV_REDUCE_AVG);

    // Remove noise in histogram. White bins identify space lines, black bins identify text lines
    float th = 0;
    Mat1b hist = horProj <= th;

    // Get mean coordinate of white white pixels groups
    vector<int> ycoords;
    int y = 0;
    int count = 0;
    bool isSpace = false;
    for (int i = 0; i < rotated.rows; ++i)
    {
        if (!isSpace)
        {
            if (hist(i))
            {
                isSpace = true;
                count = 1;
                y = i;
            }
        }
        else
        {
            if (!hist(i))
            {
                isSpace = false;
                ycoords.push_back(y / count);
            }
            else
            {
                y += i;
                count++;
            }
        }
    }

    // Draw line as final result
    Mat3b result;
    cvtColor(rotated, result, COLOR_GRAY2BGR);
    for (int i = 0; i < ycoords.size(); ++i)
    {
        line(result, Point(0, ycoords[i]), Point(result.cols, ycoords[i]), Scalar(0, 255, 0));
    }

    return 0;
}
33
ответ дан Miki 19 August 2018 в 05:08
поделиться
  • 1
    Удивительно, большое спасибо! – Alex 26 January 2016 в 19:36
  • 2
    Привет Мики, я действительно видел ваш ответ и раньше. я забыл об этом и использовал тот же подход, отвечая на вопрос answers.opencv.org/question/85884 / . Я использовал Canny для поиска разделительных линий. возможно, вам нравится это видеть. – sturkmen 2 February 2016 в 20:49
  • 3
    @sturkmen интересно; D – Miki 2 February 2016 в 20:55
  • 4
    Привет @Miki, я щелкнул входное изображение и попробовал свой код. выход не соответствует желаемому. как мы можем решить эту проблему? вы могли бы попробовать, добавив flip(img, img,1); после Mat3b img = imread() – sturkmen 24 May 2016 в 01:38
  • 5
    @sturkmen Ты прав. Была ошибка. Когда ширина RotatedRect была выше высоты, вам нужно поменять ширину и высоту и добавить на 90 градусов , а не CV_PI / 2 радианов! Исправлено сейчас ... спасибо! Интересно, сколько раз я запутался и вставил эту ошибку ... :( – Miki 24 May 2016 в 10:14

Основные шаги как @Miki,

  1. читать источник
  2. threshed
  3. find minAreaRect
  4. warp (g9)


  5. [gg] [gg] Хотя код в Python:

    #!/usr/bin/python3
    # 2018.01.16 01:11:49 CST
    # 2018.01.16 01:55:01 CST
    import cv2
    import numpy as np
    
    ## (1) read
    img = cv2.imread("img02.jpg")
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    ## (2) threshold
    th, threshed = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)
    
    ## (3) minAreaRect on the nozeros
    pts = cv2.findNonZero(threshed)
    ret = cv2.minAreaRect(pts)
    
    (cx,cy), (w,h), ang = ret
    if w>h:
        w,h = h,w
        ang += 90
    
    ## (4) Find rotated matrix, do rotation
    M = cv2.getRotationMatrix2D((cx,cy), ang, 1.0)
    rotated = cv2.warpAffine(threshed, M, (img.shape[1], img.shape[0]))
    
    ## (5) find and draw the upper and lower boundary of each lines
    hist = cv2.reduce(rotated,1, cv2.REDUCE_AVG).reshape(-1)
    
    th = 2
    H,W = img.shape[:2]
    uppers = [y for y in range(H-1) if hist[y]<=th and hist[y+1]>th]
    lowers = [y for y in range(H-1) if hist[y]>th and hist[y+1]<=th]
    
    rotated = cv2.cvtColor(rotated, cv2.COLOR_GRAY2BGR)
    for y in uppers:
        cv2.line(rotated, (0,y), (W, y), (255,0,0), 1)
    
    for y in lowers:
        cv2.line(rotated, (0,y), (W, y), (0,255,0), 1)
    
    cv2.imwrite("result.png", rotated)
    

    Наконец, результат:

8
ответ дан Mohamed Thasin ah 19 August 2018 в 05:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: