2016-05-07 55 views
9

मैं एक टिंकर टॉप लेवल विंडो बनाने की कोशिश कर रहा हूं जो वीडियो फॉर्म वेबकैम स्ट्रीम करता है और एक क्यूआर स्कैन करता है। मुझे यह क्यूआर स्कैन कोड SO और another code से मिला है जो कि टिंकर लेबल पर वीडियो स्ट्रीम करने के बजाय वेबकैम से छवियों को अपडेट करता है।पायथन: वेबकैम से वीडियो प्रदर्शित करने के लिए टिंकर और एक क्यूआर स्कैन करें

और मैंने इन दोनों को गठबंधन करने की कोशिश की ताकि वेबकैम से एक लेबल अद्यतन छवि के साथ एक अपरिवर्तित खिड़की और अपूर्ण विंडो को बंद करने के लिए एक करीबी बटन। और जब यह छवियों को स्ट्रीम करता है, तो यह क्यूआर कोड के लिए स्कैन कर सकता है और यदि कोई स्कैन सफल होता है, तो वेबकैम और अपूर्ण विंडो बंद हो जाती है।

यहां मैंने कोशिश की है।

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() 

समस्या है,

  1. मैं वास्तव में उच्चस्तरीय खिड़की पर वीडियो प्रदर्शित करने, नहीं OpenCV खिड़की
  2. एक ही समय एक QR स्कैन करते हैं, अगर एक चाहता था पढ़ना सफल है, टोपवेल खिड़की अचानक बंद वेबकैम के बिना बंद होनी चाहिए (क्योंकि, जब मैं self.cam.release() या cv2.destroyAllWindows() का उपयोग करने की कोशिश करता हूं तो मेरी वेबकैम रोशनी या यहां तक ​​कि अगर मैं प्रोग्राम संकलन को मजबूती से समाप्त करता हूं)।

अब मुझे जो ओपनसीवी द्वारा बनाया गया एक अलग विंडो है जो वीडियो को अंदर स्ट्रीम करती है। लेकिन मुझे वह खिड़की नहीं चाहिए, बल्कि मैं चाहता हूं कि वीडियो टिंकर की अपरिवर्तनीय खिड़की पर प्रदर्शित हो। जब भी एक सफल पढ़ा जाता है, तो वेबकैम अंतिम छवि पर अटक जाता है जो इसे पढ़ता है।

मैं लाइन है कि OpenCV खिड़की के लिए जिम्मेदार था दूर करने के लिए, runBarcodeScanner की विधि वर्ग

cv2.imshow(self.WINDOW_NAME, img[1]) 

यह अभी भी कोई उत्पादन के साथ एक अलग खिड़की के साथ दिखाया अंदर की कोशिश की, और अगर मैं कि बंद करने की कोशिश खिड़की, यह एक और समान और पुनरावर्ती बनाया।

अद्यतन:

के रूप में मैं देखा मैं cv2 में कुछ लाइनों की समझ के बिना कुछ मूर्खतापूर्ण गलतियाँ की, मैं वर्ग के run विधि में उच्चस्तरीय खिड़की कोड जोड़कर कोड पर कुछ परिवर्तन किया (मुझे यकीन नहीं है कि यह सही तरीका है)।

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() 

अब, मैं उच्चस्तरीय खिड़की पर छवि प्राप्त कर सकते हैं, लेकिन मुझे नहीं पता वेब कैमरा बंद करने के लिए कैसे।

हालत 1: जब मैं स्कैन करने के लिए एक QR कोड दिखाने के लिए, यह इसे सफलतापूर्वक पढ़ता है और वेब कैमरा किसी भी त्रुटि के बिना इस्तीफा।

हालत 2: जब मैं उच्चस्तरीय खिड़की पर बंद करें बटन पर क्लिक करें (जैसे कि यदि उपयोगकर्ता किसी भी स्कैन करने के लिए नहीं चाहता है और सिर्फ वेब कैमरा बंद करना चाहते हैं) मैं त्रुटि कह

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) 
मिल

मैं इस एप्लिकेशन को Linux, Mac और Windows मशीन के लिए लिख रहा हूं। मैं वेबकैम को सुरक्षित रूप से कैसे बंद या बंद कर सकता हूं।

+0

[Tkinter साथ OpenCV का उपयोग करना] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/32342935/using-opencv-with-tkinter) – tfv

