Draw a general picture:
GUI development
This article only introduces the graphical interface development.
The first problem encountered is what development language and technology to choose. Because I have used Python to do Tkinter small things before, so this time I will use Python Tkinter + OpenCV to do it.
There are several places to pay attention to:
1. Layout of Tkinter
1.1 Inheritance
I used class LPRSurface(Tk): class to inherit Tk, if it is written like this, I need to do super().__init__() in the init function to realize the initialization of the parent class.
1.2 Typesetting
I used the method of setting the width and height of the interface, so I fixed the size of the entire interface and specified it
- label: display area
- Entry: output area
- Button: the size and position of the button area
Use place instead of pack.
1.3 update
- To update the image, you only need to reconfigure the image of the label, but here it should be noted that the image must be modified with self, otherwise resources will be recycled and the image cannot be loaded normally. self.labelPic.configure(image = self.imgOri , bg="pink")
- The update of Video needs to use the threading module to recreate the thread.
2. Path memory
A separate class is used to record the opened image path and store this path in the registry (this is not good for Linux support...).
Requires winreg external library
2.1 Create a registry
winreg.CreateKey(winreg.HKEY_CURRENT_USER, r"Software\{}\LPR".format(getpass.getuser()))
2.2 Write to the registry
winreg.SetValueEx(key, "LPR", 0, winreg.REG_SZ, path)
2.3 Read the registry
winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\{}\LPR".format(getpass.getuser()))
winreg.QueryValueEx(key, "LPR")
3. OpenCV display
3.1 Format conversion
- Remember OpenCV's BGR permutation against humanity? You can use cv.cvtColor to convert the image read by OpenCV into ordinary RGB.
- Then convert it into a data format that Tkinter can display, and send it to the image in the label
imgCVRGB = cv.cvtColor(imgCV, cv.COLOR_BGR2RGB)
img = Image.fromarray(imgCVRGB)
imgTK = ImageTk.PhotoImage(image=img)
3.2 Display Adaptive
If the picture is not as large as Tkinter's Lable, it will be displayed normally, otherwise it will be scaled proportionally to ensure that the entire picture can be displayed completely on the Lable.
widthScale = 1.0*self.labelPicWidth/picWidth
heightScale = 1.0*self.labelPicHeight/picHeight
scale = min(widthScale, heightScale)
resizeWidth = int(picWidth*scale)
resizeHeight = int(picHeight*scale)
img = img.resize((resizeWidth, resizeHeight), Image.ANTIALIAS)
3.3 Delay in Thread
You can use decimals!
time.sleep(0.03)
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
from tkinter import ttk
import cv2 as cv
from PIL import Image, ImageTk
import numpy as np
import sys, random, datetime, os, winreg, getpass, time, threading
# PicPath: Save the last picture file path, this picture should be opened successful.
class LPRPath:
def getPath(self):
try:
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\{}\LPR".format(getpass.getuser()))
self.path = winreg.QueryValueEx(key, "LPR")
except:
self.path = None
return self.path
def setPath(self, path):
key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, r"Software\{}\LPR".format(getpass.getuser()))
winreg.SetValueEx(key, "LPR", 0, winreg.REG_SZ, path)
self.path = path
# Main LPR surface
class LPRSurface(Tk):
labelPicWidth = 700
labelPicHeight = 700
buttonWidth = 100
buttonHeight = 50
textWidth = 10
textHeight = 50
tkWidth = labelPicWidth
tkHeigth = labelPicHeight + buttonHeight * 4
isPicProcessing = False
root = None
videoThreadRun = False
def resizePicture(self, imgCV):
if imgCV is None:
print("Read Fail!")
return None
imgCVRGB = cv.cvtColor(imgCV, cv.COLOR_BGR2RGB)
img = Image.fromarray(imgCVRGB)
imgTK = ImageTk.PhotoImage(image=img)
picWidth = imgTK.width()
picHeight = imgTK.height()
# print("Picture Size:", picWidth, picHeight)
if picWidth <= self.labelPicWidth and picHeight <= self.labelPicHeight:
return imgTK
widthScale = 1.0*self.labelPicWidth/picWidth
heightScale = 1.0*self.labelPicHeight/picHeight
scale = min(widthScale, heightScale)
resizeWidth = int(picWidth*scale)
resizeHeight = int(picHeight*scale)
img = img.resize((resizeWidth, resizeHeight), Image.ANTIALIAS)
imgTK = ImageTk.PhotoImage(image=img)
return imgTK
# Load picture
def loadPicture(self):
# Get Picture Path
if True == self.isPicProcessing:
print("Please wait until previous picture process finish!!!")
messagebox.showerror(title="PROCESSING", message="Please wait until previous picture process finish!!!")
return
self.videoThreadRun = False
LPRPic = LPRPath()
if None == LPRPic.getPath():
initPath = ""
else:
initPath = LPRPic.path
# fileName = None
fileName = filedialog.askopenfilename(title='Load Picture', \
filetypes=[('Picture File', '*.jfif *.jpg *.png *.gif'), ('All Files', '*')], \
initialdir=initPath)
print(fileName)
if not os.path.isfile(fileName):
print("Please input correct filename!")
return False
# Read Picture File.
try:
# self.imgOri = Image.open(fileName)
# imgCV = cv.imdecode(np.fromfile(fileName, dtype=np.uint8), cv.IMREAD_COLOR)
imgCV = cv.imread(fileName)
except:
print("Open file faile!")
return False
LPRPic.setPath(fileName)
self.imgOri = self.resizePicture(imgCV)
if self.imgOri is None:
print("Load picture fail!")
return False
# self.imgOri = ImageTk.PhotoImage(self.imgOri)
self.labelPic.configure(image = self.imgOri, bg="pink")
# Video Thread
def videoThread(self):
self.videoThreadRun = True
while self.videoThreadRun:
ret, imgCV = self.camera.read()
if ret is not True:
print("Camera Read Fail!")
return False
self.imgOri = self.resizePicture(imgCV)
self.labelPic.configure(image=self.imgOri, bg="pink")
time.sleep(0.03)
print("Video Thread Finish!")
self.camera.release()
# Load Video From Camera by OpenCV
def loadVideo(self):
if self.videoThreadRun == True:
print("Video Is Opening!!!")
messagebox.showerror(title="VIDEO ERROR", message="Camera Is Opening !!!")
return False
self.camera = cv.VideoCapture(0)
if not self.camera.isOpened():
print("Open Camera Fail!")
messagebox.showerror(title="CAMERA ERROR", message="Open Camera Fail !!!")
return False
self.thread = threading.Thread(target=self.videoThread)
self.thread.setDaemon(True)
self.thread.start()
self.videoThreadRun = True
def __init__(self, *args, **kw):
super().__init__()
self.title("LPR Surface")
self.geometry(str(self.tkWidth) + "x" + str(self.tkHeigth))
self.resizable(0, 0)
def labelInit():
# Picture Label:
self.labelPic = Label(self, text="Show Picture Area", font=("Arial", 24), bg="sky blue")
self.labelPic.place(x=0, y=0, width=self.labelPicWidth, height=self.labelPicHeight)
# Vehicle Plate Number Label:
self.labelPlateNum = Label(self, text="Vehicle License Plate Number:", anchor=SW)
self.labelPlateNum.place(x=0, y=self.labelPicHeight, \
width=self.textWidth * 20, height=self.textHeight)
# Vehicle Colour Label:
self.labelPlateCol = Label(self, text="Vehicle License Plate Color:", anchor=SW)
self.labelPlateCol.place(x=0, y=self.labelPicHeight + self.textHeight * 2,
width=self.textWidth * 20, height=self.textHeight)
def buttonInit():
# Picture Button
self.buttonPic = Button(self, text="Load Picture", command=self.loadPicture)
self.buttonPic.place(x=self.tkWidth - 3 * self.buttonWidth / 2,
y=self.labelPicHeight + self.buttonHeight / 2, \
width=self.buttonWidth, height=self.buttonHeight)
# Video Button
self.buttonVideo = Button(self, text="Load Video", command=self.loadVideo)
self.buttonVideo.place(x=self.tkWidth - 3 * self.buttonWidth / 2,
y=self.labelPicHeight + 5 * self.buttonHeight / 2, \
width=self.buttonWidth, height=self.buttonHeight)
def entryInit():
# Vehicle Plate Number Output
self.entryPlateNumList = []
for index in range(7):
entryPlateNum = Entry(self)
entryPlateNum.place(x=self.textWidth * index * 6, y=self.labelPicHeight + self.textHeight, \
width=self.textWidth * 5, height=self.textHeight)
self.entryPlateNumList.append(entryPlateNum)
# Vehicle Plate Color Output
self.entryPlateColor = Entry(self)
self.entryPlateColor.place(x=0, y=self.labelPicHeight + self.textHeight * 3, \
width=self.textWidth * (42 - 1), height=self.textHeight)
labelInit()
buttonInit()
entryInit()
print("-------------init success-------------")
self.mainloop()
if __name__ == '__main__':
LS = LPRSurface()
print("Finish")
(49) Interface of License Plate Recognition (Tkinter + OpenCV Display Picture and Video) bzdww