2

I am working on an image-processing project where I want pictures from 3 cameras to get the latest frame when a button is pressed and for that, I have used multiprocessing.process and multiprocessing.queue as shown in the code below. The required task is achieved but there are 2 problems right now:

1.cpu-100% in task manager(which slows down the program)

2.there is a workaround for cam.set(cv2.CAP_PROP_BUFFERSIZE, 0) in the code which is the main cause for 50% of cpu usage

actually I want a fast way to get frames so I have also tried multiprocessing.pipe instead of the queue but since it does not get the latest frame when button pressed for the second time so I had to use queu communication method. Any help regarding code would be much appreciated

def camera_func(queue,cam_indx):
    cam = cv2.VideoCapture(cam_indx,cv2.CAP_DSHOW)   #current camera
    cam.set(cv2.CAP_PROP_BUFFERSIZE, 0)
    if cam.isOpened(): # Check success if the object is created and opened                    
        while True:
            try:
                flag, frame=cam.read()
                if flag==0:
                    break 
                # used to remove buffer size problem because it gets next frame 
                # rather latest frame   
                if not queue.empty():
                    try:
                        queue.get_nowait()   # discard previous (unprocessed) frame
                    except Queue.Empty:
                        pass

                queue.put(frame,False)

            except:
                continue      
    else:               
        cam.open()        
        raise Exception("Could not open camera")

queues=[]
for pip in range(0,a_cams):
    queu = Queue(maxsize=1)
    queues.append(queu)

processes = [Process(target=camera_func, args=(queues[x],x)) for x in range(a_cams)]   # Setup a list of processes that we want to run
for p in processes:     
    p.start()   # Run processes

Update:

I have used threading as suggested by nathancy and now it is doing the same task without the workaround thanks to fps sync from here, and CPU usage is still 80% but this time there is 40-sec lag when starting the program which is too much.

hawxeye
  • 99
  • 8
  • Have you done any benchmarking/profiling? – AMC Dec 12 '19 at 18:19
  • does it behave linearly? e.g. 40% vcpu usage for 1 camera, 80% for 2, 100% for 3? Do you have a multicore system a d could go beyond 100% if multie threads were used? – Micka Dec 12 '19 at 19:06
  • how do one do benchmark profiling? – hawxeye Dec 12 '19 at 19:43
  • no it does not behave linearly 50% usage when no workaround i.e. i get consective frame not latest when button was pressed. where as 50% jumps in when i do the workaround. I have i7 8gen 12core system – hawxeye Dec 12 '19 at 19:46
  • no, I haven't tried threading because I have 3 separate cameras – hawxeye Dec 12 '19 at 23:01
  • You can put each camera into a separate thread, I use this technique with about 9 IP cameras – nathancy Dec 13 '19 at 00:50
  • I am trying threading but I get error, may be I am doing wrong, can you share some simple code – hawxeye Dec 13 '19 at 01:11

2 Answers2

2

I had a similar problem. I found that it was directly related to how I was checking the queue.

I also had

if not queue.empty():
    try:
        r = queue.get()
        ...

What reduced the cpu load to near zero was removing the .empty() check. The .get() call automatically waits for something to be present in the queue before it continues.

1

May someone find it useful!

Since nobody answered my question so trying everything that I can I found that only changing the capture = cv2.VideoCapture(src) line in the threaded version of the camera input to capture = cv2.VideoCapture(src,cv2.CAP_DSHOW) significantly reduces the CPU usage plus there is no lag in the start also.

hawxeye
  • 99
  • 8