+0

@tfv,। यह समान दिखता है, लेकिन वही नहीं। वहां पर वीडियो को फ़ंक्शंस का उपयोग करके विंडो पर प्रदर्शित किया जाता है, लेकिन यहां से जब मैं वीडियो प्रदर्शित करने के साथ-साथ एक क्यूआर स्कैन कर रहा हूं, कक्षा और थ्रेडिंग का उपयोग करके उन्हें संयोजित करना बहुत मुश्किल हो जाता है – arvindh

उत्तर

1

आपके प्रोग्राम में दो धागे हैं, मुख्य धागा और कार्यकर्ता धागा जो कैमरे से फ्रेम पढ़ता है। जब बंद बटन क्लिक किया जाता है, तो यह मुख्य धागे में होता है। self.cam.release() ऑब्जेक्ट self.cam शायद अनुपयोगी स्थिति में है, और जब self.cam की विधि कार्यकर्ता धागे द्वारा बुलाया जाता है, तो कुछ परेशानी हो सकती है। शायद cv2.VideoCapture का कार्यान्वयन दोषपूर्ण है और ऐसा होने पर इसे कुछ अपवाद फेंकना चाहिए।

मुख्य धागे की तुलना में अन्य धागे से टिंकर विजेट तक पहुंचने से समस्याएं भी हो सकती हैं।

स्वच्छ प्रोग्राम समाप्ति के लिए, threading.Event का एक उदाहरण बनाते हुए और फिर कार्य थ्रेड में किसी बिंदु पर event.is_set() की जांच कर सकते हैं। उदाहरण

def destroy_video_window(): 
    self.stop_event.set() 
    video_window.destroy() 

के लिए और उसके बाद कार्यकर्ता सूत्र में

while True: 
    if self.stop_event.is_set(): 
     break 
    for i in range(0, self.CV_SYSTEM_CACHE_CNT): 
     self.cam.read() 

वहाँ कई चीजें हैं जो अन्य तरीके से किया जा सकता है, निम्नलिखित कोड का एक संशोधित संस्करण है। यह मुख्य धागे की तुलना में अन्य थ्रेड से टिंकर विधियों को कॉल करने से बचाता है, event_generate() कार्यकर्ता धागे द्वारा बुलाया जाने वाला एकमात्र टिंकर विधि है। आभासी घटनाओं को उत्सर्जित करके स्पष्ट मतदान से बचा जाता है, उदाहरण के लिए <<ScannerQuit>>, जो टिंकर इवेंट कतार में रखे जाते हैं।

import cv2 
import cv2.cv as cv 
import zbar 
import time 
import threading 
import Tkinter as tk 

from PIL import Image, ImageTk 

class Scanner(object): 
    def __init__(self, handler, *args, **kw): 
     self.thread = threading.Thread(target=self.run) 
     self.handler = handler 

     self.CV_SYSTEM_CACHE_CNT = 5 # Cv has 5-frame cache 
     self.LOOP_INTERVAL_TIME = 0.2 
     self.cam = cv2.VideoCapture(-1) 

     self.scanner = zbar.ImageScanner() 
     self.scanner.parse_config('enable') 
     self.cam_width = int(self.cam.get(cv.CV_CAP_PROP_FRAME_WIDTH)) 
     self.cam_height = int(self.cam.get(cv.CV_CAP_PROP_FRAME_HEIGHT)) 

     self.last_symbol = None 

    def start(self): 
     self.thread.start() 

    def scan(self, aframe): 
     imgray = cv2.cvtColor(aframe, cv2.COLOR_BGR2GRAY) 
     raw = str(imgray.data) 
     image_zbar = zbar.Image(self.cam_width, self.cam_height, 'Y800', raw) 
     self.scanner.scan(image_zbar) 

     for symbol in image_zbar: 
      return symbol.data 

    def run(self): 
     print 'starting scanner' 

     while True: 
      if self.handler.need_stop(): 
       break 

      # explanation for this in 
      # http://stackoverflow.com/a/35283646/5781248 
      for i in range(0, self.CV_SYSTEM_CACHE_CNT): 
       self.cam.read() 

      img = self.cam.read() 

      self.handler.send_frame(img) 

      self.data = self.scan(img[1]) 

      if self.handler.need_stop(): 
       break 

      if self.data is not None and (self.last_symbol is None 
              or self.last_symbol <> self.data): 
       # print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data 
       self.handler.send_symbol(self.data) 
       self.last_symbol = self.data 

      time.sleep(self.LOOP_INTERVAL_TIME) 

     self.cam.release() 

