在照片上稳健地裁剪旋转的边界框
Robustly crop rotated bounding box on photos
我正在尝试可靠地提取轮廓的旋转边界框。我想拍一张图片,找到最大的轮廓,得到它旋转的边界框,旋转图像使边界框垂直,然后裁剪到合适的大小。
为了演示,这里是在以下代码中链接的原始图像。我想最终将那只鞋旋转到垂直并裁剪成合适的尺寸。 中的以下代码似乎适用于 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)
如何获得正确的裁剪?
经过一些研究,这是我得到的:
我是这样得到的:
- 在每边填充原始图像(在我的例子中是 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))
干杯,希望对您有所帮助。
我正在尝试可靠地提取轮廓的旋转边界框。我想拍一张图片,找到最大的轮廓,得到它旋转的边界框,旋转图像使边界框垂直,然后裁剪到合适的大小。
为了演示,这里是在以下代码中链接的原始图像。我想最终将那只鞋旋转到垂直并裁剪成合适的尺寸。
最后是这个,旋转和裁剪错误:
编辑: 将阈值类型更改为 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)
如何获得正确的裁剪?
经过一些研究,这是我得到的:
我是这样得到的:
- 在每边填充原始图像(在我的例子中是 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))
干杯,希望对您有所帮助。