web-dev-qa-db-fra.com

Obtenez la couleur moyenne dans un contour avec CV ouvert

J'ai donc décidé de commencer à apprendre le CV ouvert et Python ensemble!

Mon premier projet consiste à détecter des objets en mouvement sur un arrière-plan relativement fixe, puis à détecter leur couleur moyenne pour les trier. Il y a au moins 10 objets pour détecter et je traite une vidéo colorée.

Jusqu'à présent, j'ai réussi à retirer l'arrière-plan, identifier les contours (éventuellement obtenir le centre de chaque contour), mais maintenant, je me débats pour obtenir la couleur moyenne ou moyenne à l'intérieur de chaque contour. Il y a quelques sujets sur ce type de question, mais la plupart d'entre eux sont écrits dans C. apparemment, je pourrais utiliser cv.mean() mais je ne peux pas obtenir de masque de travail pour nourrir cette fonction. Je suppose que ce n'est pas si difficile mais je suis coincé là-bas ... acclamations!

import numpy as np
import cv2

video_path = 'test.h264'

cap = cv2.VideoCapture(video_path)
fgbg = cv2.createBackgroundSubtractorMOG2()


while (cap.isOpened):

    ret, frame = cap.read()
    if ret==True:
        fgmask = fgbg.apply(frame)
        (contours, hierarchy) = cv2.findContours(fgmask, cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)

        for c in contours:
            if cv2.contourArea(c) > 2000:
                cv2.drawContours(frame, c, -1, (255,0,0), 3)
        cv2.imshow('foreground and background',fgmask)
        cv2.imshow('rgb',frame)

    key = cv2.waitKey(1) & 0xFF

    if key == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()
6
fab

Solution sur une image

1) Trouver le contour (dans ce cas, le rectangle, le contour qui n'est pas un rectangle est beaucoup plus difficile à faire)

2) Trouvez les coordonnées du contour

3) couper l'image du contour

4) somme des canaux individuels et divisez-les par nombre de pixels dedans (ou avec une fonction moyenne)

import numpy as np
import cv2
img = cv2.imread('my_image.jpg',1)
cp = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(cp,150,255,0)
cv2.imshow('img',thresh) 
cv2.waitKey(0)
im2,contours,hierarchy = cv2.findContours(thresh.astype(np.uint8), 1, 2)
cnts = contours
for cnt in cnts:
    if cv2.contourArea(cnt) >800: # filter small contours
        x,y,w,h = cv2.boundingRect(cnt) # offsets - with this you get 'mask'
        cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
        cv2.imshow('cutted contour',img[y:y+h,x:x+w])
        print('Average color (BGR): ',np.array(cv2.mean(img[y:y+h,x:x+w])).astype(np.uint8))
        cv2.waitKey(0)
cv2.imshow('img',img) 
cv2.waitKey(0)
cv2.destroyAllWindows()

Pour supprimer le bruit, vous pouvez simplement prendre le centre du contour et prendre un rectangle plus petit à examiner.

Pour contour non rectangulaire, consultez la fonction CV2.filloly -> Contour des contours non rectangulaires . mais son algorithme lent un peu lent (mais rien de limitation)

Si vous êtes intéressé par un contour non rectangulaire, vous devrez faire attention à faire la moyenne, car vous aurez besoin de masque et que le masque/l'arrière-plan est toujours rectangulaire, vous ferez donc une méchante sur quelque chose que vous ne voulez pas

1
Martin