Próbowałem stworzyć okno najwyższego poziomu, które przesyła strumieniowo wideo w postaci kamery internetowej i zrobić skan QR. Mam ten kod QR code od SO i another code, który tylko aktualizuje obrazy z kamery internetowej zamiast przesyłania strumieniowego wideo na etykiecie tkinter.python: tkinter, aby wyświetlić wideo z kamery internetowej i zrobić skan QR
i starałem się połączyć oba te elementy, aby uzyskać okno z etykietą aktualizującą obraz z kamery internetowej i przycisk zamykania, aby zamknąć okno główne. Podczas przesyłania obrazów może skanować kod QR, a jeśli skanowanie powiedzie się, kamera internetowa i okno główne zostaną zamknięte.
Oto, co próbowałem.
import cv2
import cv2.cv as cv
import numpy
import zbar
import time
import threading
import Tkinter
from PIL import Image, ImageTk
class BarCodeScanner(threading.Thread, Tkinter.Toplevel):
def __init__(self):
# i made this as a global variable so i can access this image
# outside ie,. beyond the thread to update the image on to the tkinter window
global imgtk
imgtk = None
threading.Thread.__init__(self)
self.WINDOW_NAME = 'Camera'
self.CV_SYSTEM_CACHE_CNT = 5 # Cv has 5-frame cache
self.LOOP_INTERVAL_TIME = 0.2
cv.NamedWindow(self.WINDOW_NAME, cv.CV_WINDOW_NORMAL)
self.cam = cv2.VideoCapture(-1)
self.confirm = 0
def scan(self, aframe):
imgray = cv2.cvtColor(aframe, cv2.COLOR_BGR2GRAY)
# to show coloured image, as from the other code mentioned in the other code
imgcol = cv2.cvtColor(aframe, cv2.COLOR_BGR2RGBA)
imgcol_array = Image.fromarray(imgcol)
imgtk = ImageTk.PhotoImage(image=imgcol_array)
raw = str(imgray.data)
scanner = zbar.ImageScanner()
scanner.parse_config('enable')
width = int(self.cam.get(cv.CV_CAP_PROP_FRAME_WIDTH))
height = int(self.cam.get(cv.CV_CAP_PROP_FRAME_HEIGHT))
imageZbar = zbar.Image(width, height,'Y800', raw)
scanner.scan(imageZbar)
for symbol in imageZbar:
print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data
return symbol.data
def run(self):
self.datalst = []
print 'BarCodeScanner run', time.time()
while True:
for i in range(0,self.CV_SYSTEM_CACHE_CNT):
self.cam.read()
img = self.cam.read()
self.data = self.scan(img[1])
cv2.imshow(self.WINDOW_NAME, img[1])
cv.WaitKey(1)
time.sleep(self.LOOP_INTERVAL_TIME)
if self.data:
self.datalst.append(self.data)
# i have added this section so that it waits for scan
# if a scan is made it and if gets same value after 2 scans
# it has to stop webcam
if len(self.datalst) == 2 and len(set(self.datalst)) <= 1:
# I want to close the webcam before closing the toplevel window
#self.cam.release()
#cv2.destroyAllWindows()
break
self.cam.release()
def Video_Window():
video_window = Tkinter.Toplevel()
video_window.title('QR Scan !!')
img_label = Tkinter.Label(video_window)
img_label.pack(side=Tkinter.TOP)
close_button = Tkinter.Button(video_window, text='close', command = video_window.destroy)
close_button.pack(side=Tkinter.TOP)
def update_frame():
global imgtk
img_label.configure(image=imgtk)
img_label.after(10,update_frame)
update_frame()
def main():
root = Tkinter.Tk()
button_scanQr = Tkinter.Button(root, text='QR Scan', command=start_scan)
button_scanQr.pack()
root.mainloop()
def start_scan():
scanner = BarCodeScanner()
scanner.start()
Video_Window()
#scanner.join()
main()
Problem jest
- I rzeczywiście chciał, aby wyświetlić film na Toplevel oknie, a nie okno OpenCV
- jednocześnie zrobić QR skanowania, jeśli czytanie się powiedzie, okno Toplevel powinno się zamknąć bez gwałtownej domykania kamery (ponieważ, kiedy próbuję użyć
self.cam.release()
lubcv2.destroyAllWindows()
, moje kamery internetowe zapalają się lub włączają, nawet jeśli skończę kompilację programów).
Teraz otrzymuję oddzielne okno utworzone przez OpenCV, które przesyła wideo do środka. Ale nie chcę tego okna, zamiast tego chcę, aby film był wyświetlany w oknie trzystu dzwonka. także, gdy następuje pomyślny odczyt, kamera internetowa zatrzymuje się na końcowym obrazie, który odczytuje.
próbowałem usunąć wiersz, który był odpowiedzialny za oknem OpenCV, wewnątrz run
metoda BarcodeScanner
klasy
cv2.imshow(self.WINDOW_NAME, img[1])
jeszcze pojawił się z innego okna bez wyjścia, a jeśli próbuję zamknąć że window, utworzył kolejny podobny i rekursywny.
UPDATE:
jak zauważyłem zrobiłem kilka głupich błędów, bez zrozumienia niektórych liniach w cv2
, zrobiłem kilka zmian w kodzie, dodając Toplevel kod okno do metody klasy run
(nie jestem pewien, czy to jest właściwa droga).
import cv2
import cv2.cv as cv
import numpy
import zbar
import time
import threading
import Tkinter
from multiprocessing import Process, Queue
from Queue import Empty
from PIL import Image, ImageTk
class BarCodeScanner(threading.Thread, Tkinter.Toplevel):
def __init__(self):
threading.Thread.__init__(self)
#self.WINDOW_NAME = 'Camera'
self.CV_SYSTEM_CACHE_CNT = 5 # Cv has 5-frame cache
self.LOOP_INTERVAL_TIME = 0.2
#cv.NamedWindow(self.WINDOW_NAME, cv.CV_WINDOW_NORMAL)
self.cam = cv2.VideoCapture(-1)
# check if webcam device is free
self.proceede = self.cam.isOpened()
if not self.proceede:
return
self.confirm = 0
def scan(self, aframe):
imgray = cv2.cvtColor(aframe, cv2.COLOR_BGR2GRAY)
raw = str(imgray.data)
scanner = zbar.ImageScanner()
scanner.parse_config('enable')
width = int(self.cam.get(cv.CV_CAP_PROP_FRAME_WIDTH))
height = int(self.cam.get(cv.CV_CAP_PROP_FRAME_HEIGHT))
imageZbar = zbar.Image(width, height,'Y800', raw)
scanner.scan(imageZbar)
for symbol in imageZbar:
print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data
return symbol.data
def run(self):
if not self.proceede:
return
def show_frame():
_, img = self.cam.read()
img = cv2.flip(img,1)
cv2image = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
img_label.imgtk = imgtk
img_label.configure(image=imgtk)
video_window.after(250, show_frame)
def destroy_video_window():
self.cam.release()
video_window.destroy()
# Toplevel GUI
video_window = Tkinter.Toplevel()
video_window.title('QR Scan !!')
img_label = Tkinter.Label(video_window)
img_label.pack(side=Tkinter.TOP)
close_button = Tkinter.Button(video_window, text='close', command = destroy_video_window)
close_button.pack(side=Tkinter.RIGHT)
show_frame()
self.datalst = []
print 'BarCodeScanner run', time.time()
while True:
for i in range(0,self.CV_SYSTEM_CACHE_CNT):
self.cam.read()
img = self.cam.read()
self.data = self.scan(img[1])
time.sleep(self.LOOP_INTERVAL_TIME)
if self.data:
self.datalst.append(self.data)
if len(self.datalst) == 2 and len(set(self.datalst)) <= 1:
video_window.destroy()
break
self.cam.release()
def main():
root = Tkinter.Tk()
button_scanQr = Tkinter.Button(root, text='QR Scan', command=scaner)
button_scanQr.pack()
root.mainloop()
def scaner():
scanner = BarCodeScanner()
scanner.start()
main()
Teraz mogę uzyskać obraz w oknie Toplevel, ale nie wiem, jak zamknąć kamerę internetową.
stan 1: kiedy pokazują kod QR skanowania, odczytuje go z powodzeniem i kamera zostaje zamknięty bez jakiegokolwiek błędu.
Warunek 2: Kiedy klikam przycisk zamykania na będąc w głównym oknie (powiedzmy, jeśli użytkownik nie chce robić żadnych skanowania i po prostu chcą, aby zamknąć kamerę) dostaję błąd mówiąc
libv4l2: error dequeuing buf: Invalid argument
VIDIOC_DQBUF: Invalid argument
select: Bad file descriptor
VIDIOC_DQBUF: Bad file descriptor
select: Bad file descriptor
VIDIOC_DQBUF: Bad file descriptor
Segmentation fault (core dumped)
Piszę tę aplikację dla maszyny Linux
, i Windows
. Jak mogę bezpiecznie zamknąć lub zakończyć kamerę internetową.
Możliwe duplikat [Using OpenCV z Tkinter] (http://stackoverflow.com/questions/32342935/using-opencv-with-tkinter) – tfv
@tfv,. wygląda podobnie, ale nie tak samo. tam wideo jest wyświetlane na oknie przy użyciu funkcji, ale tutaj, ponieważ robię jednocześnie skan QR przy jednoczesnym wyświetlaniu wideo, łączenie ich za pomocą klas i wątków znacznie utrudnia przejście – arvindh