Сохранение кадра видео перед текущим кадром?


В настоящее время у меня есть фрагмент кода, который отображает видео, и я пытаюсь расширить его, чтобы он показывал разницу между текущим и предыдущим кадром, чтобы он обнаруживал движение. Я знаю, что мне придется использовать функцию absdiff(), чтобы показать контраст между двумя изображениями, но я не уверен, как сохранить предыдущий кадр в виде Mat. Может кто-нибудь взглянуть на мой код ниже и показать мне, где я должен добавить этот код "предыдущего кадра", и что я должен написать. Я предполагаю, что этого не произойдет. это займет много времени, я просто не могу найти никаких учебников для этого в интернете...

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.highgui.VideoCapture;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

// ********************************************************

public class CaptureVideo {

public static void main(String[] args) throws InterruptedException {

    // load the Core OpenCV library by name

    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

    // create video capture device object

    VideoCapture cap = new VideoCapture();

    // try to use the hardware device if present

    int CAM_TO_USE = 0;

    // create a new image object

    Mat matFrame = new Mat();

    // try to open first capture device (0)

    try {
        cap.open(CAM_TO_USE);
    } catch (Exception e1) {
        System.out.println("No webcam attached");

        // otherwise try opening a video file 

        try{
            cap.open("files/video.mp4");
        } catch (Exception e2) {
            System.out.println("No video file found");
        }
    }

    // if the a video capture source is now open

    if (cap.isOpened())
    {

        // create a new window object

        Imshow ims = new Imshow("From video source ... ");

        boolean keepProcessing = true;

        while (keepProcessing)
        {   
            // grab the next frame from video source

            cap.grab();

            // decode and return the grabbed video frame

            cap.retrieve(matFrame);

            // if the frame is valid (not end of video for example)

            if (!(matFrame.empty()))
            {
                // *** to any processing here*** 

                // display image with a delay of 40ms (i.e. 1000 ms / 25 = 25 fps)

                ims.showImage(matFrame);
                Thread.sleep(40);
            } else { 
                keepProcessing = false;
            }
        }

    } else {
        System.out.println("error cannot open any capture source - exiting");

    }

    // close down the camera correctly

    cap.release();

  }
}

Я попытался добавить следующий код после любого из операторов else, но все, что получается, - это черный экран (который я предполагаю, потому что "previousFrame" - это просто дубликат "matFrame"):

            previousFrame = matFrame;

            Core.absdiff(matFrame, previousFrame, diffFrame);

            ims.showImage(diffFrame);
Может ли кто-нибудь указать мне, где я ошибаюсь?
1 3

1 ответ:

Делание previousFrame = matFrame; делает previousFrame укажите на matFrame. Вы не копируете матрицу - оба previousFrame и matFrame ссылаются на один и тот же объект. Таким образом, вы, по сути, вычитаете матрицу вместе с собой, поэтому вы получаете черную рамку.

Вам нужно сделать правильную копию, и поэтому вам нужно клонировать матрицу, используя Mat.clone(). Однако, если вы хотите найти разницу между двумя кадрами, имейте в виду, что мы должны прочитать в по крайней мере, два кадра для того, чтобы это произошло. Мы действительно не можем найти отличительный кадр, когда читаем только первый кадр видео, и поэтому мы должны проверить, является ли это первый кадр или нет. Если это первый кадр, просто отобразите нормальный кадр соответственно. После этого момента мы можем отобразить разностный кадр, убедившись, что мы копируем предыдущий кадр перед чтением в следующем кадре.

Таким образом, сделайте это для вашего цикла:

   // ****** Change - add a flag to check to see if the first frame has been read
   boolean firstFrame = true;

   // ****** Change - declare previous frame here
   Mat previousFrame;
   while (keepProcessing)
    {   
        // ****** Change - Save previous frame before getting next one
        // Only do this if the first frame has passed
        if (!firstFrame)
            previousFrame = matFrame.clone();

        // grab the next frame from video source
        cap.grab();

        // decode and return the grabbed video frame
        cap.retrieve(matFrame);

        // if the frame is valid (not end of video for example)
        if (!(matFrame.empty()))
        {
            // **** Change - If we are on the first frame, only show that and
            // set the flag to false
            if (firstFrame) {
                ims.showImage(matFrame);
                firstFrame = false;
            }
            // ***** Change - now show absolute difference after first frame
            else {                
                Core.absdiff(matFrame, previousFrame, diffFrame);
                ims.showImage(diffFrame);                 
            }

            // display image with a delay of 40ms (i.e. 1000 ms / 25 = 25 fps)                
            Thread.sleep(40);
        } else { 
            keepProcessing = false;
        }
    }