Выравнивание изображений с помощью openCV

У меня есть коллекция из примерно 250 изображений. Все они были отсканированы с книги, поэтому все они немного смещены или повернуты относительно друг друга. Теперь я хотел бы извлечь некоторые данные из этих изображений, но для того, чтобы сделать это автоматически, все позиции на всех изображениях должны быть идентичными. Вот почему мне нужно как-то выровнять эти изображения, чтобы все позиции на всех изображениях соответствовали друг другу. Каков наилучший способ добиться этого? Я решил, что openCV - лучший способ сделать это, но я не уверен, с чего мне начать.

Ниже приведен пример отсканированного изображения:

Выравнивание изображений с помощью openCV

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
1 691
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Пунктирные линии, вероятно, являются хорошей опорной точкой.

Вы можете использовать маску для выравнивания отдельных изображений. Сканируйте края масок для получения координат и используйте их для поворота и смещения изображений. Под этим я подразумеваю перебор значений верхней строки маски. Первый белый пиксель дает верхнюю центральную координату. Аналогично для других сторон маски. Вы можете сравнить эти значения на разных изображениях, чтобы определить сдвиг и поворот. Чтобы применить эти преобразования, прочитайте здесь. Это потребует довольно много работы, хотя. Возможно, есть более простой вариант:

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

Отдельные субизображения:

