Crop Rectangle, возвращаемый minAreaRect OpenCV

minAreaRect в OpenCV возвращает вращающийся прямоугольник. Как обрезать эту часть изображения внутри прямоугольника?

boxPoints возвращает координаты угловых точек повернутого прямоугольника, так что вы можете получить доступ к пикселям, пройдя через точки внутри поля, но есть ли более быстрый способ обрезать в Python?

  • Обнаружение пиков в 2D-массиве
  • Каковы некоторые методы анализа яркости изображения с помощью Python?
  • Получение ограничивающей рамки распознанных слов с использованием python-tesseract
  • Как вы совмещаете изображение с другим изображением с PIL в Python?
  • Использование Python для инвертирования и перевода изображений
  • Как обнаружить Рождественскую елку?
  • РЕДАКТИРОВАТЬ

    См. code в моем ответе ниже.

  • Каков самый быстрый способ рисовать изображение из дискретных значений пикселей в Python?
  • ImportError: невозможно импортировать имя _imaging
  • Обрезка изображения с существующего изображения
  • С помощью библиотеки изображений Python (PIL), как создать изображение с альфа-каналом над другим изображением?
  • Загрузка изображения Python OpenCV из строки байтов
  • Как читать сырое изображение с помощью PIL?
  • 4 Solutions collect form web for “Crop Rectangle, возвращаемый minAreaRect OpenCV”

    Вы не дали пример кода, поэтому я также отвечаю без кода. Вы можете действовать следующим образом:

    1. Из углов прямоугольника определите угол α вращения относительно горизонтальной оси.
    2. Поверните изображение по альфа, чтобы прямоугольник с обрезанной стороной был параллелен границам изображения. Убедитесь, что временное изображение больше по размеру, поэтому никакая информация не теряется (cf: Поворот изображения без обрезки OpenCV )
    3. Обрезать изображение с помощью numpy slicing (cf: как обрезать изображение в OpenCV с помощью Python )
    4. Поверните изображение назад по-альфе.

    Вот код для выполнения вышеуказанной задачи. Чтобы ускорить процесс, вместо первого поворота всего изображения и обрезки часть изображения, которая имеет повернутый прямоугольник, сначала обрезается, затем поворачивается и обрезается снова, чтобы дать конечный результат.

     # Let cnt be the contour and img be the input rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect) box = np.int0(box) W = rect[1][0] H = rect[1][1] Xs = [i[0] for i in box] Ys = [i[1] for i in box] x1 = min(Xs) x2 = max(Xs) y1 = min(Ys) y2 = max(Ys) angle = rect[2] if angle < -45: angle += 90 # Center of rectangle in source image center = ((x1+x2)/2,(y1+y2)/2) # Size of the upright rectangle bounding the rotated rectangle size = (x2-x1, y2-y1) M = cv2.getRotationMatrix2D((size[0]/2, size[1]/2), angle, 1.0) # Cropped upright rectangle cropped = cv2.getRectSubPix(img, size, center) cropped = cv2.warpAffine(cropped, M, size) croppedW = H if H > W else W croppedH = H if H < W else W # Final cropped & rotated rectangle croppedRotated = cv2.getRectSubPix(cropped, (int(croppedW),int(croppedH)), (size[0]/2, size[1]/2)) 

    здесь функция, которая выполняет эту задачу:

     import cv2 import numpy as np 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 

    здесь пример использования

     # generate image img = np.zeros((1000, 1000), dtype=np.uint8) img = cv2.line(img,(400,400),(511,511),1,120) img = cv2.line(img,(300,300),(700,500),1,120) # find contours / rectangle _,contours,_ = cv2.findContours(img, 1, 1) rect = cv2.minAreaRect(contours[0]) # crop img_croped = crop_minAreaRect(img, rect) # show import matplotlib.pylab as plt plt.figure() plt.subplot(1,2,1) plt.imshow(img) plt.subplot(1,2,2) plt.imshow(img_croped) plt.show() 

    это выход

    оригинальное и обрезанное изображение

    @AbdulFatir был готов к хорошему решению, но, как сказано в комментариях (@Randika @epinal), это не совсем работало для меня, так что я немного изменил его и, похоже, работал для моего дела. вот изображение, которое я использую. mask_of_image

     im, contours, hierarchy = cv2.findContours(open_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) print("num of contours: {}".format(len(contours))) mult = 1.2 # I wanted to show an area slightly larger than my min rectangle set this to one if you don't img_box = cv2.cvtColor(img.copy(), cv2.COLOR_GRAY2BGR) for cnt in contours: rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect) box = np.int0(box) cv2.drawContours(img_box, [box], 0, (0,255,0), 2) # this was mostly for debugging you may omit W = rect[1][0] H = rect[1][1] Xs = [i[0] for i in box] Ys = [i[1] for i in box] x1 = min(Xs) x2 = max(Xs) y1 = min(Ys) y2 = max(Ys) rotated = False angle = rect[2] if angle < -45: angle+=90 rotated = True center = (int((x1+x2)/2), int((y1+y2)/2)) size = (int(mult*(x2-x1)),int(mult*(y2-y1))) cv2.circle(img_box, center, 10, (0,255,0), -1) #again this was mostly for debugging purposes M = cv2.getRotationMatrix2D((size[0]/2, size[1]/2), angle, 1.0) cropped = cv2.getRectSubPix(img_box, size, center) cropped = cv2.warpAffine(cropped, M, size) croppedW = W if not rotated else H croppedH = H if not rotated else W croppedRotated = cv2.getRectSubPix(cropped, (int(croppedW*mult), int(croppedH*mult)), (size[0]/2, size[1]/2)) plt.imshow(croppedRotated) plt.show() plt.imshow(img_box) plt.show() 

    Это должно создать серию таких изображений: изолированный контур 1 изолированный контур 2 изолированный контур 3

    И это также даст результат: Результаты

    Python - лучший язык программирования в мире.