[PYTHON] Correspondance de modèle par OpenCV (CUDA)

Motivation

--J'ai installé CUDA activé OpenCV (Python), mais je n'ai pas trouvé la documentation (japonais / anglais) et l'exemple de code, donc je l'ai écrit en référence à la version c ++. --CUDA Vive voulait essayer ――Je voulais écrire un article sur Qiita

Résumé

--OpenCV compatible CUDA installé sur Ubuntu

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

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

src = cv.imread("maharo.jpg ", cv.IMREAD_GRAYSCALE)
h, w = src.shape[::-1] # w=200, h=200

plt.subplot(111),plt.imshow(src,cmap = 'gray')
plt.title('otter image'), plt.xticks([]), plt.yticks([])
plt.show()

image.png

Ensuite, définissez les variables autour du GPU. Vous pouvez vérifier si le GPU est activé en vérifiant si «cv2.cuda.getCudaEnabledDeviceCount ()» renvoie un nombre supérieur ou égal à 1. Fondamentalement, OpenCV compatible CUDA peut être utilisé en réécrivant «cv2.function» en «cv2.cuda.function». (Il y a quelques exceptions, comme ce modèle de correspondance. Voir dir (cv2.cuda) pour plus de détails) De plus, la mémoire des variables et du GPU est sécurisée par cv2.cuda_GpuMat (), et les informations sont échangées entre les mémoires par .upload () /. Download ().

print(cv.cuda.getCudaEnabledDeviceCount())
g_src = cv.cuda_GpuMat()
g_dst = cv.cuda_GpuMat()
g_src.upload(src)

Pour le moment, j'ai déplacé l'image de Mahalo vers le GPU. Resize Expérimentons le goût du matériel GPU avec juste Resize (512-> 2K) qui n'inclut pas les informations de lecture / écriture dans la boucle. À propos, CUDA ne prend pas en charge l'interpolation Lanczos. (Il y a quelque chose comme ça dans l'ensemble) CPU

%%timeit
cpu_dst = cv.resize(src, (h*10, w*10), interpolation=cv.INTER_CUBIC)
# 777 µs ± 8.06 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

CUDA

%%timeit
g_dst = cv.cuda.resize(g_src, (h*4, w*4), interpolation=cv.INTER_CUBIC)
# 611 µs ± 6.34 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

__ Le goût du matériau est lent __ Cela a entraîné certains avantages non liés au GPU. À propos, la vitesse d'exécution compte tenu de la lecture et de l'écriture à partir du processeur est plus lente.

%%timeit
g_src.upload(src)
g_dst = cv.cuda.resize(g_src, (h*4, w*4), interpolation=cv.INTER_CUBIC)
gpu_dst = g_dst.download()
# 1.51 ms ± 16.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Même si j'ai eu du mal à intégrer CUDA, je n'aime pas ça. Eh bien, ça ne ressemble pas à ça en parallèle, est-ce difficile? Il semble que la lecture et l'écriture prennent environ 800 μs. De quoi cela dépend-il? Je pense que PCIe 3.0 sera le goulot d'étranglement (aucune base)

Template Matching Jetons un second regard et faisons la correspondance de modèles qui semble être utile en parallèle.

ex_src = cv.resize(src, (h*10, w*10), interpolation=cv.INTER_CUBIC)
tmpl = ex_src[1000:1200, 1000:1200]
th, tw = tmpl.shape[::-1]

CPU

%%timeit
result = cv.matchTemplate(ex_src, tmpl, cv.TM_CCOEFF_NORMED)
# 138 ms ± 5.03 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Ce n'est pas plus lent que prévu ... (Ajout: probablement parce que le processus s'exécute sur 32 threads.)

result = cv.matchTemplate(ex_src, tmpl, cv.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
top_left = max_loc
bottom_right = (top_left[0] + th, top_left[1] + tw)
cv.rectangle(ex_src,top_left, bottom_right, 255, 2)
plt.subplot(121),plt.imshow(result,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(ex_src,cmap = 'gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.show()

image.png CUDA La version CUDA du template maching est un peu spéciale (pour Python), mais elle est définie comme createTemplateMatching (precision, METHOD).

gsrc = cv.cuda_GpuMat()
gtmpl = cv.cuda_GpuMat()
gresult = cv.cuda_GpuMat()
gsrc.upload(ex_src)
gtmpl.upload(tmpl)
matcher = cv.cuda.createTemplateMatching(cv.CV_8UC1, cv.TM_CCOEFF_NORMED)
%%timeit
gresult = matcher.match(gsrc, gtmpl)
# 10.5 ms ± 406 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

__ Le matériau a bon goût __ CPU: Par rapport à 138 ms, CUDA a atteint une vitesse de 10,5 ms, soit environ 10 fois plus rapide.

%%timeit
gsrc.upload(ex_src)
gtmpl.upload(tmpl)
matcher = cv.cuda.createTemplateMatching(cv.CV_8UC1, cv.TM_CCOEFF_NORMED)
gresult = matcher.match(gsrc, gtmpl)
resultg = gresult.download()
# 16.6 ms ± 197 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Même si vous calculez la lecture / écriture, c'est toujours environ 8 fois plus rapide. C'est le cas de la GTX 1080, donc avec le GPU de génération Ampère récemment évoqué, encore plus rapide ...? J'ai seulement besoin de max_locg, mais y a-t-il un moyen de récupérer max_locg au stade gresult?

gresult = matcher.match(gsrc, gtmpl)
resultg = gresult.download()
min_valg, max_valg, min_locg, max_locg = cv.minMaxLoc(resultg)
top_leftg = max_locg
bottom_rightg = (top_leftg[0] + tw, top_leftg[1] + th)
cv.rectangle(src,top_leftg, bottom_rightg, 255, 2)
plt.subplot(121),plt.imshow(resultg,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(ex_src,cmap = 'gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.show()

image.png

print(max_loc,max_locg)
# (1000, 1000) (1000, 1000)

Le même résultat est obtenu.

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

référence

Code de test Construire OpenCV avec CUDA activé sur Ubuntu

Recommended Posts

Correspondance de modèle par OpenCV (CUDA)
Transformation affine par OpenCV (CUDA)
07. Génération de déclaration par modèle
Extraction d'objets dans l'image par correspondance de modèles en utilisant OpenCV avec Python
Accélérer la lecture en spécifiant une trame OpenCV
Notation de correspondance de modèle par convolution
Reconnaissance d'objets avec openCV par traincascade
Reconnaissez la carte Othello avec OpenCV