VideoCapture.read() returns past image

2019-09-01 18:45发布

问题:

I'm running python3.6 with openCV on the Raspberry pi(OS is Raspbian)

The approximate structure of the code is as follows.

  1. The image is captured at time interval(3~5 min).

  2. Captured image is processed in functions and returns measure(kind of accuracy)

  3. Iterate 1.~2. until end_check() returns True

Problem is that the most recent taken image is out of date. It looks it was taken almost 10 minutes ago. All images recently taken are late. But the images taken at the beginning seem to be timed. And the time recorded in all .jpg files entered correctly +It looks this problem is occured after more than a hour. (20~22 iterates)

Images are captured with cam0.read() in the cv2 package. Below is main part of the code. It is quite long to upload full code. It someone request, I will update.

def run(interval,model_list):
    cam0 = cv2.VideoCapture(0)  #Only cam0 is used. cam2 is just to record.
    camdir = "/home/pi/capstone/cam0/"
    cam2 = cv2.VideoCapture(1)
    cam2dir = "/home/pi/capstone/cam2/"
    runNo = 0
    acc_list = list()
    error_list = list()
    end = False
    while(end == False):
        print(runNo,"th run")

        img_name = "%s.jpg" %runNo
        frame, res = cam0.read()   #`res` is the image which will be processed
        cv2.imwrite(os.path.join(camdir,img_name),res)
        _ , cam2pic = cam2.read()
        cv2.imwrite(os.path.join(cam2dir,img_name),cam2pic)
        try:
            temp = Real(res)
            mat = temp.match(model_list)
            acc_list.append([mat,runNo])
            print("Accuracy=", mat)
        except ValueError:
            acc_list.append(["ValueError",runNo])
            error_list.append(["ValueError",runNo])
        except AttributeError:
            acc_list.append(["AttributeError", runNo])
            error_list.append(["AttributeError",runNo])
        except SmallObjectError:
            acc_list.append(["SmallObjectError", runNo])
            error_list.append(["SmallObjectError",runNo])
        runNo = runNo+1
        endNo = 40
        if(runNo/2 > endNo):
            end_check(res, end)
        elif(runNo > endNo):
            end = True
        sleep(interval*60)

    with open("acc_list.txt", "w") as output: #records for tracking errors
        output.write(str(acc_list))
    with open("err_list.txt", "w") as output:
        output.write(str(error_list))
    cam0.release()
    cam2.release()

run(3.5,model_list)

(+) Some newly found things and guess

  • The images time gap is getting bigger with code running
  • Code finally showed OpenCV Error
  • It looks kind of Video signal is stored in RAM on R-pi and .read() returning out-dated image in RAM
  • Stored Video signal in RAM araise resource problem

Below is the OpenCV Error

OpenCV Error: Assertion failed (dsize.area() > 0 || (inv_scale_x > 0 && inv_scale_y > 0)) in resize, file /home/pi/opencv/opencv-3.4.0/modules/imgproc/src/resize.cpp, line 4045
Traceback (most recent call last):
  File "runpi.py", line 264, in <module>
    run(3.5,model_list)
  File "runpi.py", line 234, in run
    mat = temp.match(model_list)
  File "runpi.py", line 184, in match
    self.__resize(model.get_m_inform())
  File "runpi.py", line 147, in __resize
    self.mask = cv2.resize(self.mask, None, fx=reratio, fy=reratio, interpolation = inter_method)
cv2.error: /home/pi/opencv/opencv-3.4.0/modules/imgproc/src/resize.cpp:4045: error: (-215) dsize.area() > 0 || (inv_scale_x > 0 && inv_scale_y > 0) in function resize

(+) Some part of code araising Error

This is __.resize() method. When I process the image that occured OpenCV Error manually, it works well even if OpenCV Error pointing out kind of image size matter. So I thought it is not matter of image itself or size got from md_inf(). Anyway Here is code.

def __resize(self, md_inf):       
    #md_inf = [219, 122, 132, 171, 262] <-sample
    reratio = md_inf[0]/self.y
    if(reratio>1):
        inter_method = cv2.INTER_LINEAR
    else:
        inter_method = cv2.INTER_AREA

    ###below is line 147###
    self.mask = cv2.resize(self.mask, None, fx=reratio, fy=reratio, interpolation = inter_method)
    temp = np.zeros((md_inf[3], md_inf[4]), np.uint8)
    m_cx, m_cy = md_inf[1:3]

    _, contour, _ = cv2.findContours(self.mask, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

    total_contour = contour[0]
    for ctr in contour[1:]:
        total_contour = np.concatenate((total_contour, ctr), axis =0)
    mmt = cv2.moments(total_contour)
    if(mmt['m00'] < 7500):
        raise SmallObjectError

    self.cy = int(mmt['m10']/mmt['m00']) #y is horrizon axis
    self.cx = int(mmt['m01']/mmt['m00']) #x is vertical axis

    x, y = self.mask.shape

    adjust = m_cx - self.cx + x - temp.shape[0]
    if(adjust > 0):
        m_cx = m_cx - adjust

    temp[(m_cx-self.cx):(m_cx-self.cx) +x, (m_cy-self.cy):(m_cy-self.cy) +y] = self.mask

    self.mask = temp

回答1:

I agree with Mark Serchell's comment. The way I am using is to set variable to time + x seconds and check. OpenCV have useful feature for skiping frames like cam.grab(). It will just read that frame from buffer but will not do anything with it. In that way you can avoid "suffering from buffering". Simple code would be:

import cv2
import time
cam = cv2.VideoCapture(url)
ret,frame = cam.read()
timeCheck = time.time()
future = 10*60 # delay
while ret:
    if time.time() >= timeCheck:
        ret,frame = cam.read()
        # Do your staff here
        timeCheck = time.time()+future
    else:
        # Read from buffer, but skip it
        ret = cam.grab() # note that grab() function returnt only status code,not the frame