如何在OpenCV中旋转边界框并裁剪它(Python)

4
我有一个矩形的坐标(XMIN,YMIN,XMAX和YMAX),在一张特定的图片上。我希望将该矩形旋转到特定角度,然后从图像中裁剪出来。怎么做呢?
例如,这个image。我已经得到了左侧显示的输出边界框(使用XMIN,YMIN,XMAX和YMAX绘制)。我想按右侧的图像旋转它,然后裁剪它。
请问有人能提供样例代码或指向一个解释的链接吗?

请让您的问题更清晰明确。您是要在什么背景上绘制这4个点?一些图像吗?还是只是坐标? 请参阅“导览”(https://stackoverflow.com/tour)并阅读“帮助中心”(https://stackoverflow.com/help)中的信息指南,特别是“如何提出好问题”(https://stackoverflow.com/help/how-to-ask),“好主题是什么”(https://stackoverflow.com/help/on-topic)和“如何创建一个最小可复现示例”(https://stackoverflow.com/help/minimal-reproducible-example)。 - fmw42
完成...希望现在清楚了 - Marcus Richard
1
将你的图像裁剪到那些边界框的坐标上。使用cv2.rotate()参见 https://docs.opencv.org/4.1.1/dd/d99/classcv_1_1Affine3.html#a990d571a479b9b336f30c259fb74d18c 获得轮廓及其旋转的边界框。查阅cv2.minAreaRect() 参见 https://docs.opencv.org/4.1.1/d3/dc0/group__imgproc__shape.html#ga3d476a3417130ae5154aea421ca7ead9 。或者,旋转图像。计算旋转框的坐标,从旋转点绘制填充多边形。使用填充多边形作为遮罩来抹掉背景。在不带额外线条的原始输入图像上发布。 - fmw42
你想要旋转多少角度?确切的边界坐标是什么?当您提出问题并提供原始图像时,请编写完整的要求,而不是组合或屏幕截图。 - fmw42
这里有一个关于各种选项的不错讨论:https://www.pyimagesearch.com/2017/01/02/rotate-images-correctly-with-opencv-and-python/ - abarry
2个回答

4

以下是使用Python/OpenCV的一种方法。

  • 读取输入图像
  • 转换为HSV图像
  • 对绿色方框进行颜色阈值处理
  • 获取外轮廓
  • 打印边界框
  • 将图像顺时针旋转10度
  • 将旋转后的图像转换为HSV图像
  • 对旋转后的绿色方框进行颜色阈值处理
  • 获取外轮廓
  • 创建一个黑色图像,并用白色轮廓填充
  • 获取白色像素坐标
  • 从坐标中获取最小区域矩形
  • 获取旋转矩形的顶点
  • 在旋转后的图像上绘制旋转矩形轮廓

输入:

enter image description here

import cv2
import numpy as np
from scipy import ndimage

# load image
img = cv2.imread("berry.png")

# convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# threshold using inRange or green
range1 = (20,200,170)
range2 = (80,255,255)
thresh = cv2.inRange(hsv,range1,range2)

# get bounding box coordinates from the one outer contour
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
x,y,w,h = cv2.boundingRect(contours[0])
print("bounding_box(x,y,w,h):",x,y,w,h)

# rotate image by 10 degree clockwise
rotated = img.copy()
rotated = ndimage.rotate(img, -10, cval=255)


# convert rotated to hsv
hsv_rotated = cv2.cvtColor(rotated, cv2.COLOR_BGR2HSV)

# threshold using inRange or green
range1 = (20,200,170)
range2 = (80,255,255)
thresh_rotated = cv2.inRange(hsv_rotated,range1,range2)

# get bounding box coordinates from the one outer contour
contours = cv2.findContours(thresh_rotated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]

# draw white filled contour on black background
mask = np.zeros_like(thresh_rotated)
cv2.drawContours(mask, [contours[0]], -1, (255), -1)

# get coordinates of white pixels in mask
coords = np.column_stack(np.where(mask.transpose() > 0))

# get rotated rectangle
rotrect = cv2.minAreaRect(coords)

# rotated rectangle box points
box = np.int0(cv2.boxPoints(rotrect))
print("rotate_box_corners:\n",box)

# draw rotated rectangle on rotated image
result = rotated.copy()
cv2.polylines(result, [box], True, (0,0,255), 1)


# write result to disk
cv2.imwrite("berry_thresh.png", thresh)
cv2.imwrite("berry_rotated.png", rotated)
cv2.imwrite("berry_thresh_rotated.png", thresh_rotated)
cv2.imwrite("berry_mask.png", mask)
cv2.imwrite("berry_rotated_box.png", result)

# display results
cv2.imshow("THRESH", thresh)
cv2.imshow("ROTATED", rotated)
cv2.imshow("THRESH_ROT", thresh_rotated)
cv2.imshow("MASK", mask)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()


输入绿线阈值:

enter image description here

旋转后的输入图像:

enter image description here

旋转图像中的绿线阈值:

enter image description here

填充阈值:

enter image description here

在旋转图像上显示旋转矩形的结果:

enter image description here

输入边界框:

bounding_box(x,y,w,h): 12 13 212 124


输出顶点:

rotate_box_corners:
 [[222 172]
 [ 14 136]
 [ 35  14]
 [243  51]]



3
您可以使用旋转矩阵来旋转图像和边界框。
步骤:
  1. 生成旋转矩阵
  2. 使用OpenCV的 warpAffine 函数旋转图像
  3. 使用相同的旋转矩阵旋转边界框的4个角点
请了解 getRotationMatrix2DwarpAffine

    img_path = '' #The image path
    bb = [] #XMIN,YMIN,XMAX,YMAX
    angle = 3 #Rotation angle in degrees, +ve is counter-clockwise
    
    bb = np.array(((bb[0],bb[1]),(bb[2],bb[1]),(bb[2],bb[3]),(bb[0],bb[3]))) #Get all 4 coordinates of the box
    
    img = cv2.imread(img_path) #Read the img
    
    center = (img.shape[0]//2,img.shape[1]//2) #Get the center of the image
    
    rotMat = cv2.getRotationMatrix2D(center,angle,1.0) #Get the rotation matrix, its of shape 2x3
    
    img_rotated = cv2.warpAffine(img,rotMat,img.shape[1::-1]) #Rotate the image
    
    bb_rotated = np.vstack((bb.T,np.array((1,1,1,1)))) #Convert the array to [x,y,1] format to dot it with the rotMat
    bb_rotated = np.dot(rotMat,bb_rotated).T #Perform Dot product and get back the points in shape of (4,2)
    
    #Plot the original image and bb
    plt.imshow(img)
    plt.plot(
        np.append(bb[:,0],bb[0,0]),
        np.append(bb[:,1],bb[0,1])
    )
    plt.show()
    
    #Plot the rotated image and bb
    plt.imshow(img_rotated)
    plt.plot(
        np.append(bb_rotated[:,0],bb_rotated[0,0]),
        np.append(bb_rotated[:,1],bb_rotated[0,1])
    )
    plt.show()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接