【问题标题】:OpenCV Image Manipulation to Crop an Angled Section of an Image in PythonOpenCV 图像处理以在 Python 中裁剪图像的斜切部分
【发布时间】:2019-08-27 17:53:54
【问题描述】:

我正在尝试使用 opencv / PIL 裁剪图像的一部分,如下所示。我想裁剪矩形区域,如以下链接中图像中的红线所示。它倾斜了一个角度。

我使用了如下的 numpy 切片逻辑。但它不会以某个角度裁剪。它裁剪一个正常的直矩形

rect = cv2.boundingRect(pts)  
x,y,w,h = rect   
cropped = img[y:y+h, x:x+w]  

还尝试将整个图像旋转一个角度,然后裁剪该部分,但它会缩小生成的图像

我可以使用以下代码在该图像上绘制一个矩形:

def draw_angled_rec(x0, y0, width, height, angle, img):

_angle = angle * math.pi / 180.0
b = math.cos(_angle) * 0.5
a = math.sin(_angle) * 0.5
pt0 = (int(x0 - a * height - b * width),
       int(y0 + b * height - a * width))
pt1 = (int(x0 + a * height - b * width),
       int(y0 - b * height - a * width))
pt2 = (int(2 * x0 - pt0[0]), int(2 * y0 - pt0[1]))
pt3 = (int(2 * x0 - pt1[0]), int(2 * y0 - pt1[1]))

cv2.line(img, pt0, pt1, (255,0,0), 3)
cv2.line(img, pt1, pt2, (255,0,0), 3)
cv2.line(img, pt2, pt3, (255,0,0), 3)
cv2.line(img, pt3, pt0, (255,0,0), 3)

请建议/建议实现它的方法。

谢谢

【问题讨论】:

  • 找到 4 个角的像素坐标,然后在每个角之间建立一条线的方程,如果它在由所有 4 条线包围的区域内,你保留像素吗?看起来很复杂,但我个人不知道更复杂(简单)的方法

标签: python numpy opencv image-processing python-imaging-library


【解决方案1】:

这是一个图像提取小部件,可让您通过单击并拖动鼠标来旋转图像并选择 ROI。这个想法是使用鼠标选择边界框窗口,我们可以在其中使用 Numpy 切片来裁剪图像。由于 OpenCV 不允许您绘制有角度的矩形,因此您可以通过首先旋转图像来绕过它。

选择 ROI 后,您可以使用边界框坐标裁剪图像。如果我们将(0,0) 视为图像的左上角,从左到右为x 方向,从上到下为y 方向,我们将(x1, y1) 作为左上顶点,@ 987654326@作为ROI右下角的顶点,我们可以通过以下方式裁剪图像:

ROI = image[y1:y2, x1:x2]

我们能够做到这一点,因为图像在 OpenCV 中存储为 Numpy 数组。 Here 是 Numpy 数组索引和切片的绝佳资源。

要使用小部件:

  • left mouse click + drag - 选择投资回报率
  • right mouse click - 重置图片
  • r - 将图像顺时针旋转 5 度
  • e - 逆时针旋转图像 5 度
  • c - 裁剪选定的 ROI
  • q - 退出程序
import cv2
import numpy as np

class ExtractImageWidget(object):
    def __init__(self):
        self.original_image = cv2.imread('plane.PNG')

        # Resize image, remove if you want raw image size
        self.original_image = cv2.resize(self.original_image, (640, 556))
        self.clone = self.original_image.copy()

        cv2.namedWindow('image')
        cv2.setMouseCallback('image', self.extract_coordinates)

        # Bounding box reference points and boolean if we are extracting coordinates
        self.image_coordinates = []
        self.angle = 0
        self.extract = False
        self.selected_ROI = False

    def extract_coordinates(self, event, x, y, flags, parameters):
        # Record starting (x,y) coordinates on left mouse button click
        if event == cv2.EVENT_LBUTTONDOWN:
            self.image_coordinates = [(x,y)]
            self.extract = True

        # Record ending (x,y) coordintes on left mouse bottom release
        elif event == cv2.EVENT_LBUTTONUP:
            self.image_coordinates.append((x,y))
            self.extract = False

            self.selected_ROI = True
            self.crop_ROI()

            # Draw rectangle around ROI
            cv2.rectangle(self.clone, self.image_coordinates[0], self.image_coordinates[1], (0,255,0), 2)
            cv2.imshow("image", self.clone) 

        # Clear drawing boxes on right mouse button click and reset angle
        elif event == cv2.EVENT_RBUTTONDOWN:
            self.clone = self.original_image.copy()
            self.angle = 0
            self.selected_ROI = False

    def show_image(self):
        return self.clone

    def rotate_image(self, angle):
        # Grab the dimensions of the image and then determine the center
        (h, w) = self.original_image.shape[:2]
        (cX, cY) = (w / 2, h / 2)

        self.angle += angle
        # grab the rotation matrix (applying the negative of the
        # angle to rotate clockwise), then grab the sine and cosine
        # (i.e., the rotation components of the matrix)
        M = cv2.getRotationMatrix2D((cX, cY), -self.angle, 1.0)
        cos = np.abs(M[0, 0])
        sin = np.abs(M[0, 1])

        # Compute the new bounding dimensions of the image
        nW = int((h * sin) + (w * cos))
        nH = int((h * cos) + (w * sin))

        # Adjust the rotation matrix to take into account translation
        M[0, 2] += (nW / 2) - cX
        M[1, 2] += (nH / 2) - cY

        # Perform the actual rotation and return the image
        self.clone = cv2.warpAffine(self.original_image, M, (nW, nH))

        self.selected_ROI = False

    def crop_ROI(self):
        if self.selected_ROI:
            self.cropped_image = self.clone.copy()

            x1 = self.image_coordinates[0][0]
            y1 = self.image_coordinates[0][1]
            x2 = self.image_coordinates[1][0]
            y2 = self.image_coordinates[1][1]

            self.cropped_image = self.cropped_image[y1:y2, x1:x2]

            print('Cropped image: {} {}'.format(self.image_coordinates[0], self.image_coordinates[1]))
        else:
            print('Select ROI to crop before cropping')

    def show_cropped_ROI(self):
        cv2.imshow('cropped image', self.cropped_image)

if __name__ == '__main__':
    extract_image_widget = ExtractImageWidget()
    while True:
        cv2.imshow('image', extract_image_widget.show_image())
        key = cv2.waitKey(1)

        # Rotate clockwise 5 degrees
        if key == ord('r'):
            extract_image_widget.rotate_image(5)

        # Rotate counter clockwise 5 degrees
        if key == ord('e'):
            extract_image_widget.rotate_image(-5)

        # Close program with keyboard 'q'
        if key == ord('q'):
            cv2.destroyAllWindows()
            exit(1)

        # Crop image
        if key == ord('c'):
            extract_image_widget.show_cropped_ROI()

【讨论】:

    猜你喜欢
    • 2023-03-05
    • 1970-01-01
    • 2012-12-31
    • 1970-01-01
    • 1970-01-01
    • 2014-06-01
    • 1970-01-01
    • 2023-04-03
    • 2017-08-04
    相关资源
    最近更新 更多