OpenCV копирует область неправильного контура в другое изображение после вращения контура - PullRequest
2 голосов
/ 01 ноября 2019

Я работаю с изображением с искаженными / повернутыми текстами. Мне нужно повернуть эти текстовые объекты обратно на горизонтальный уровень (0 градусов), прежде чем я смогу запустить OCR на них. Мне удалось исправить проблему поворота, но теперь мне нужно найти способ скопировать содержимое исходного контура в повернутую матрицу.

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

  1. Найти контур
  2. Сильное расширение и удалить нетекстовые линии
  3. Найти угол контура и выполнить коррекцию угла в полярном пространстве.

Я пытался использовать аффинное преобразование для поворота прямоугольных текстовых блобов, но в итоге некоторые тексты были обрезаны, потому что некоторые текстовые капли нерегулярны. Результат здесь

Синие точки в контурах - центроиды, числа - углы контура. Как я могу скопировать содержимое необращенного контура, повернуть его и скопировать в новое изображение? enter image description here

Код

def getContourCenter(contour):
    M = cv2.moments(contour)
    if M["m00"] != 0:
        cx = int(M['m10']/M['m00'])
        cy = int(M['m01']/M['m00'])
    else:
        return 0, 0
    return int(cx), int(cy)

def rotateContour(contour, center: tuple, angle: float):

    def cart2pol(x, y):
        theta = np.arctan2(y, x)
        rho = np.hypot(x, y)
        return theta, rho

    def pol2cart(theta, rho):
        x = rho * np.cos(theta)
        y = rho * np.sin(theta)
        return x, y

    # Translating the contour by subtracting the center with all the points
    norm = contour - [center[0], center[1]]

    # Convert the points to polar co-ordinates, add the rotation, and convert it back to Cartesian co-ordinates.
    coordinates = norm[:, 0, :]
    xs, ys = coordinates[:, 0], coordinates[:, 1]
    thetas, rhos = cart2pol(xs, ys)

    thetas = np.rad2deg(thetas)
    thetas = (thetas + angle) % 360
    thetas = np.deg2rad(thetas)

    # Convert the new polar coordinates to cartesian co-ordinates
    xs, ys = pol2cart(thetas, rhos)
    norm[:, 0, 0] = xs
    norm[:, 0, 1] = ys

    rotated = norm + [center[0], center[1]]
    rotated = rotated.astype(np.int32)

    return rotated


def straightenText(image, vis):

    # create a new mat
    mask = 0*np.ones([image.shape[0], image.shape[1], 3], dtype=np.uint8)

    # invert pixel index arrangement and dilate aggressively
    dilate = cv2.dilate(~image, ImageUtils.box(33, 1))

    # find contours
    _, contours, hierarchy = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    for contour in contours:
        [x, y, w, h] = cv2.boundingRect(contour)
        if w > h:

            # find contour angle and centers
            (x, y), (w, h), angle = cv2.minAreaRect(contour)
            cx, cy = getContourCenter(contour)

            # fix angle returned
            if w < h:
                angle = 90 + angle

            # fix contour angle
            rotatedContour = rotateContour(contour, (cx, cy), 0-angle)

            cv2.drawContours(vis, contour, -1, (0, 255, 0), 2)
            cv2.drawContours(mask, rotatedContour, -1, (255, 0, 0), 2)
            cv2.circle(vis, (cx, cy), 2, (0, 0, 255), 2, 8) # centroid
            cv2.putText(vis, str(round(angle, 2)), (cx, cy), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255,0,0), 2)

1 Ответ

0 голосов
/ 02 ноября 2019

Вот один из способов, который является самым простым способом, который я могу сделать в Python / OpenCV, хотя и не оптимальным по скорости.

  • Создание белого пустого изображения дляжелаемый вывод. (Таким образом, у нас есть черный текст на белом фоне на случай, если вам понадобится OCR)

  • Получите повернутый ограничивающий прямоугольник вашего контура на вашем входе.

  • Получите нормальный ограничивающий прямоугольник вашего контура на выходе.

  • Получите 4 угла ограничивающей рамки для каждого.

  • Вычислитеаффинная матрица преобразования между двумя наборами из 4 угловых точек.

  • Деформация (целого) входного изображения до одинакового размера (неоптимального).

  • Используйте размеры выходной ограничительной рамки и верхний левый угол с кусочками для переноса, чтобы перенести область искривленного изображения в ту же область на белом выходном изображении.

  • Повторите для каждого текстаконтур, используя полученное изображение вместо исходного белого изображения в качестве нового изображения назначения.

Итак, вот симуляция, чтобы показать вам, как.

Исходное текстовое изображение:

enter image description here

Исходное текстовое изображениес красным повернутым прямоугольником:

enter image description here

Желаемый ограничивающий прямоугольник белого цвета Изображение:

enter image description here

Текст, переданный белому изображению в нужный прямоугольник Регион:

enter image description here

Код:

import cv2
import numpy as np

# Read source text image.
src = cv2.imread('text_on_white.png')
hs, ws, cs = src.shape

# Read same text image with red rotated bounding box drawn.
src2 = cv2.imread('text2_on_white.png')

# Read white image showing desired output bounding box.
src2 = cv2.imread('text2_on_white.png')

# create white destination image
dst = np.full((hs,ws,cs), (255,255,255), dtype=np.uint8)

# define coordinates of bounding box in src
src_pts = np.float32([[51,123], [298,102], [300,135], [54,157]])

# size and placement of text in dst is (i.e. bounding box):
xd = 50
yd = 200
wd = 249
hd = 123
dst_pts = np.float32([[50,200], [298,200], [298,234], [50,234]])

# get rigid affine transform (no skew)
# use estimateRigidTransform rather than getAffineTransform so can use all 4 points
matrix = cv2.estimateRigidTransform(src_pts, dst_pts, 0)

# warp the source image
src_warped = cv2.warpAffine(src, matrix, (ws,hs), cv2.INTER_AREA, borderValue=(255,255,255))

# do numpy slicing on warped source and place in white destination
dst[yd:yd+hd, xd:xd+wd] = src_warped[yd:yd+hd, xd:xd+wd]

# show results
cv2.imshow('SRC', src)
cv2.imshow('SRC2', src2)
cv2.imshow('SRC_WARPED', src_warped)
cv2.imshow('DST', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save results
cv2.imwrite('text_on_white_transferred.png', dst)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...