OpenCV图像处理以在Python中裁剪图像的倾斜部分 [英] OpenCV Image Manipulation to Crop an Angled Section of an Image in Python

查看:546
本文介绍了OpenCV图像处理以在Python中裁剪图像的倾斜部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to crop a portion of an image as shown below using opencv / PIL . I want to crop the rectangle area as shown in red lines in the image in the below link. It is tilted at an angle.

我使用了如下的numpy切片逻辑.但是它不会倾斜.它会裁剪出一个普通的直角矩形

I used numpy slicing logic as below. But it doesn't crop at an angle. It crops a normal straight rectangle

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

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

Also tried rotating the entire image at an angle and then cropping that part but it shrinks the resulting image

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

I am able to draw a rectangle on that image using the below code :

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

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)

请提出/建议一种实现方法.

Please suggest / advice a way to achieve it.

谢谢

推荐答案

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

Here's a image extraction widget that allows you to rotate the image and select a ROI by clicking and dragging the mouse. The idea is to use the mouse to select the bounding box window where we can use Numpy slicing to crop the image. Since OpenCV does not let you draw an angled rectangle, you can bypass that by first rotating the image.

一旦选择了ROI,就可以使用边界框坐标裁剪图像.如果将(0,0)视为图像的左上角,从左至右作为x方向,从上至下作为y方向,则将(x1, y1)作为左上角顶点,将(x2,y2)作为ROI的右下角顶点,我们可以通过以下方式裁剪图像:

Once you have selected the ROI, you can then crop the image using the bounding box coordinates. If we consider (0,0) as the top left corner of the image with left-to-right as the x-direction and top-to-bottom as the y-direction and we have (x1, y1) as the top-left vertex and (x2,y2) as the bottom-right vertex of a ROI, we can crop the image by:

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

由于图像在OpenCV中存储为Numpy数组,因此我们能够做到这一点. 此处是Numpy数组索引和切片的重要资源.

We are able to do this since images are stored as a Numpy array in OpenCV. Here is a great resource for Numpy array indexing and slicing.

要使用小部件,请执行以下操作:

To use the widget:

  • left mouse click + drag-选择投资回报率
  • right mouse click-重置图像
  • r-顺时针旋转图像5度
  • e-逆时针旋转图像5度
  • c-选择作物的投资报酬率
  • q-退出程序
  • left mouse click + drag - select ROI
  • right mouse click - reset image
  • r - rotate image clockwise 5 degrees
  • e - rotate image counter-clockwise 5 degrees
  • c - crop selected ROI
  • q - quit program
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()

这篇关于OpenCV图像处理以在Python中裁剪图像的倾斜部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