Оптимизировать функцию обрезки - PullRequest
1 голос
/ 31 марта 2020

Я использую следующий код для обрезки изображения и извлечения непрямого патча angular.

def crop_image(img,roi):
    height = img.shape[0]
    width = img.shape[1]

    mask = np.zeros((height, width), dtype=np.uint8)
    points = np.array([roi])
    cv2.fillPoly(mask, points, (255))

    res = cv2.bitwise_and(img, img, mask=mask)

    rect = cv2.boundingRect(points)  # returns (x,y,w,h) of the rect
    cropped = res[rect[1]: rect[1] + rect[3], rect[0]: rect[0] + rect[2]]

    return cropped, res

Рой [(1053, 969), (1149, 1071), (883, 1075), (813, 983)]. Однако приведенный выше код работает. Как мне оптимизировать скорость кода? Это слишком медленно. Есть ли другой лучший способ обрезки непрямых angular патчей?

Ответы [ 2 ]

1 голос
/ 01 апреля 2020

Вот один из способов использования Python / OpenCV и Numpy.

Ввод:

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread("efile.jpg")

points = np.array( [[ [693,67], [23,85], [62,924], [698,918] ]] )

# get bounding rectangle of points
x,y,w,h = cv2.boundingRect(points)
print(x,y,w,h)

# draw white filled polygon from points on black background as mask
mask = np.zeros_like(img)
cv2.fillPoly(mask, points, (255,255,255))

# fill background of image with black according to mask
masked = img.copy()
masked[mask==0] = 0

# crop to bounding rectangle
cropped = masked[y:y+h, x:x+w]

# write results
cv2.imwrite("efile_mask.jpg", mask)
cv2.imwrite("efile_masked.jpg", masked)
cv2.imwrite("efile_cropped.jpg", cropped)

# display it
cv2.imshow("efile_mask", mask)
cv2.imshow("efile_masked", masked)
cv2.imshow("efile_cropped", cropped)
cv2.waitKey(0)


Маска из указанных точек:

enter image description here

Изображение с черным фоном:

enter image description here

Обрезанный результат:

enter image description here

1 голос
/ 31 марта 2020

Я вижу две части, которые можно оптимизировать.

  1. Обрезка изображения до границ ограничивающего прямоугольника может быть применена в качестве первого шага. Выгода? Вы значительно уменьшите размер изображений, с которыми работаете. Вам нужно только перевести точки roi по x, y прямоугольника, и вы хороши для go.
  2. В операции bitwise_and вы «обгоняете» изображение с собой и проверяете в каждый пиксель, разрешено ли маской выводить его. Я думаю, это то место, где тратится больше всего времени. Вместо этого вы можете напрямую использовать маску «и» и сэкономить свое драгоценное время (без дополнительной проверки маски). Опять же, небольшая настройка, чтобы сделать это, изображение маски должно иметь точно такую ​​же форму, что и входное изображение (включая каналы).

Редактировать: Изменить код на поддержка любого количества каналов во входном изображении

Код ниже делает эти две вещи:

def crop_image(img, roi):
height = img.shape[0]
width = img.shape[1]
channels = img.shape[2] if len(img.shape) > 2 else 1

points = np.array([roi])

rect = cv2.boundingRect(points)

mask_shape = (rect[3], rect[2]) if channels == 1 else (rect[3], rect[2], img.shape[2])

#Notice how the mask image size is now the size of the bounding rect
mask = np.zeros(mask_shape, dtype=np.uint8)

#tranlsate the points so that their origin is the bounding rect top left point
for p in points[0]:
    p[0] -= rect[0]
    p[1] -= rect[1]


mask_filling = tuple(255 for _ in range(channels))
cv2.fillPoly(mask, points, mask_filling)

cropped = img[rect[1]: rect[1] + rect[3], rect[0]: rect[0] + rect[2]]

res = cv2.bitwise_and(cropped, mask)

return cropped, res
...