2

I have working code for applying background subtraction on a still video but it won't properly write the frames of subtracted background to its output file. I get the .avi file & filename which I specified in cv2.VideoWriter, but it doesn't seem to write each frame that I pass:

import cv2
import numpy as np
cap = cv2.VideoCapture('traffic-mini.mp4')
fgbg = cv2.createBackgroundSubtractorMOG2()
cv2.startWindowThread()

fourcc = cv2.VideoWriter_fourcc('M','J','P','G')
out = cv2.VideoWriter('test_output.avi',fourcc, 20.0, (640,480))

while True:
    ret, frame = cap.read()
    if ret == True:
        frame = fgbg.apply(frame)
        out.write(frame)
        cv2.imshow('fg',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break



cap.release()
out.release()
cv2.destroyAllWindows()
for i in range (1,5):
    cv2.waitKey(1)

The output video test_output.avi is always 6KB and has no frames passed in. What am I missing? Thanks in advance

Atenean1
  • 82
  • 11
  • try changing fourcc = `cv2.VideoWriter_fourcc('M','J','P','G')` to `fourcc = cv2.VideoWriter_fourcc(*'XVID')`, because maybe your system does not have the codec for MJPG – krxat Aug 22 '19 at 08:27

3 Answers3

1

Try this:

#Add a 0 to the end of the out after (640, 480)
out = cv2.VideoWriter('test_output.avi',fourcc, 20.0, (640,480),0)

while True:
   ret, frame = cap.read()

   if ret == True:
      frame = cv2.resize(frame, (640,480))
      frame = fgbg.apply(frame)
      out.write(frame)
      cv2.imshow('fg',frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    else:
       break

The reason why is to write out black and white frames you need the 0 at the end to tell opencv that there is no channel involved.
You may have to switch the two number for the resize around as I can remember off hand which is width or height of the frame, but the point is the video frame size should match for both your output and your input. Also a hint for background subtraction is to gray the video out as well like

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
MNM
  • 2,673
  • 6
  • 38
  • 73
0

It's because the size of frame is not (640,480). Instead of

out = cv2.VideoWriter('test_output.avi',fourcc, 20.0, (640,480))

try

out = cv2.VideoWriter('test_output.avi',fourcc, 20.0, (int(cap.get(3)), int(cap.get(4))))

Ha Bom
  • 2,787
  • 3
  • 15
  • 29
  • Thank you for the answer, but I'm afraid the same problem persists. What does that last parameter do? Should I pass in something else? – Atenean1 Nov 30 '18 at 09:43
  • The last parameter is the shape (width, height) of frames you want to save. `int(cap.get(3))` is the width and `int(cap.get(4))` is the height of the frames you read from the video. – Ha Bom Dec 01 '18 at 01:07
0

MNM's proposed solution - adding 0 as a last parameter of VideoWriter - works well on my end - using OpenCV 3.4.5 on Raspbian Stretch (Raspberry Pi 3).

Although the official documentation https://docs.opencv.org/3.4.5/dd/d9e/classcv_1_1VideoWriter.html - states that "isColor If it is not zero, the encoder will expect and encode color frames, otherwise it will work with grayscale frames (the flag is currently supported on Windows only)." It may be applicable to other OSes.