Повернутая ограничительная рамка на фотографиях с надежной обрезкой

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

Для демонстрации вот исходное изображение, связанное в следующем коде. Я хотел бы закончить туфлю, повернутую по вертикали и обрезанную до нужного размера. Следующий код из этого ответа, похоже, работает с простыми изображениями, такими как строки opencv и т. Д., Но не с фотографиями.

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

В конце концов, он повернут и неправильно обрезан:

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

РЕДАКТИРОВАТЬ: после изменения типа порога на cv2.THRESH_BINARY_INV теперь он повернут правильно, но обрезается неправильно:

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

import cv2
import matplotlib.pyplot as plt
import numpy as np
import urllib.request
plot = lambda x: plt.imshow(x, cmap='gray').figure


url = 'https://i.imgur.com/4E8ILuI.jpg'
img_path = 'shoe.jpg'

urllib.request.urlretrieve(url, img_path)
img = cv2.imread(img_path, 0)
plot(img)


threshold_value, thresholded_img = cv2.threshold(
    img, 250, 255, cv2.THRESH_BINARY)
_, contours, _ = cv2.findContours(thresholded_img, 1, 1)
contours.sort(key=cv2.contourArea, reverse=True)

shoe_contour = contours[0][:, 0, :]
min_area_rect = cv2.minAreaRect(shoe_contour)

def crop_minAreaRect(img, rect):

    # rotate img
    angle = rect[2]
    rows, cols = img.shape[0], img.shape[1]
    M = cv2.getRotationMatrix2D((cols / 2, rows / 2), angle, 1)
    img_rot = cv2.warpAffine(img, M, (cols, rows))

    # rotate bounding box
    rect0 = (rect[0], rect[1], 0.0)
    box = cv2.boxPoints(rect)
    pts = np.int0(cv2.transform(np.array([box]), M))[0]
    pts[pts < 0] = 0

    # crop
    img_crop = img_rot[pts[1][1]:pts[0][1],
                       pts[1][0]:pts[2][0]]

    return img_crop


cropped = crop_minAreaRect(thresholded_img, min_area_rect)
plot(cropped)

Как мне получить правильную обрезку?



person Hatshepsut    schedule 24.07.2017    source источник
comment
Этот сценарий кажется неполным: NameError: name 'min_area_rect' is not defined.   -  person Dan Mašek    schedule 25.07.2017
comment
@ DanMašek Спасибо, исправлено.   -  person Hatshepsut    schedule 25.07.2017
comment
Без проблем. В качестве первого шага я бы предложил использовать cv2.THRESH_BINARY_INV. На верхнем уровне findContours ищет белые объекты на черном фоне, поэтому на белом фоне самый большой контур соответствует всему изображению.   -  person Dan Mašek    schedule 25.07.2017
comment
minAreaRect тоже немного сложно. Для ограничивающего прямоугольника полного изображения я получаю ((492.5, 415.5), (829.0, 983.0), -90.0) - обратите внимание, что он говорит, что он выше, чем шире, с углом -90 градусов. Это необходимо учитывать, иначе он будет вращаться, когда не должен.   -  person Dan Mašek    schedule 25.07.2017
comment
@ DanMašek Обрезка неправильная, отредактированный вопрос, чтобы показать.   -  person Hatshepsut    schedule 25.07.2017
comment
Да, с этим ответом куча проблем. Проблема в том, что вы не можете просто повернуть, вам также нужно переводить в некоторых случаях (например, в этом, когда повернутый прямоугольник шире исходного изображения).   -  person Dan Mašek    schedule 25.07.2017
comment
@Hatshepsut Рассмотрите возможность поворота изображения по диагонали. Если у вас есть ограничивающая рамка, возьмите диагональ ограничительной рамки и поверните изображение относительно этой диагонали.   -  person Jeru Luke    schedule 25.07.2017
comment
Я тоже ищу ответ на этот вопрос. Вы наконец-то решили это?   -  person jdhao    schedule 20.02.2019


Ответы (1)


После некоторых исследований я получил следующее:

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

Вот как я это понял:

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

img = cv2.imread("padded_shoe.jpg")
# four corner points for padded shoe
cnt = np.array([
    [[313, 794]],
    [[727, 384]],
    [[1604, 1022]],
    [[1304, 1444]]
])
print("shape of cnt: {}".format(cnt.shape))
rect = cv2.minAreaRect(cnt)
print("rect: {}".format(rect))

box = cv2.boxPoints(rect)
box = np.int0(box)
width = int(rect[1][0])
height = int(rect[1][1])

src_pts = box.astype("float32")
dst_pts = np.array([[0, height-1],
                    [0, 0],
                    [width-1, 0],
                    [width-1, height-1]], dtype="float32")
M = cv2.getPerspectiveTransform(src_pts, dst_pts)
warped = cv2.warpPerspective(img, M, (width, height))

Ура, надеюсь, это поможет.

person jdhao    schedule 22.02.2019