Код:

    import cv2
    import numpy as np  
    # load image
    img_large=cv2.imread("BAgla.jpg")
    # resize for ease of use
    img_ori = cv2.resize(img_large, None, fx=0.2, fy=0.2, interpolation= cv2.INTER_CUBIC)
    # create grayscale
    img = cv2.cvtColor(img_ori, cv2.COLOR_BGR2GRAY)
    # create mask for image size
    mask = np.zeros((img.shape[:2]),dtype=np.uint8)
    # do a morphologic close to merge dotted line
    kernel = np.ones((8,8))
    res = cv2.morphologyEx(img,cv2.MORPH_OPEN, kernel)
    # detect edges for houglines
    edges = cv2.Canny(res, 50,50)
    # detect lines
    lines = cv2.HoughLines(edges,1,np.pi/180,200)
    # draw detected lines
    for line in lines:
            rho,theta = line[0]
            a = np.cos(theta)
            b = np.sin(theta)
            x0 = a*rho
            y0 = b*rho
            x1 = int(x0 + 1000*(-b))
            y1 = int(y0 + 1000*(a))
            x2 = int(x0 - 1000*(-b))
            y2 = int(y0 - 1000*(a))

            cv2.line(mask,(x1,y1),(x2,y2),(255),2)
            cv2.line(img,(x1,y1),(x2,y2),(127),2)

    # invert the mask for use with findcontours
    mask_inv = cv2.bitwise_not(mask)
    # use findcontours to get the boundingboxes of the tiles
    contours, hier = cv2.findContours(mask_inv,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    boundingrects = []
    for cnt in contours:
            boundingrects.append(cv2.boundingRect(cnt))

    # findContours has no garanteed order, so sort array
    boundingrects.sort()

    # titles for window names / save file names
    title = ['Kaart', None, 'Smaakprofiel', 'Basiswaarden','Gelijkaardige bieren','Chemisch Profiel']

    # create images for top and bottom tiles
    for index in [0,2,3,5]:
            x,y,w,h = boundingrects[index]
            subimg = img_ori[y:y+h,x:x+w]
            cv2.imshow(title[index], subimg  )

    # combine middle tiles
    x1,y1,w1,h1 = boundingrects[1]
    x2,y2,w2,h2 = boundingrects[4]
    subimg = img_ori[y1:y2+h2,x1:x2+w2]
    cv2.imshow(title[4], subimg  )

    # display result
    cv2.imshow("Result", img  )
    cv2.imshow("Mask", mask  )
    cv2.waitKey(0)
    cv2.destroyAllWindows()

Обратите внимание, что я использовал уменьшенную версию изображения, так что учтите это при обработке изображений.

Хорошо, пока я понимаю, как трансформировать и обнаруживать линии. Но потом вы сказали, что можно «использовать маску для выравнивания отдельных изображений». Как мне это сделать? Вы заявили, что я могу сканировать края масок в поисках координат и использовать их для поворота и смещения изображений. Честно говоря, я понятия не имел, как это сделать... Должен ли я применять положения этих строк из первого изображения ко всем остальным 250 изображениям? Или какой подход будет лучшим?

Frederik Vanclooster 27.06.2019 16:43

Я часто получаю ошибку в следующей строке ret, contours, hier = cv2.findContours(mask_inv,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX‌​_SIMPLE). Там написано ValueError: not enough values to unpack (expected 3, got 2)

Frederik Vanclooster 17.07.2019 16:12

Это потому, что у вас более новая версия openCV. Просто удалите ret,, так как это значение больше не возвращается: contours, hier = cv2.findContours(mask_inv,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX‌​_SIMPLE). Я также обновил ответ

J.D. 17.07.2019 20:58

Хорошо, спасибо, тогда еще один вопрос. Вы уменьшаете изображение для удобства использования. Имеет ли это какие-либо последствия, если я хочу извлечь данные из графиков в субизображениях? Если да, то что я должен учитывать при использовании полноразмерных изображений?

Frederik Vanclooster 18.07.2019 21:02

Самый простой подход — изменить способ создания фрагмента изображения. Вместо img_ori используйте img_large и умножьте размер части изображения на 5 (поскольку размер изображения был уменьшен до 20%). Некрасивый: subimg = img_large[y*5:y*5+h*5,x*5:x*5+w*5]

J.D. 18.07.2019 23:05

Или можно с самого начала использовать img_large вместо его уменьшения?

Frederik Vanclooster 19.07.2019 00:41

Конечно. Вам нужно будет настроить morphologyEx, чтобы пунктирная линия правильно соединилась в сплошную линию. Может быть, Canny и HoughLines тоже. Просто попробуйте несколько вещей и посмотрите на эффект. Общий результат будет таким же, за исключением того, что обработка уменьшенного изображения более эффективна. Поэтому я бы посоветовал метод умножения.

J.D. 19.07.2019 08:03

Спасибо за помощь. Я заметил, что вы сортируете массив ограничивающих прямоугольников, однако это, похоже, не обеспечивает равномерного упорядочения всех фрагментов изображений. Дело в том, что я хотел бы использовать только части изображения, содержащие круговые графики, но для того, чтобы извлечь их из массива boundingrects, порядок должен быть последовательным. В большинстве случаев я полагал, что индексы 2 и 5 кажутся правильными, но есть некоторые изображения, которые производят другой порядок. Любая идея, как это возможно и как это можно исправить?

Frederik Vanclooster 02.08.2019 20:26

Я заметил, что на некоторых отсканированных изображениях на скане видна строка, с которой начинается следующая страница книги. Эта линия, кажется, мешает обнаружению контуров для создания подизображений. Можно ли как-то игнорировать эту строку, не игнорируя при этом нужные пунктиры? Редактировать: после некоторой обрезки я заметил, что линия была не единственной проблемой, почему-то горизонтальные пунктирные линии обнаруживаются дважды, а вертикальные линии не обнаруживаются. Может ли это быть как-то связано с небольшим вращением сканов?

Frederik Vanclooster 02.08.2019 20:54

Через некоторое время, пытаясь понять это, я пришел к выводу, что преобразование HoughLines обнаруживает несколько строк из обнаружения края Canny. Итак, каким-то образом я должен попытаться «сгладить» вывод canny, чтобы hough обнаруживал только отдельные строки, а не несколько... Однако я уже некоторое время пытаюсь это исправить, я понятия не имею, как это сделать.

Frederik Vanclooster 02.08.2019 23:26

Сортировка основана на значениях x/y. Если страница наклонена, это может привести к последовательному виду. Вместо этого вы можете определить правильный, используя дерево решений. Например, если x < 25% ширины страницы и y > 50% длины страницы, то это левый нижний угол.

J.D. 03.08.2019 01:11

Что касается обнаружения строк, то это необходимо для обработки в комментариях. Лучше открыть новый вопрос. Обновлено: только что увидел, что у вас уже есть.

J.D. 03.08.2019 01:13

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

Frederik Vanclooster 03.08.2019 01:14

Другие вопросы по теме