J'ai des problèmes pour comprendre les régions d'intérêt dans opencv. J'ai du code qui fait une simple soustraction d'arrière-plan de mon first_frame . Je suis également capable de dessiner un rectangle avec ma fonction mouse_draw_rect .
Maintenant, je voudrais que la soustraction d'arrière-plan se produise uniquement à l'intérieur du rectangle que je dessine parce que je voudrais accélérer le traitement de l'algorithme. Je sais que je dois définir une sorte de région d'intérêt, mais j'ai tout essayé hier et aujourd'hui et rien de ce que j'ai essayé des tutoriels n'a fonctionné. Quelqu'un peut-il m'aider à traverser ce processus s'il vous plaît?
EDIT : tentative de correction du code
import numpy as np
import cv2
import matplotlib.pyplot as plt
cap = cv2.VideoCapture(0)
_, first_frame = cap.read()
def mouse_draw_rect(event, x, y, flags, params):
global point1, point2, drawing, first_frame, x1, x2, y1, y2
if event == cv2.EVENT_LBUTTONDOWN:
if drawing is False:
drawing = True
point1 = (x, y)
x1 = (x)
y1 = (y)
else:
drawing = False
elif event == cv2.EVENT_MOUSEMOVE:
if drawing is True:
point2 = (x, y)
x2 = (x)
y2 = (y)
elif event == cv2.EVENT_MBUTTONDOWN:
first_frame = frame
drawing = False
point1 = ()
point2 = ()
x1 = ()
x2 = ()
y1 = ()
y2 = ()
cv2.namedWindow('Original')
cv2.setMouseCallback("Original", mouse_draw_rect)
while True:
ret, frame = cap.read( )
if point1 and point2:
cv2.rectangle(frame, point1, point2, (0, 0, 0),5)
difference = cv2.absdiff(first_frame[y1:y2, x1:x2], frame[y1:y2, x1:x2])
difference = cv2.GaussianBlur(difference, (3, 3), 0)
_, difference = cv2.threshold(difference, 18, 255, cv2.THRESH_BINARY)
cv2.imshow('first frame (1)', first_frame)
cv2.imshow('Original', frame)
cv2.imshow('difference', difference)
key = cv2.waitKey(30) & 0xff
if key == 27:
break
cap.release()
cv2.destroyAllWindows()
3 Réponses :
Recadrez simplement la zone du rectangle que vous avez dessiné. Au lieu de
difference = cv2.absdiff(first_frame[y1:y2, x1:x2], frame[y1:y2, x1:x2])
utiliser
difference = cv2.absdiff(first_frame, frame)
Je fais probablement une erreur majeure, mais j'ai essayé d'appliquer ce que vous avez suggéré et cela revient avec une erreur selon laquelle y1 n'est pas défini. J'ai changé le code dans mon texte principal pour que vous puissiez voir ce que j'ai ajouté.
(x1, y1) et (x2, y2) sont vos point1 et point2. N'utilisez pas de x et de y, utilisez vos noms
Alors je tire les valeurs comme ça? difference = cv2.absdiff (first_frame [point1 [1]: point2 [1], point1 [0]: point2 [0]], frame [point1 [1]: point2 [1], point1 [0]: point2 [0 ]])
Malheureusement, lorsque je l'ajoute à ma fonction, il ne s'applique toujours pas au rectangle. Je vais probablement faire une pause et essayer de m'attaquer demain, merci pour votre temps.
Sur chaque image, vous pouvez créer une sous-image en utilisant subimage = image [y1: y2, x1: x2] Et puis utiliser la sous-image pour le traitement.
Une implémentation rapide et sale dans votre code :
Remplacer
elif event == cv2.EVENT_MOUSEMOVE:
avec
elif event == cv2.EVENT_LBUTTONUP:
Et ajoutez la sous-image:
if point1 and point2:
cv2.rectangle(frame, point1, point2, (0, 0, 0),5)
subimg = frame[point1[1]:point2[1],point1[0]:point2[0]]
cv2.imshow("Subimage",subimg)
Le principal problème vient de l'événement de sélection du ROI et de la manière dont il est appelé actuellement. La mise en œuvre actuelle n'est pas dynamique, ce qui signifie que nous ne pouvons pas visualiser le retour sur investissement que nous essayons de sélectionner. De plus, nous avons commencé le traitement avant même de sélectionner le retour sur investissement.
La bonne façon de sélectionner le retour sur investissement est qu'une fois que nous avons capturé la première image, enregistrez l'événement de clic de souris et visualisez l'image indéfiniment avec imshow et waitKey (n) code > jusqu'à ce qu'une touche spécifique soit enfoncée. Alternativement, nous pouvons être en mesure d'obtenir le même effet sans la boucle infinie en utilisant waitKey (0) (Non testé).
À ce stade, nous devrions être en mesure de dessiner le rectangle de retour sur investissement souhaité. Le facteur clé ici est que l'exécution doit être arrêtée soit en utilisant une boucle infinie ou waitKey (0) . Il ne suffit pas d'enregistrer l'événement. Une fois la sélection du retour sur investissement effectuée, continuez avec le reste du code.
Voici quelques recommandations:
Voici le code complet démontrant l'utilisation correcte de l'événement de clic de souris pour sélectionner le retour sur investissement pour le traitement vidéo:
def initialize_camera(cap):
for i in range(0,60): #Skip first 60 frames
_, frame = cap.read()
return frame
Conseil de pro: fort>
Parfois, lorsqu'une caméra est initialisée, il faut un certain temps pour se réchauffer en fonction de la lumière ambiante présente dans la pièce. Vous pouvez envisager de sauter quelques images initiales pour laisser la caméra se stabiliser à partir de la phase d'initialisation. Cela peut être fait en définissant la fonction initialize_camera dans le code ci-dessus comme suit:
import numpy as np
import cv2
import matplotlib.pyplot as plt
ORIGINAL_WINDOW_TITLE = 'Original'
FIRST_FRAME_WINDOW_TITLE = 'First Frame'
DIFFERENCE_WINDOW_TITLE = 'Difference'
canvas = None
drawing = False # true if mouse is pressed
#Retrieve first frame
def initialize_camera(cap):
_, frame = cap.read()
return frame
# mouse callback function
def mouse_draw_rect(event,x,y,flags, params):
global drawing, canvas
if drawing:
canvas = params[0].copy()
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
params.append((x,y)) #Save first point
elif event == cv2.EVENT_MOUSEMOVE:
if drawing:
cv2.rectangle(canvas, params[1],(x,y),(0,255,0),2)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
params.append((x,y)) #Save second point
cv2.rectangle(canvas,params[1],params[2],(0,255,0),2)
def select_roi(frame):
global canvas
canvas = frame.copy()
params = [frame]
ROI_SELECTION_WINDOW = 'Select ROI'
cv2.namedWindow(ROI_SELECTION_WINDOW)
cv2.setMouseCallback(ROI_SELECTION_WINDOW, mouse_draw_rect, params)
roi_selected = False
while True:
cv2.imshow(ROI_SELECTION_WINDOW, canvas)
key = cv2.waitKey(10)
#Press Enter to break the loop
if key == 13:
break;
cv2.destroyWindow(ROI_SELECTION_WINDOW)
roi_selected = (3 == len(params))
if roi_selected:
p1 = params[1]
p2 = params[2]
if (p1[0] == p2[0]) and (p1[1] == p2[1]):
roi_selected = False
#Use whole frame if ROI has not been selected
if not roi_selected:
print('ROI Not Selected. Using Full Frame')
p1 = (0,0)
p2 = (frame.shape[1] - 1, frame.shape[0] -1)
return roi_selected, p1, p2
if __name__ == '__main__':
cap = cv2.VideoCapture(0)
#Grab first frame
first_frame = initialize_camera(cap)
#Select ROI for processing. Hit Enter after drawing the rectangle to finalize selection
roi_selected, point1, point2 = select_roi(first_frame)
#Grab ROI of first frame
first_frame_roi = first_frame[point1[1]:point2[1], point1[0]:point2[0], :]
#An empty image of full size just for visualization of difference
difference_image_canvas = np.zeros_like(first_frame)
while cap.isOpened():
ret, frame = cap.read()
if ret:
#ROI of current frame
roi = frame[point1[1]:point2[1], point1[0]:point2[0], :]
difference = cv2.absdiff(first_frame_roi, roi)
difference = cv2.GaussianBlur(difference, (3, 3), 0)
_, difference = cv2.threshold(difference, 18, 255, cv2.THRESH_BINARY)
#Overlay computed difference image onto the whole image for visualization
difference_image_canvas[point1[1]:point2[1], point1[0]:point2[0], :] = difference.copy()
cv2.imshow(FIRST_FRAME_WINDOW_TITLE, first_frame)
cv2.imshow(ORIGINAL_WINDOW_TITLE, frame)
cv2.imshow(DIFFERENCE_WINDOW_TITLE, difference_image_canvas)
key = cv2.waitKey(30) & 0xff
if key == 27:
break
else:
break
cap.release()
cv2.destroyAllWindows()
C'était une explication incroyable, merci. Je vais parcourir votre code et en apprendre autant que je peux.
@sentientnativeplant ... Génial. Vous pouvez envisager d'accepter la réponse si elle résout votre problème afin que ce message puisse sortir de la liste des questions sans réponse et aider les lecteurs qui rencontrent le même problème. :)