Alenorze
@Alenorze
Не люблю Индию

Как оптимизировать функцию на OpenCV?

Всем привет знатоки, есть функция которая работает достаточно медленно, у меня в распоряжении 72 ядра, хотелось бы услышать рекомендации по оптимизации, в нее приходит rgba не grayscale.

def color_transfer_init(image_with_alpha):

    image, image_mask = image_with_alpha[..., :3], image_with_alpha[..., 3]
    _, mask_hard = cv2.threshold(
        image_mask, MASK_THRESHOLD, 1.0, cv2.THRESH_BINARY)

    _x, mask_crop = cv2.threshold(
        image_mask, 0.01, 1.0, cv2.THRESH_BINARY)

    img_lab = cv2.cvtColor(image, cv2.COLOR_RGB2LAB)

    mask = np.uint8(mask_crop)
    cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
    cnt = sorted(cnts, key=cv2.contourArea)[-1]

    x,y,w,h = cv2.boundingRect(cnt)

    if h <= w:
        h = int(h * 1.8)
    elif h * 1.2 <= w:
        h = int(h * 1.3)
    elif h * 0.8 <= w:
        h = int(h * 1.3)

    mask_hard = mask_hard[y:y+h, x:x+w]
    img_lab = img_lab[y:y+h, x:x+w]
    img_rgba = image_with_alpha[y:y+h, x:x+w]
    
    img_mean, img_std = cv2.meanStdDev(
        img_lab, mask=mask_hard.astype(np.uint8))

    return img_lab, img_mean.reshape((3,)), img_std.reshape((3,)), img_rgba
  • Вопрос задан
  • 377 просмотров
Решения вопроса 1
@f4f
Мне кажется, надо порядок условных операторов поменять (h * 1.2 > h > h *0.8). В текущем варианте h * 1.2 не будет (поскольку первое условие выполнится).

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

Из очевидного, что касается именно opencv - нету смысла всю картинку переводить в lab, если потом вырезается roi. Сначала вырежьте roi, а потом переводите в lab. Аналогично можно сделать с mask_hard (хотя если использовать адаптивные методы бинаризации, то результат может немного отличаться по краям roi)

Не так хорошо знаком с opencv для python, но в версии для c++ по умолчанию используется распараллеливание, где возможно. Имеет смысл собирать библиотеку с openmp / tbb и смотреть, что какой дает прирос.

Если обрабатывается пачка картинок, то явно запускать в несколько потоков, аггрегируя результаты, если это необходимо.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
profesor08
@profesor08
Вот у тебя там несколько вызовов для обработки всех пикселей изображения. Операция тяжелая для процессора, там миллионы пикселей, и каждый надо обработать. Это именно то самое место, которое надо распараллелить на несколько ядер. Я не знаю, распарраллеливает ли OpenCV это дело, но ты можешь глянуть исходники на гите, там все будет ясно. Если нет распараллеливания, то придется этим заняться тебе и некоторые вещи считать вручную. Увы.
Ответ написан
Комментировать
adugin
@adugin Куратор тега Python
1) Заранее аллоцируйте память под результат и передавайте в функции OpenCV параметр dst, он есть почти везде.
2) Если нужен один контур с максимальной площадью, то не надо сортировать весь список sorted(cnts, key=cv2.contourArea)[-1], используйте max(cnts, key=cv2.contourArea).
3) ROI имеет смысл вырезать самым первым шагом, и уже потом делать преобразования.
4) Не очень понятен микс преобразования в uint8 и порога 1.0, нельзя как-то по-другому сделать?
5) Если Linux, то имеет смысл попробовать библиотеку pillow-simd, это форк PIL, заточена под векторные инструкции процессора.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы