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

У меня есть изображение в градациях серого страницы комиксов, в котором есть несколько диалоговых пузырьков (= речевые балуны и т.д.), которые заключены в области с белым фоном и сплошными черными границами, которые содержат текст внутри, то есть что-то вроде этого:

Пример изображения комикса

Я хочу обнаружить эти области и создать маску (двоичный код в порядке), который будет охватывать все внутренние области диалогов, т.е. что-то вроде:

Образец результата маскирования

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

Пример изображения с прозрачным наложением маски

Итак, моя основная идея алгоритма была примерно такой:

  • Определите, где находится текст - запустите по крайней мере один пиксель в каждом пузыре. Немного развейте эти районы и примените порог, чтобы получить лучшую начальную почву; Я сделал эту часть:

Текстовые позиции, очерченные

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

  2. Используйте некоторую операцию binary_closing для удаления темных областей (т.е. областей, соответствующих тексту) внутри пузырьков). Эта часть работает нормально.

Пока что шаги 1 и 3 работают, но я боюсь с шага 2. В настоящее время я работаю с scikit-image, и я не вижу никаких готовых алгоритмов, таких как заливка заливок. Очевидно, что я могу использовать что-то тривиальное, как обход ширины, в основном как предлагается здесь, но на самом деле это очень медленно, когда это делается на Python. Я подозреваю, что сложная морфология вроде binary_erosion или generate_binary_structure in ndimage или scikit-image, но я изо всех сил пытаюсь понять всю эту морфологическую терминологию и в основном как реализовать такую ​​пользовательскую заливку заливки (т.е. начиная с изображения с шага 1, работая над исходным изображением и производя вывод для отдельного выходного изображения).

Я открыт для любых предложений, в том числе в OpenCV и т.д.

Ответ 1

Несмотря на то, что ваш фактический вопрос касается этапа 2 вашего конвейера обработки, я хотел бы предложить другой подход, который может быть, imho, проще, и, как вы заявили, что вы открыты для предложений.

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

    Реализована

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

    Обнаружение кромок

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

    Водораздел-сегментация

Прошу прощения за этот общий ответ, но здесь слишком поздно для фактического кодирования для меня, но если вопрос все еще открыт, и вам нужно/нужно еще несколько советов относительно моего предложения, я подробно рассмотрю его. Но вы можете определенно взглянуть на сегментирование по регионам в документах scikit-image.

Ответ 2

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

Поскольку вы не даете исходный код, мне приходилось создавать что-то с нуля, которое, надеюсь, хорошо взаимодействует с вашим выходом с шага 1. Для этого я просто взял 2 фиксированные координаты, вы бы взяли белые точки рядом с центрами blob, созданными из текста вы извлекли на шаге 1. Как только вы предоставите правильный код, вы можете настроить этот интерфейс.

Я взял на себя смелость заполнить все внутренние отверстия, созданные вашими письмами. Если вы этого не хотите, вы можете пропустить код из строки 36.

Для решения я фактически взял идеи из двух частей кода, которые я привел в приведенном ниже тексте. Здесь вы можете найти более полезную информацию.

Держите нас в курсе вашего прогресса!

import cv2
import numpy as np

# with ideas from:
# http://www.learnopencv.com/filling-holes-in-an-image-using-opencv-python-c/
# http://stackoverflow.com/info/10316057/filling-holes-inside-a-binary-object
print cv2.__file__

# Read image
im_in = cv2.imread("gIEXY.png", cv2.IMREAD_GRAYSCALE);

# Threshold.
# Set values equal to or above 200 to 0.
# Set values below 200 to 255.

th, im_th = cv2.threshold(im_in, 200, 255, cv2.THRESH_BINARY_INV);

# Copy the thresholded image.
im_floodfill = im_th.copy()

# Mask used to flood filling.
# Notice the size needs to be 2 pixels than the image.
h, w = im_th.shape[:2]
mask = np.zeros((h+2, w+2), np.uint8)

# Floodfill from points inside baloons
cv2.floodFill(im_floodfill, mask, (80,400), 128);
cv2.floodFill(im_floodfill, mask, (610,90), 128);

# Invert floodfilled image
im_floodfill_inv = cv2.bitwise_not(im_floodfill)

# Combine the two images to get the foreground
im_out = im_th | im_floodfill_inv

# Create binary image from segments with holes
th, im_th2 = cv2.threshold(im_out, 130, 255, cv2.THRESH_BINARY)

# Create contours to fill holes
im_th3 = cv2.bitwise_not(im_th2)
contour,hier = cv2.findContours(im_th3,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)

for cnt in contour:
    cv2.drawContours(im_th3,[cnt],0,255,-1)

segm = cv2.bitwise_not(im_th3)


# Display image
cv2.imshow("Original", im_in)
cv2.imshow("Segmented", segm)
cv2.waitKey(0)