License plate recognition UI (Tkinter + OpenCV display Picture and Video)

 

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

Guess you like

Origin blog.csdn.net/qq_42672770/article/details/131129874