class ScanWindow(tk.Toplevel): 
    def __init__(self, parent, gui, *args, **kw): 
     tk.Toplevel.__init__(self, master=parent, *args, **kw) 

     self.parent = parent 
     self.gui = gui 
     self.scanner = None 

     self.lock = threading.Lock() 
     self.stop_event = threading.Event() 

     self.img_label = tk.Label(self) 
     self.img_label.pack(side=tk.TOP) 

     self.close_button = tk.Button(self, text='close', command=self._stop) 
     self.close_button.pack() 

     self.bind('<Escape>', self._stop) 

     parent.bind('<<ScannerFrame>>', self.on_frame) 
     parent.bind('<<ScannerEnd>>', self.quit) 
     parent.bind('<<ScannerSymbol>>', self.on_symbol) 

    def start(self): 
     self.frames = [] 
     self.symbols = [] 

     class Handler(object): 
      def need_stop(self_): 
       return self.stop_event.is_set() 

      def send_frame(self_, frame): 
       self.lock.acquire(True) 
       self.frames.append(frame) 
       self.lock.release() 

       self.parent.event_generate('<<ScannerFrame>>', when='tail') 

      def send_symbol(self_, data): 
       self.lock.acquire(True) 
       self.symbols.append(data) 
       self.lock.release() 

       self.parent.event_generate('<<ScannerSymbol>>', when='tail') 

     self.stop_event.clear() 
     self.scanner = Scanner(Handler()) 
     self.scanner.start() 
     self.deiconify() 

    def _stop(self, *args): 
     self.gui.stop() 

    def stop(self): 
     if self.scanner is None: 
      return 

     self.stop_event.set() 

     self.frames = [] 
     self.symbols = [] 
     self.scanner = None 
     self.iconify() 

    def quit(self, *args): 
     self.parent.event_generate('<<ScannerQuit>>', when='tail') 

    def on_symbol(self, *args): 
     self.lock.acquire(True) 
     symbol_data = self.symbols.pop(0) 
     self.lock.release() 

     print 'symbol', '"%s"' % symbol_data 
     self.after(500, self.quit) 

    def on_frame(self, *args): 
     self.lock.acquire(True) 
     frame = self.frames.pop(0) 
     self.lock.release() 

     _, img = frame 
     img = cv2.flip(img, 1) 
     cv2image = cv2.cvtColor(img, cv2.COLOR_BGR2RGBA) 
     img = Image.fromarray(cv2image) 
     imgtk = ImageTk.PhotoImage(image=img) 
     self.img_label.imgtk = imgtk 
     self.img_label.configure(image=imgtk) 

class GUI(object): 
    def __init__(self, root): 
     self.root = root 

     self.scan_window = ScanWindow(self.root, self) 
     self.scan_window.iconify() 

     self.root.title('QR Scan !!') 

     self.lframe = tk.Frame(self.root) 
     self.lframe.pack(side=tk.TOP) 

     self.start_button = tk.Button(self.lframe, text='start', command=self.start) 
     self.start_button.pack(side=tk.LEFT) 

     self.stop_button = tk.Button(self.lframe, text='stop', command=self.stop) 
     self.stop_button.configure(state='disabled') 
     self.stop_button.pack(side=tk.LEFT) 

     self.close_button = tk.Button(self.root, text='close', command=self.quit) 
     self.close_button.pack(side=tk.TOP) 

     self.root.bind('<<ScannerQuit>>', self.stop) 
     self.root.bind('<Control-s>', self.start) 
     self.root.bind('<Control-q>', self.quit) 
     self.root.protocol('WM_DELETE_WINDOW', self.quit) 

    def start(self, *args): 
     self.start_button.configure(state='disabled') 
     self.scan_window.start() 
     self.stop_button.configure(state='active') 

    def stop(self, *args): 
     self.scan_window.stop() 
     self.start_button.configure(state='active') 
     self.stop_button.configure(state='disabled') 

    def quit(self, *args): 
     self.scan_window.stop() 
     self.root.destroy() 

def main(): 
    root = tk.Tk() 
    gui = GUI(root) 
    root.mainloop() 

main() 
संबंधित मुद्दे