【问题标题】:Robustly crop rotated bounding box on photos稳健地裁剪照片上的旋转边界框
【发布时间】:2017-12-30 11:29:00
【问题描述】:

我正在尝试稳健地提取轮廓的旋转边界框。我想拍一张图片,找到最大的轮廓,得到它的旋转边界框,旋转图像使边界框垂直,然后裁剪到大小。

为了演示,这里是在以下代码中链接的原始图像。我想最终将那只鞋旋转到垂直并裁剪成合适的尺寸。 this answer 的以下代码似乎适用于简单的图像,如 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)

我怎样才能得到正确的裁剪?


【问题讨论】:

  • 该脚本似乎不完整:NameError: name 'min_area_rect' is not defined.
  • @DanMašek 谢谢,已修复。
  • 没问题。作为第一步,我建议使用cv2.THRESH_BINARY_INV。在顶层,findContours 在黑色背景上寻找白色物体,因此白色背景下最大的轮廓对应于整个图像。
  • minAreaRect 也有点棘手。对于完整的图像边界框,我得到((492.5, 415.5), (829.0, 983.0), -90.0) - 注意它说它比更宽更高,角度为-90度。这需要考虑,否则它不应该旋转。
  • @DanMašek 裁剪不正确,要显示已编辑的问题。

标签: python image opencv cv2


【解决方案1】:

经过一番研究,这是我得到的:

这就是我得到它的方式:

  • 在每一侧填充原始图像(在我的情况下为 500 像素)
  • 找到鞋子的四个角点(四个点应该形成一个包围鞋子的多边形,但不必是精确的矩形)
  • 使用代码here裁剪鞋子:

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))

干杯,希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 2022-06-23
    • 1970-01-01
    • 2021-01-22
    • 1970-01-01
    相关资源
    最近更新 更多