[PYTHON] Transformation affine par OpenCV (CUDA)

Motivation

Voir Articles précédents

Résumé

environnement

code

Prétraitement

Tout d'abord, lisez diverses choses, puis obtenez 200 * 200 maharo.jpg. Il s'agit du [Mahalo-kun] de Kawauso dans l'aquarium Sunshine (https://wikiwiki.jp/kawausotter/%E3%83%9E%E3%83%8F%E3%83%AD%EF%BC%88%E3% 82% B5% E3% 83% B3% E3% 82% B7% E3% 83% A3% E3% 82% A4% E3% 83% B3% E6% B0% B4% E6% 97% 8F% E9% A4% C'est une image de A8% EF% BC% 89). Voir Articles précédents pour plus de détails sur ce domaine.

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
print('Enabled CUDA devices:',cv.cuda.getCudaEnabledDeviceCount()) # 1

src = cv.cvtColor(cv.imread("maharo.jpg "),cv.COLOR_BGR2RGB)
h, w, c = src.shape #200, 200, 3
plt.subplot(111),plt.imshow(src)
plt.title('otter image'), plt.xticks([]), plt.yticks([])
plt.show()

g_src = cv.cuda_GpuMat()
g_dst = cv.cuda_GpuMat()
g_src.upload(src)

image.png Tout d'abord, définissez la matrice de conversion affine. En combinant la rotation autour du centre et le mouvement parallèle, l'axe central est tourné par la rotation de l'échelle.

def get_rot_affine(src, rot, scale):
    h, w = src.shape[::-1]
    rot_affine = cv.getRotationMatrix2D((h/2, w/2), rot, scale)
    rot_affine[:2,2] -= [h/2, w/2]
    rot_affine[:2,2] += [h/2*scale, w/2*scale]
    return rot_affine

1x rotation de 20 degrés

Pour la même rotation de 20 degrés de grossissement, définissez la matrice d'affiliation comme suit. À propos, CUDA ne prend pas en charge l'interpolation Lanczos.

rot_affine = get_rot_affine(src, 20, 1)

CPU Tout d'abord, essayez-le sur le processeur.

%%timeit
img_dst = cv.warpAffine(src, rot_affine, (w*1, h*1), flags=cv.INTER_CUBIC)
# 1.08 ms ± 7.24 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

image.png

CUDA Je voudrais découvrir le goût des matériaux GPU en les traitant uniquement, ce qui n'inclut pas la lecture / l'écriture d'informations dans la boucle. Comme d'habitude, cv2.cuda.wrapAffine est utilisé, mais les arguments ne sont que l'image source src et l'image de sortie dst sur le GPU, et la matrice d'affiliation et la taille de dst sont les mêmes que cv.wrapAffine normal Semble utiliser. (Je me fâche quand je le mets sur le GPU).

%%timeit
g_dst = cv.cuda.warpAffine(g_src, rot_affine, (w*1, h*1), flags=cv.INTER_CUBIC)
# 383 µs ± 28.6 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

Eh bien, c'est comme ça ... Après tout, si l'image est petite, elle ne semble être qu'environ 2 à 3 fois plus efficace.

%%timeit
g_src.upload(src)
g_dst = cv.cuda.warpAffine(g_src, rot_affine, (w*1, h*1), flags=cv.INTER_CUBIC)
gpu_dst = g_dst.download()
# 450 µs ± 5.11 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

image.png

Même si vous envisagez de lire / écrire, la vitesse ne change pas beaucoup. (Parce que l'image est claire)

Rotation 10 fois 20 degrés

Faites Mahalo 10 fois (2K) et faites-le pivoter de 20 degrés. La matrice affine est appelée comme suit.

rot_affine = get_rot_affine(src, 20, 10)

CPU Tout d'abord, essayez-le sur le processeur.

%%timeit
img_dst = cv.warpAffine(src, rot_affine, (w*10, h*10), flags=cv.INTER_CUBIC)
# 7.29 ms ± 36.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

C'est assez rapide pour un grossissement 10x. Cela dépend de l'environnement, la parallélisation ne fonctionnait pas bien lors du traitement d'images 200 px et le processeur fonctionnait avec 1 thread, mais lors du traitement d'images 2K, la parallélisation de 32 threads fonctionnait correctement. Cela dépend de la vitesse. (Si vous le faites avec un Core i5 / 7 normal, etc., ce sera plus lent. À propos, 2 * Xeon E5-2667 v3 @ 3,20 GHz dans l'environnement de vérification équivaut à environ 1 * Ryzen 9 3900XT selon Cinebench. C'est l'époque ...)

image.png

CUDA

%%timeit
g_dst = cv.cuda.warpAffine(g_src, rot_affine, (w*10, h*10), flags=cv.INTER_CUBIC)
# 1.42 ms ± 16.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Il est environ 5 fois plus rapide que le processeur. Eh bien, c'est assez facile à comprendre et rapide à moins que l'autre partie ne soit Xeon, mais il semble que GTX 1080 soit un peu mauvais.

%%timeit
g_src.upload(src)
g_dst = cv.cuda.warpAffine(g_src, rot_affine, (w*10, h*10), flags=cv.INTER_CUBIC)
gpu_dst = g_dst.download()
# 2.64 ms ± 163 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Lors de l'importation / exportation, cela prend un peu de temps car l'image est grande.

image.png

Le code utilisé cette fois (Jupyter Notebook) est publié sur Github.

référence

Comprendre complètement la conversion Affin

Recommended Posts

Transformation affine par OpenCV (CUDA)
Correspondance de modèle par OpenCV (CUDA)
Conversion d'affine
Application de la conversion affine par tenseur - de la détection de base à la détection d'objet -
[FSL] Conversion affine (mouvement parallèle + conversion linéaire)
[Python] Utilisation d'OpenCV avec Python (transformation d'image)
Pensez à la transformation Janken par l'optimisation
Accélérer la lecture en spécifiant une trame OpenCV
Traitement de lignes horizontales à l'aide de la transformation de morphologie OpenCV
Reconnaissance d'objets avec openCV par traincascade
Reconnaissez la carte Othello avec OpenCV