1
votes

Je souhaite définir une région d'intérêt dans une vidéo et ne traiter que cette zone

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


0 commentaires

3 Réponses :


1
votes

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)


4 commentaires

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.



0
votes

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)


0 commentaires

0
votes

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:

  • Évitez si possible d'utiliser des variables globales
  • Créez une fenêtre distincte pour la sélection du ROI et supprimez-la ensuite
  • Créez des fonctions distinctes pour chaque tâche individuelle

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


2 commentaires

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