Подтвердить что ты не робот

Как обрезать самый большой прямоугольник из изображения

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

Я делаю следующее, но не получаю желаемых результатов:

import cv2
import numpy as np

im = cv2.imread('images/img5.jpg')
gray=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,0)
_,contours,_ = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow("Show",im)
cv2.imwrite("images/img5_rect.jpg", im)
cv2.waitKey(0)

Ниже приведены несколько примеров:

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

введите описание изображения здесь

Второй пример: не найти правильные размеры прямоугольника на этом изображении. введите описание изображения здесь

введите описание изображения здесь

3-й пример. Невозможно найти правильные размеры на этом изображении. введите описание изображения здесь введите описание изображения здесь

4-й пример. То же самое и с этим. введите описание изображения здесь введите описание изображения здесь

4b9b3361

Ответ 1

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

  • Обычно бумага (ребра, по крайней мере) белая, поэтому вам может быть повезло, перейдя в цветовое пространство, такое как YUV, которое лучше разделяет светимость:

    image_yuv = cv2.cvtColor(image,cv2.COLOR_BGR2YUV)
    image_y = np.zeros(image_yuv.shape[0:2],np.uint8)
    image_y[:,:] = image_yuv[:,:,0]
    
  • Текст на бумаге является проблемой. Используйте эффект размытия, чтобы (надеюсь) удалить эти высокочастотные шумы. Вы также можете использовать морфологические операции, такие как дилатация.

    image_blurred = cv2.GaussianBlur(image_y,(3,3),0)
    
  • Вы можете попытаться применить canny edge-detector, а не простой порог. Не обязательно, но может помочь вам:

     edges = cv2.Canny(image_blurred,100,300,apertureSize = 3)
    
  • Затем найдите контуры. В моем случае я использовал только экстремальные внешние контуры. Вы можете использовать флаг CHAIN_APPROX_SIMPLE для сжатия контура

    contours,hierarchy = cv2.findContours(edges,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    
  • Теперь у вас должна быть куча контуров. Время найти правильные. Для каждого контура cnt сначала найдите выпуклую оболочку, затем используйте approaxPolyDP, чтобы максимально упростить контур.

    hull = cv2.convexHull(cnt)
    simplified_cnt = cv2.approxPolyDP(hull,0.001*cv2.arcLength(hull,True),True)
    
  • Теперь мы должны использовать этот упрощенный контур, чтобы найти охватывающий четырехугольник. Вы можете экспериментировать с множеством правил, которые вы придумали. Самый простой способ - выбрать четыре самых длинных сегмента контура, а затем создать круглый четырехугольник, пересекая эти четыре линии. Основываясь на вашем случае, вы можете найти эти строки на основе контрастности линии, угла, который они создают, и подобных вещей.

  • Теперь у вас есть куча четырехугольников. Теперь вы можете выполнить двухэтапный метод, чтобы найти нужный четырехсторонний. Сначала вы удаляете те, которые, вероятно, ошибаются. Например, один угол четырехугольника составляет более 175 градусов. Тогда вы можете выбрать тот, у которого самая большая площадь, в качестве конечного результата. Вы можете видеть оранжевый контур как один из результатов, которые я получил в этот момент: Все контуры

  • Последний шаг после нахождения (надеюсь) правого четырехугольника, превращается обратно в прямоугольник. Для этого вы можете использовать findHomography для создания матрицы преобразования.

    (H,mask) = cv2.findHomography(cnt.astype('single'),np.array([[[0., 0.]],[[2150., 0.]],[[2150., 2800.]],[[0.,2800.]]],dtype=np.single))
    

    Числа предполагают проецирование на бумагу с буквой. Вы можете придумать лучшие и более умные числа для использования. Вам также необходимо изменить порядок точек контура в соответствии с порядком координат буквенной бумаги. Затем вы вызываете warpPerspective для создания окончательного изображения:

    final_image = cv2.warpPerspective(image,H,(2150, 2800))
    

    Это деформирование должно привести к чему-то вроде следующего (из моих результатов раньше): Warping

Надеюсь, это поможет вам найти подходящий подход в вашем случае.

Ответ 2

Это довольно сложная задача, которая не может быть решена путем простого поиска контуров. Например, покрытие "Economist" показывает только 1 край магазина, который разбивает изображение пополам. Как ваш компьютер должен знать, какой из них - журнал, а какой - стол? Таким образом, вы должны добавить гораздо больше интеллекта в свою программу.

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

В общем, это слишком широкий вопрос для StackOverflow. Попытайтесь разбить его на более мелкие проблемы, попытайтесь их решить, и если вы ударите стену, вернитесь сюда.