I am reasonably inexperienced Python user (v2.7.8) and I am trying to write a GUI that displays an image from a USB camera at a low 640x480 resolution but at the click of a button records a still at the highest resolution of 2592x1944. The GUI is being written in Tkinter. My Tkinter program uses Multiprocessing and Queue to take a frame from the camera, store it in queue and display the frame in the object window. I have had the program working on a Raspberry Pi with PiCamera as a proof of principle but now I need to move the system onto a PC with this USB device (https://www.leopardimaging.com/uploads/LI-OV5640-USB-72_datasheet.pdf). I have tried to port the code using OpenCV2 to control the camera, but as soon as I try to alter the resolution of the camera the program hangs with no error message appearing.
I can write similar code in the Python shell and get it working, although my method for displaying a smaller live feed is clunky:
import numpy as np
from multiprocessing import Process, Queue
from Queue import Empty
import cv2
from PIL import Image, ImageTk
import time
feed_queue = Queue(maxsize=2**4)
live_feed = cv2.VideoCapture(1)
live_feed.set(3,2592)
live_feed.set(4,1944)
live_feed.set(5,15)
while True:
ret, img = live_feed.read()
preview_size = (640,480)
preview_frame = cv2.resize(img, preview_size, interpolation=cv2.INTER_AREA)
cv2.imshow("input", preview_frame)
key = cv2.waitKey(10)
if key == 27:
cv2.imwrite("output.jpg",img)
break
However, as soon as I write something similar for working in Tkinter, it all falls down:
def image_capture(feed_queue):
live_feed = cv2.VideoCapture(1)
live_feed.set(3,2592)
live_feed.set(4,1944)
live_feed.set(5,15)
while True:
try:
flag, frame = live_feed.read()
if flag == 0:
break
feed_queue.put(frame)
cv2.waitKey(10)
except:
live_feed.release()
continue
def update_image(image_label, feed_queue):
frame = feed_queue.get()
preview_size = (640,480)
preview_frame = cv2.resize(frame, preview_size, interpolation = cv2.INTER_AREA)
# Convert the colour space information from CV2's BGR to the more standard RGB for use with the Tkinter widgets using Python Image Library built in functions
im = cv2.cvtColor(preview_frame, cv2.COLOR_BGR2RGB)
# Create a reference copy of the original image so that it isn't designated as garbage by Python's memory allocator
a = Image.fromarray(im)
# Now convert this duplicate image to the format required by Tkinter and assign it to the Tkinter label widget, named image_label
b = ImageTk.PhotoImage(image=a)
image_label.configure(image=b)
image_label._image_cache = b
# Update the main window with this new image
root.update()
def update_all(root, image_label, feed_queue):
update_image(image_label, feed_queue)
root.after(0, func=lambda: update_all(root, image_label, feed_queue))
if __name__ == '__main__':
feed_queue = Queue(maxsize=2**4)
p = Process(target=image_capture, args=(feed_queue,))
p.start()
# setup the update callback
root.after(0, func=lambda: update_all(root, image_label, feed_queue))
print 'root.after was called...'
root.mainloop()
print 'mainloop exit'
p.join()
This may not be the most efficient way of doing it, so I would be grateful for any suggestions on better methods or ways I can get this program working.
Thanks everyone!
NOTE: I may have isolated the issue to putting the image into the queue. I wrote a few commands in the shell code and it crashed at that point
import numpy as np
from multiprocessing import Process, Queue
from Queue import Empty
import cv2
global live_feed
live_feed = cv2.VideoCapture(1)
live_feed.set(3,2592
live_feed.set(4,1944)
live_feed.set(5,15)
def takeapicture():
global live_feed
flag, frame = live_feed.read()
return flag, frame
def makeaq(feed_q):
global live_feed
flag, frame = live_feed.read()
feed_q.put(frame)
feed_q = Queue(maxsize = 2**4)
issue, img = takeapicture()
issue, img.shape
>(True, (1944L, 2592L, 3L))
pin = feed_q.get()
And crash!