En python, notamment avec le support d'OpenCV, j'ai essayé de reconnaître un objet rouge à partir de l'image de la caméra vidéo, j'ai donc fait un article.
En raison de l'utilisation d'OpenCV, il est possible d'utiliser C / C ++ au lieu de python, mais si vous le faites avec python, vous pouvez l'écrire avec une quantité de travail étonnamment faible, c'est incroyable.
J'ai donc essayé d'écrire un article w
Le terme algorithme est cool à utiliser, mais ce n'est pas si noble. Je voudrais aborder le mécanisme de détection des objets rouges.
Je pense qu'il existe une méthode standard pour exprimer les couleurs RVB. En exprimant la luminosité de chacun des R, V et B de 0 à 255, il devient une couleur 24 bits. Alors, ce RVB peut-il être utilisé pour déterminer le rouge? C'est en fait assez difficile. Par exemple, R = 255, G = 0, B = 0 sera rouge, peu importe qui dit quoi. Mais qu'en est-il de R = 10, G = 0, B = 0? N'est-ce pas noir plutôt que rouge? Je me sens comme ça. En d'autres termes, il est difficile de juger de la teinte avec RVB.
Par conséquent, nous utilisons une structure de données appelée espace colorimétrique HSV. \ (Pour plus de détails, accédez à [Wikipedia](https://ja.wikipedia.org/wiki/HSV color space) )
Maintenant, créons une fonction et convertissons-la en espace colorimétrique HSV. L'importation d'OpenCV et de numpy est une norme.
import cv2
import numpy as np
def find_rect_of_target_color(image):
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV_FULL)
h = hsv[:, :, 0]
s = hsv[:, :, 1]
Jusqu'à ce point, les composantes H et S de l'image ont été extraites. Le composant H est Hue (teinte). En fait, il tourne comme un cercle en 360 pas: rouge → vert → bleu → rouge. Comme je l'ai écrit au début, il est difficile de juger de la teinte avec RVB, mais une fois converti en HSV, il devient très facile de juger par teinte en regardant H.
Dans le cas d'OpenCV, H, S et V sont tous tenus en 256 étapes (lorsque COLOR_BGR2HSV_FULL
est spécifié), donc le H d'origine devrait être de 360 pas, mais il est arrondi à 256 étapes. Prenez ce côté en compte et continuez.
En parlant de rouge dans la teinte (teinte), il est d'environ 280 à 28 ° y compris la gamme violacée. Si vous recalculez cela en 256 étapes, je pense que ce sera environ 200 à 20. Par conséquent, la plage où la valeur de H est (H <20 | H> 200) est rouge.
Faites également attention à la profondeur des couleurs. Même si la teinte (teinte) est rouge, si la couleur est suffisamment claire, elle s'approchera du blanc ou du noir. Il est nécessaire de juger en même temps la composante S et la saturation. Il est généralement compris entre 0 et 255, et plus le nombre est grand, plus il est "vif". Ici, puisqu'il s'agit d'un jugement rouge, ajoutons-le à la condition que la valeur de S soit (S> 128).
Si vous les écrivez ensemble de manière numpy, cela ressemblera à ce qui suit.
mask = np.zeros(h.shape, dtype=np.uint8)
mask[((h < 20) | (h > 200)) & (s > 128)] = 255
Vous avez maintenant les données de masque qui montrent la partie rouge. (255 pour le rouge, 0 pour le non-rouge) Mais ce n'est pas la fin. Ces données de masque ne montrent que "où les points sont rougeâtres" dans l'image.
Après tout, tant qu'il détecte un objet rouge, je veux reconnaître un bloc de points d'une certaine taille. Dans l'état actuel des choses, ce n'est qu'un groupe de points, et il n'y a pas d'unité. Afin de reconnaître ces données, qui ne sont qu'un point, comme un bloc, considérons d'abord ce qu'on appelle un "contour". Une fois que vous avez un contour, vous connaissez la masse entourée par ce contour.
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
La combinaison d'OpenCV et de python est excellente.
Vous pouvez l'écrire en une seule ligne.
Regardons maintenant le contenu de contours
. En fait, lors du processus de création du contour, il a déjà été disposé en morceaux.
rects = []
for contour in contours:
approx = cv2.convexHull(contour)
rect = cv2.boundingRect(approx)
rects.append(rect)
J'écrirai à nouveau la même chose, mais la combinaison d'OpenCV et de python est excellente. C'est vraiment concis.
cv2.convexHull ()
est une fonction qui calcule une forme convexe contenant une masse inégale. Le contour
contient des informations de point qui forment le contour, mais comme il ne s'agit que d'un contour, il a une forme très compliquée, comme une côte de rias. C'est cv2.convexHull ()
qui transforme cela en un polygone 2D qui ressemble à un sac qui s'enroule. La valeur de retour ʻapproxest un tableau de (X, Y). Ensuite,
cv2.boundingRect ()` calcule le rectangle dans lequel s'inscrit le polygone en forme de sac. Il renvoie des informations rectangulaires de la forme (x, y, largeur, hauteur).
Jusqu'à ce point, les informations sur le groupe de points ont été collectées dans une liste de rectangles pour chaque bloc.
Maintenant, connectons ce que j'ai écrit séparément dans l'ordre.
import cv2
import numpy as np
def find_rect_of_target_color(image):
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV_FULL)
h = hsv[:, :, 0]
s = hsv[:, :, 1]
mask = np.zeros(h.shape, dtype=np.uint8)
mask[((h < 20) | (h > 200)) & (s > 128)] = 255
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
rects = []
for contour in contours:
approx = cv2.convexHull(contour)
rect = cv2.boundingRect(approx)
rects.append(np.array(rect))
return rects
Seulement ça. Avec juste cela, nous avons une fonction qui renvoie un tableau de rectangles qui identifient les points rouges dans l'image donnée.
Après l'avoir fait jusqu'à présent, je voudrais confirmer son fonctionnement. Traitons en temps réel avec l'image de la caméra vidéo.
if __name__ == "__main__":
capture = cv2.VideoCapture()
while cv2.waitKey(30) < 0:
_, frame = capture.read()
rects = find_rect_of_target_color(frame)
for rect in rects:
cv2.rectangle(frame, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), (0, 0, 255), thickness=2)
cv2.imshow('red', frame)
capture.release()
cv2.destroyAllWindows()
comment c'est? Avez-vous obtenu les résultats escomptés? C'est mon attente, mais je pense que c'était un mauvais résultat. C'est parce que les grands et petits rectangles sont reconnus comme des «objets rouges». Il est absurde de penser à quelque chose comme le bruit comme un «objet». Éclaircissons-le parce que c'est une certaine taille.
Ici, une petite recommandation est de ne faire que du plus grand rectangle un "objet rouge". Pour détecter un objet rouge, avez-vous tenu l'objet rouge à portée de main devant la caméra? En d'autres termes, je voulais le détecter. Souvent, ce que vous voulez détecter est la plus grosse copie.
Modifiez ce qui suit afin que celui qui possède la plus grande surface soit recherché dans la liste rectangulaire obtenue.
if __name__ == "__main__":
capture = cv2.VideoCapture()
while cv2.waitKey(30) < 0:
_, frame = capture.read()
rects = find_rect_of_target_color(frame)
if len(rects) > 0:
rect = max(rects, key=(lambda x: x[2] * x[3]))
cv2.rectangle(frame, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), (0, 0, 255), thickness=2)
cv2.imshow('red', frame)
capture.release()
cv2.destroyAllWindows()
Alors c'est tout pour cette fois. Je suis impressionné par le fait que la combinaison de python + OpenCV est très pratique.
Recommended Posts