python - OpenCV - 如何从同一源捕获两个视频源 - Python
问题描述
我有一个程序,我需要 tkinter 来显示来自 Pi 相机的提要,并且我还需要它在进入帧时解码 QR 码。我不断收到错误消息:TypeError: cannot unpack non-iterable NoneType object
因为第二个功能无法访问相机供稿。
我曾尝试将 frame 设为全局变量,但这似乎也不起作用。
关于如何解决这个问题的任何想法?
# import all the necessary modules
from tkinter import *
from multiprocessing import Process, Queue
from queue import Empty # for excepting a specific error
import cv2
import pyzbar.pyzbar as pyzbar
import sys
import os
import requests
from PIL import Image, ImageTk
import time
def resetGUI():
root.configure(bg='white')
nameFrame.configure(bg='white')
instructionsFrame.configure(bg='white')
nameLabel.config(text="", bg='white')
instructionsLabel.config(text="Place your QR code under the scanner below.", bg='white')
def processScan(code):
if code != "":
print (code)
#some post request
return ["hellllllo"]
def showVideo():
_, frame = vid.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
cv2.waitKey(5)
cv2.destroyAllWindows
lmain.after(10, showVideo)
# this is the function that will be run in a child process
def startScanning(queue_):
i = 0
while i<2:
# _,f = vid.read()
_,frame = vid.read()
decoded = pyzbar.decode(frame)
for obj in decoded:
queue_.put(obj.data)
print('decoded')
#cv2.imshow('QRCode',f)
#cv2.waitKey(5)
#cv2.destroyAllWindows
#time.sleep(1)
# just a function to not write a `lambda`, just easier
# to read code
def start_process():
Process(target=startScanning, args=(queue, ), daemon=True).start()
def updateGUI():
try:
data = queue.get(block=False)
while not queue.empty():
queue.get()
except Empty:
pass
else:
#queue.clear()
code = processScan(data)
if code:
if len(code) > 1: #Pass ACCEPTED
root.configure(bg='green'): #Pass DENIED
root.after(3000, resetGUI)
finally:
root.after(100, updateGUI)
# crucial part is to use this if statement because
# child processes run this whole script again
if __name__ == '__main__':
root = Tk()
logo = "logo.png"
settings = "settings.png"
if os.environ.get('DISPLAY','') == '':
print('no display found. Using :0.0')
os.environ.__setitem__('DISPLAY', ':0.0')
#create main window
#root.attributes("-fullscreen", True)
root.title("Title")
root.geometry("480x800")
root.configure(bg='white')
ttelogo = PhotoImage(file = logo)
settingslogo = PhotoImage(file = settings)
#settings button
settingsFrame = Frame(root,width=50,height=50,bg="white")
settingsFrame.pack_propagate(0) # Stops child widgets of label_frame from resizing it
settingsBtn = Button(settingsFrame, image=settingslogo).pack()
settingsFrame.place(x=430,y=0)
#logo
img = Label(root, image=ttelogo, bg='white')
img.image = ttelogo
img.place(x=176.5,y=10)
#Name Label
nameFrame = Frame(root,width=400,height=100,bg="white")
nameFrame.pack_propagate(0) # Stops child widgets of label_frame from resizing it
nameLabel = Label(nameFrame,bg="white",fg="black",text="",font=("Calibri",22))
nameLabel.pack()
nameFrame.place(x=40,y=140)
#Instructions Label
instructionsFrame = Frame(root,width=440,height=100,bg="white")
instructionsFrame.pack_propagate(0) # Stops child widgets of label_frame from resizing it
instructionsLabel = Label(instructionsFrame,bg="white",fg="black",text="Hello",font=("Calibri",15))
instructionsLabel.pack()
instructionsFrame.place(x=20,y=210)
#Camera Window
cameraFrame = Frame(root, width=440, height=480)
cameraFrame.place(x=20, y=260)
#Camera Feed
lmain = Label(cameraFrame)
lmain.place(x=0, y=0)
vid = cv2.VideoCapture(0)
# define queue (since it is a global variable now
# it can be easily used in the functions)
queue = Queue()
#label = Label(root)
#label.pack()
# initially start the update function
updateGUI()
# just a button for starting the process, but you can also simply
# call the function
start_process()
showVideo()
root.mainloop()
编辑:删除了线程和不必要的代码
# import all the necessary modules
from tkinter import *
from multiprocessing import Process, Queue
from queue import Empty # for excepting a specific error
import cv2
import pyzbar.pyzbar as pyzbar
import sys
import os
import requests
from PIL import Image, ImageTk
import time
import threading
def resetGUI():
root.configure(bg='white')
nameFrame.configure(bg='white')
instructionsFrame.configure(bg='white')
nameLabel.config(text="", bg='white')
instructionsLabel.config(text="Place your QR code under the scanner below.", bg='white')
def processScan(code):
if code != "":
print (code)
#some post request
return ["hellllllo"]
def showVideo():
vid = cv2.VideoCapture(0)
_, frame = vid.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
cv2.waitKey(5)
cv2.destroyAllWindows
lmain.after(10, showVideo)
# this is the function that will be run in a child process
def startScanning(queue_):
i = 0
while i<2:
vid = cv2.VideoCapture(0)
# _,f = vid.read()
_,frame = vid.read()
decoded = pyzbar.decode(frame)
for obj in decoded:
queue_.put(obj.data)
print('decoded')
def start_process():
threading.Thread(target=startScanning, args=(queue, ), daemon=True).start()
def updateGUI():
try:
data = queue.get(block=False)
while not queue.empty():
queue.get()
except Empty:
pass
else:
#queue.clear()
code = processScan(data)
if code:
if len(code) > 1: #Pass ACCEPTED
root.configure(bg='green'): #Pass DENIED
root.after(3000, resetGUI)
finally:
root.after(100, updateGUI)
if __name__ == '__main__':
root = Tk()
logo = "logo.png"
settings = "settings.png"
if os.environ.get('DISPLAY','') == '':
print('no display found. Using :0.0')
os.environ.__setitem__('DISPLAY', ':0.0')
#create main window
#root.attributes("-fullscreen", True)
root.title("Title")
root.geometry("480x800")
root.configure(bg='white')
#Camera Window
cameraFrame = Frame(root, width=440, height=480)
cameraFrame.place(x=20, y=260)
#Camera Feed
lmain = Label(cameraFrame)
lmain.place(x=0, y=0)
queue = Queue()
# initially start the update function
updateGUI()
start_process()
showVideo()
root.mainloop()
编辑 2:尝试了全球视频
from tkinter import *
from multiprocessing import Process, Queue
from queue import Empty # for excepting a specific error
import cv2
import pyzbar.pyzbar as pyzbar
import sys
import os
import requests
from PIL import Image, ImageTk
import time
import threading
def resetGUI():
root.configure(bg='white')
nameFrame.configure(bg='white')
instructionsFrame.configure(bg='white')
nameLabel.config(text="", bg='white')
instructionsLabel.config(text="Place your QR code under the scanner below.", bg='white')
def processScan(code):
if code != "":
print (code)
#some post request
return ["hellllllo"]
def showVideo():
global vid
vid = cv2.VideoCapture(0)
_, frame = vid.read()
frame = cv2.flip(frame, 1)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
cv2.waitKey(5)
cv2.destroyAllWindows
lmain.after(10, showVideo)
# this is the function that will be run in a child process
def startScanning(queue_):
i = 0
while i<2:
# _,f = vid.read()
_,frame = vid.read()
decoded = pyzbar.decode(frame)
for obj in decoded:
queue_.put(obj.data)
print('decoded')
def start_process():
threading.Thread(target=startScanning, args=(queue, ), daemon=True).start()
def updateGUI():
try:
data = queue.get(block=False)
while not queue.empty():
queue.get()
except Empty:
pass
else:
#queue.clear()
code = processScan(data)
if code:
if len(code) > 1: #Pass ACCEPTED
root.configure(bg='green'): #Pass DENIED
root.after(3000, resetGUI)
finally:
root.after(100, updateGUI)
if __name__ == '__main__':
root = Tk()
logo = "logo.png"
settings = "settings.png"
if os.environ.get('DISPLAY','') == '':
print('no display found. Using :0.0')
os.environ.__setitem__('DISPLAY', ':0.0')
#create main window
#root.attributes("-fullscreen", True)
root.title("Title")
root.geometry("480x800")
root.configure(bg='white')
#Camera Window
cameraFrame = Frame(root, width=440, height=480)
cameraFrame.place(x=20, y=260)
#Camera Feed
lmain = Label(cameraFrame)
lmain.place(x=0, y=0)
queue = Queue()
# initially start the update function
updateGUI()
showVideo()
start_process()
root.mainloop()
最新更新后,出现以下错误:
[ WARN:0] global /root/opencv/modules/videoio/src/cap_v4l.cpp (890) open VIDEOIO(V4L2:/dev/video0): can't open camera by index
Exception in Tkinter callback
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/lib/python3.7/threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "stackoverflow2.py", line 49, in startScanning
decoded = pyzbar.decode(frame)
File "/usr/local/lib/python3.7/dist-packages/pyzbar/pyzbar.py", line 181, in decode
pixels, width, height = _pixel_data(image)
File "/usr/local/lib/python3.7/dist-packages/pyzbar/pyzbar.py", line 147, in _pixel_data
pixels, width, height = image
TypeError: cannot unpack non-iterable NoneType object
Traceback (most recent call last):
File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "/usr/lib/python3.7/tkinter/__init__.py", line 749, in callit
func(*args)
File "stackoverflow2.py", line 34, in showVideo
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
cv2.error: OpenCV(4.5.3) /root/opencv/modules/imgproc/src/color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'
解决方案
推荐阅读
- ruby - 如何在 Ruby 的“坚固”gem 中获取 git 存储库的默认分支?
- utf-8 - 当数组包含 UTF-8 字符时,CodeCeption assertContains 失败
- angular - 将 Angular 从 4 升级到 6 时使用 angular2-jwt 和 AuthHttp 的问题
- latex - Latex BibTex 找不到数据库条目
- visual-studio - SQL Server 是否使用 Windows 身份验证从 Azure 连接到 Visual Studio?
- c++ - 如何创建 Gdk::Pixbuf 实例的 std::map 并在 Gdk::Cairo 中使用它
- php - 如何从 sql 数据库中删除两个不同数据相等的行?
- leaflet - 不添加带有传单地图和 L.Routing.control 的添加 css 的自定义标记
- datetime - 在给定时间之间创建随机分钟日期
- python - 带有小马 0.7 的 Python 3.6 在提交到 oracle db 时出错