Я хотел бы определить область интереса в видео и обрабатывать только эту область - PullRequest
1 голос
/ 16 апреля 2019

У меня проблемы с пониманием областей интереса в opencv.У меня есть код, который выполняет простое вычитание фона из моего first_frame.Я также могу нарисовать прямоугольник с моей функцией mouse_draw_rect.

Теперь я хотел бы, чтобы вычитание фона происходило только внутри нарисованного мной прямоугольника, потому что я хотел бы ускорить обработку алгоритма.Я знаю, что должен установить какой-то регион интересов, но я пробовал все это вчера и сегодня, и ничто из того, что я пробовал из учебников, не сработало.Может ли кто-нибудь помочь мне в этом процессе, пожалуйста?

РЕДАКТИРОВАТЬ : попытка исправить код

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 ]

1 голос
/ 16 апреля 2019

Просто обрежьте область в прямоугольнике, который вы нарисовали.Вместо

difference = cv2.absdiff(first_frame, frame)

используйте

difference = cv2.absdiff(first_frame[y1:y2, x1:x2], frame[y1:y2, x1:x2])
0 голосов
/ 16 апреля 2019

Основная проблема связана с событием выбора ROI и тем, как оно вызывается в данный момент. Текущая реализация не является динамической, что означает, что мы не можем визуализировать, какой ROI мы пытаемся выбрать. Кроме того, мы начали обработку еще до выбора ROI.

Правильный способ выбора области интереса заключается в том, что после того, как мы захватили первый кадр, зарегистрируйте событие щелчка мыши и визуализируйте кадр бесконечно с помощью imshow и waitKey(n), пока не будет нажата какая-то конкретная клавиша. В качестве альтернативы, мы можем достичь того же эффекта без бесконечного цикла, используя waitKey(0) (не проверено).

На этом этапе мы должны нарисовать желаемый прямоугольник ROI. Ключевым фактором здесь является то, что выполнение должно быть остановлено либо с помощью бесконечного цикла, либо waitKey(0). Просто зарегистрировать событие недостаточно. После выбора ROI перейдите к оставшейся части кода.

Вот некоторые рекомендации:

  • Избегайте использования глобальных переменных, где это возможно
  • Создать отдельное окно для выбора ROI и затем отменить его
  • Создание отдельных функций для каждой отдельной задачи

Ниже приведен полный код, демонстрирующий правильное использование события щелчка мыши для выбора области интереса для обработки видео:

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

Pro Tip: Иногда, когда камера инициализируется, требуется некоторое время для прогрева в зависимости от окружающего освещения, присутствующего в комнате. Вы можете пропустить несколько начальных кадров, чтобы позволить камере перейти от фазы инициализации. Это можно сделать, определив функцию initialize_camera в приведенном выше коде следующим образом:

def initialize_camera(cap):
    for i in range(0,60): #Skip first 60 frames
        _, frame = cap.read()
    return frame
0 голосов
/ 16 апреля 2019

В каждом кадре вы можете создать подизображение, используя subimage = image[y1:y2,x1:x2] И затем использовать подизображение для обработки.

Быстрая и грязная реализация в вашем коде:

Заменить
elif event == cv2.EVENT_MOUSEMOVE:

с

elif event == cv2.EVENT_LBUTTONUP:

И добавить подизображение:

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