Обработка изображений OpenCV для обрезки угловой части изображения в Python

#python #numpy #opencv #image-processing #python-imaging-library

#питон #numpy #opencv #обработка изображений #python-imaging-библиотека #python #python-imaging-library

Вопрос:

Я пытаюсь обрезать часть изображения, как показано ниже, используя opencv / PIL . Я хочу обрезать прямоугольную область, как показано красными линиями на изображении по ссылке ниже. Он наклонен под углом.

введите описание изображения здесь

Я использовал логику нарезки numpy, как показано ниже. Но он не обрезается под углом. Он обрезает обычный прямой прямоугольник

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

Также попробовал повернуть все изображение под углом, а затем обрезать эту часть, но это уменьшает результирующее изображение

Я могу нарисовать прямоугольник на этом изображении, используя приведенный ниже код :

определение draw_angled_rec(x0, y0, ширина, высота, угол, изображение):

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

Пожалуйста, предложите / посоветуйте способ достижения этой цели.

Спасибо

Комментарии:

1. Найдите пиксельные координаты 4 углов, затем разработайте уравнение линии между каждым, и если оно находится в области, ограниченной всеми 4 линиями, вы сохраняете пиксель? Кажется сложным, но лично я не знал бы более сложного (простого) способа

Ответ №1:

Обрезка изображения

Вот виджет извлечения изображения, который позволяет поворачивать изображение и выбирать рентабельность инвестиций щелчком мыши. Идея состоит в том, чтобы с помощью мыши выбрать окно ограничивающей рамки, в котором мы можем использовать Numpy slicing для обрезки изображения. Поскольку OpenCV не позволяет рисовать угловой прямоугольник, вы можете обойти это, сначала повернув изображение.

После того, как вы выбрали рентабельность инвестиций, вы можете обрезать изображение, используя координаты ограничивающей рамки. Если мы рассматриваем (0,0) как верхний левый угол изображения с направлением слева направо в качестве направления x и сверху вниз в качестве направления y, и мы имеем (x1, y1) в качестве верхней левой вершины и (x2,y2) в качестве нижней правой вершины ROI, мы можем обрезать изображение с помощью:

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

Мы можем это сделать, поскольку изображения хранятся в OpenCV в виде массива Numpy. Вот отличный ресурс для индексации и нарезки массива Numpy.

Для использования виджета:

  • left mouse click drag — выберите рентабельность инвестиций
  • right mouse click — сброс изображения
  • r — повернуть изображение по часовой стрелке на 5 градусов
  • e — поверните изображение против часовой стрелки на 5 градусов
  • c — обрезать выбранную рентабельность инвестиций
  • 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()