0

I tried using schedule. It works fine but the viewfinder of the webcam is stuck at the initial state so it produces only one image multiple times.

Any help?

import cv2
import time
import schedule

cam = cv2.VideoCapture(0)

cv2.namedWindow("Webcam")

img_counter = 0


def capture():

    global img_counter

    img_name = "opencv_frame_{}.png".format(img_counter)

    cv2.imwrite(img_name, frame)

    print("screenshot taken")

    img_counter += 1



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

    if not ret:
        print("failed to grab frame")
        break

    cv2.imshow("test", frame)

    k = cv2.waitKey(1)

    if k % 256 == 27:
        print("closing the app")
        break

    else:
        schedule.every(5).seconds.do(capture)
        while 1:
            schedule.run_pending()
            time.sleep(1)

cam.release()

cam.destroyAllWindows()
Pierre.Vriens
  • 2,117
  • 75
  • 29
  • 42
Shajahan A
  • 11
  • 3
  • As written, I think your code gets stuck in the `while 1` loop. So it should be calling `capture` every 5 seconds. However `capture` has no read statement. Read is only called once on the first loop of `while True`. To fix, you might want to move the `read` function to `capture`. – bfris Sep 01 '21 at 17:11

2 Answers2

0

You are suffering from buffering. OpenCV VideoCapture() reads a few frames into a buffer - I think it is 5 but have not checked for a while and it may differ between platforms or versions.

There are a few possible work-arounds depending on your situation:

  • call read() 4-5 times when you want a frame - it will only take a couple of hundred milliseconds
  • call grab() either repeatedly in another thread or just before you want a frame
  • reduce the size of the buffer so it can only hold a single frame.

Sorry for the somewhat woolly answer as I am not set up to test more at the moment.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • 1
    Might not be this - OP is only reading from the camera once and reusing the result in the capture function... – AKX Aug 30 '21 at 09:16
  • @AKX You're probably right, I'm not sure what OP is really trying to achieve, so I'll leave it for a bit as a possible idea to consider and delete it if we work it out a better solution. Thanks for flagging it up. – Mark Setchell Aug 30 '21 at 09:51
0

I think your code could be simplified to something like this while still retaining a near-realtime preview of the periodically saved images.

import cv2
import schedule

cam = cv2.VideoCapture(0)
cv2.namedWindow("Webcam")
img_counter = 0


def capture():
    global img_counter
    img_name = "opencv_frame_{}.png".format(img_counter)
    cv2.imwrite(img_name, frame)
    print("screenshot taken")
    img_counter += 1


# Set up schedule before loop

schedule.every(5).seconds.do(capture)


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

    if not ret:
        print("failed to grab frame")
        break

    cv2.imshow("test", frame)
    schedule.run_pending()

    k = cv2.waitKey(100)  # 1/10 sec delay; no need for separate sleep

    if k % 256 == 27:
        print("closing the app")
        break

cam.release()
cam.destroyAllWindows()
AKX
  • 152,115
  • 15
  • 115
  • 172