├── .DS_Store
├── .idea
├── encodings.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── misc.xml
├── modules.xml
├── workspace.xml
└── 车牌识别.iml
├── README.md
├── __pycache__
├── config.cpython-37.pyc
├── debug.cpython-37.pyc
├── img_api.cpython-37.pyc
├── img_api2.cpython-37.pyc
├── img_excel.cpython-37.pyc
├── img_function.cpython-34.pyc
├── img_function.cpython-37.pyc
├── img_math.cpython-34.pyc
├── img_math.cpython-37.pyc
├── img_recognition.cpython-34.pyc
├── img_recognition.cpython-37.pyc
├── img_sql.cpython-37.pyc
├── main.cpython-34.pyc
├── main.cpython-37.pyc
├── math.cpython-37.pyc
├── screencut.cpython-37.pyc
└── sql.cpython-37.pyc
├── data.xls
├── face.py
├── img
├── .DS_Store
├── lock.jpg
└── start.png
├── img_api.py
├── img_api2.py
├── img_excel.py
├── img_function.py
├── img_math.py
├── img_recognition.py
├── img_sql.py
├── login.py
├── main.py
├── pic
├── .DS_Store
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── api.png
├── hy.png
├── locate.png
├── log.png
├── login.png
└── sql.png
├── screencut.py
├── svm.dat
├── svmchinese.dat
└── tmp
├── .DS_Store
├── cut.png
├── img_contours.jpg
├── test.jpg
└── url.png
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/.DS_Store
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | train_svm
30 | deskew
31 | print
32 | else
33 | img_color_contours
34 | predict_result
35 | img_only_color
36 | row
37 | not
38 | AipOcr
39 | top
40 | LicensePlate
41 | postLicensePlate
42 | thread_run
43 | center_window
44 | get_imgtk
45 | self.thread_run2
46 | self.cameraflag
47 | self.apistr
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
--------------------------------------------------------------------------------
/.idea/车牌识别.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Python opencv 车牌识别
2 |
3 | ## [请使用新版](https://github.com/dreamhunter2333/python_PlateRecogntion)
4 |
--------------------------------------------------------------------------------
/__pycache__/config.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/config.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/debug.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/debug.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/img_api.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/img_api.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/img_api2.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/img_api2.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/img_excel.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/img_excel.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/img_function.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/img_function.cpython-34.pyc
--------------------------------------------------------------------------------
/__pycache__/img_function.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/img_function.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/img_math.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/img_math.cpython-34.pyc
--------------------------------------------------------------------------------
/__pycache__/img_math.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/img_math.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/img_recognition.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/img_recognition.cpython-34.pyc
--------------------------------------------------------------------------------
/__pycache__/img_recognition.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/img_recognition.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/img_sql.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/img_sql.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/main.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/main.cpython-34.pyc
--------------------------------------------------------------------------------
/__pycache__/main.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/main.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/math.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/math.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/screencut.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/screencut.cpython-37.pyc
--------------------------------------------------------------------------------
/__pycache__/sql.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/__pycache__/sql.cpython-37.pyc
--------------------------------------------------------------------------------
/data.xls:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/data.xls
--------------------------------------------------------------------------------
/face.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import tkinter as tk
4 | from tkinter import ttk
5 | from tkinter.filedialog import *
6 | import tkinter.messagebox
7 | from PIL import Image, ImageTk
8 | import img_api2
9 | import cv2
10 | import threading
11 | import time
12 |
13 | class Login(ttk.Frame):
14 | def __init__(self, win):
15 | ttk.Frame.__init__(self, win)
16 | frame0 = ttk.Frame(self)
17 | frame1 = ttk.Frame(self)
18 | win.title("人脸识别")
19 | win.minsize(800, 550)
20 | self.center_window()
21 | self.thread_run = None
22 | self.thread_run2 = None
23 | self.camera = None
24 |
25 | self.pilImage = Image.open("img/start.png")
26 | self.tkImage = ImageTk.PhotoImage(image=self.pilImage)
27 | self.image_ctl = tk.Label(frame0, image=self.tkImage)
28 | self.image_ctl.pack()
29 |
30 | frame0.pack(side=TOP, fill=tk.Y, expand=1)
31 | frame1.pack(side=TOP, fill=tk.Y, expand=1)
32 |
33 | self.facer = ttk.Label(frame1, text='', font=('Times', '20'))
34 | self.facer.pack()
35 |
36 | self.face_button1 = ttk.Button(frame1, text="选择文件", width=15, command=self.file1)
37 | self.face_button1.pack(side=TOP)
38 | self.url_face_button = ttk.Button(frame1, text="使用相机识别", width=15, command=self.cv_face)
39 | self.url_face_button.pack(side=TOP)
40 | self.file_pic_button = ttk.Button(frame1, text="本地文件识别", width=15, command=self.file_pic)
41 | self.file_pic_button.pack(side=TOP)
42 |
43 | self.pack(fill=tk.BOTH, expand=tk.YES, padx="10", pady="10")
44 |
45 | def center_window(self):
46 | screenwidth = log.winfo_screenwidth()
47 | screenheight = log.winfo_screenheight()
48 | log.update()
49 | width = log.winfo_width()
50 | height = log.winfo_height()
51 | size = '+%d+%d' % ((screenwidth - width)/2, (screenheight - height)/2)
52 | log.geometry(size)
53 |
54 | def file1(self):
55 | self.pic_path = askopenfilename(title="选择识别图片", filetypes=[("jpg图片", "*.jpg"), ("png图片", "*.png")])
56 |
57 | def cv_face(self):
58 | if self.thread_run:
59 | if self.camera.isOpened():
60 | self.camera.release()
61 | print("关闭摄像头")
62 | self.camera = None
63 | self.thread_run = False
64 | return
65 | if self.camera is None:
66 | self.camera = cv2.VideoCapture(1)
67 | if not self.camera.isOpened():
68 | self.camera = None
69 | print("没有外置摄像头")
70 | self.camera = cv2.VideoCapture(0)
71 | if not self.camera.isOpened():
72 | print("没有内置摄像头")
73 | tkinter.messagebox.showinfo('警告', '摄像头打开失败!')
74 | self.camera = None
75 | return
76 | else:
77 | print("打开内置摄像头")
78 | else:
79 | print("打开外置摄像头")
80 | self.thread = threading.Thread(target=self.video_thread)
81 | self.thread.setDaemon(True)
82 | self.thread.start()
83 | self.thread_run = True
84 |
85 | def video_thread(self):
86 | self.thread_run = True
87 | self.thread2 = threading.Thread(target=self.video_pic)
88 | self.thread2.setDaemon(True)
89 | self.thread2.start()
90 | self.thread_run2 = True
91 | while self.thread_run:
92 | _, img_bgr = self.camera.read()
93 | img = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
94 | im = Image.fromarray(img)
95 | w, h = im.size
96 | pil_image_resized = self.resize(w, h, im)
97 | self.imgtk = ImageTk.PhotoImage(image=pil_image_resized)
98 | self.image_ctl.configure(image=self.imgtk)
99 | print("run end")
100 |
101 | def video_pic(self):
102 | self.thread_run2 = True
103 | predict_time = time.time()
104 | while self.thread_run2:
105 | if time.time() - predict_time > 2:
106 | print("实时识别中")
107 | _, img_bgr = self.camera.read()
108 | cv2.imwrite("tmp/test2.jpg", img_bgr)
109 | self.pic_path = "tmp/test2.jpg"
110 | try:
111 | self.file_pic()
112 | except:
113 | pass
114 | predict_time = time.time()
115 | print("video_pic")
116 | pass
117 |
118 | def file_pic(self):
119 | self.pic_path2 = "img/lock.jpg"
120 | try:
121 | facestr, result = img_api2.facef(self.pic_path, self.pic_path2)
122 | except:
123 | tkinter.messagebox.showinfo('提示', '登录失败,请重试!')
124 | return
125 | self.facer.configure(text=str(facestr))
126 | self.pic()
127 | if result > 80:
128 | self.thread_run = False
129 | self.thread_run2 = False
130 | tkinter.messagebox.showinfo('提示', '登录成功!')
131 | close_window()
132 | os.system("python3 ./main.py")
133 | else:
134 | tkinter.messagebox.showinfo('提示', '登录失败,请重试!')
135 |
136 | def pic(self):
137 | self.pilImage3 = Image.open(self.pic_path)
138 | w, h = self.pilImage3.size
139 | pil_image_resized = self.resize(w, h, self.pilImage3)
140 | self.tkImage3 = ImageTk.PhotoImage(image=pil_image_resized)
141 | self.image_ctl.configure(image=self.tkImage3)
142 |
143 | def resize(self, w, h, pil_image):
144 | w_box = 800
145 | h_box = 400
146 | f1 = 1.0*w_box/w
147 | f2 = 1.0*h_box/h
148 | factor = min([f1, f2])
149 | width = int(w*factor)
150 | height = int(h*factor)
151 | return pil_image.resize((width, height), Image.ANTIALIAS)
152 |
153 |
154 | def close_window():
155 | print("log destroy")
156 | log.destroy()
157 |
158 |
159 | if __name__ == '__main__':
160 | log = tk.Tk()
161 |
162 | login = Login(log)
163 | # close,退出输出destroy
164 | log.protocol('WM_DELETE_WINDOW', close_window)
165 | # 进入消息循环
166 | log.mainloop()
167 |
--------------------------------------------------------------------------------
/img/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/img/.DS_Store
--------------------------------------------------------------------------------
/img/lock.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/img/lock.jpg
--------------------------------------------------------------------------------
/img/start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/img/start.png
--------------------------------------------------------------------------------
/img_api.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | import requests
3 | import os
4 | import base64
5 | import json
6 | import jsonpath
7 |
8 | ACCESS_TOKEN = ''
9 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
10 |
11 | # ID,KEY的配置信息
12 | INFO_CONFIG = {
13 | 'ID': '15777797',
14 | 'API_KEY': 'xkQmQk08d7pTP56LqXhqpUbm',
15 | 'SECRET_KEY': 'bzgSQwTy6WTkXczLlYPfOwu2OQZQ8CEg'
16 | }
17 |
18 | # URL配置
19 | URL_LIST_URL = {
20 | # ACCESS_TOKEN_URL用于获取ACCESS_TOKEN, POST请求,
21 | # grant_type必须参数,固定为client_credentials,client_id必须参数,应用的API Key,client_secre 必须参数,应用的Secret Key.
22 | 'ACCESS_TOKEN_URL': 'https://aip.baidubce.com/oauth/2.0/token?' + 'grant_type=client_credentials&client_id={API_KEYS}&client_secret={SECRET_KEYS}&'.format(
23 | API_KEYS=INFO_CONFIG['API_KEY'], SECRET_KEYS=INFO_CONFIG['SECRET_KEY']),
24 | # 车牌识别
25 | 'LICENSE_PLATE': 'https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate',
26 |
27 | }
28 |
29 |
30 | class AccessTokenSuper(object):
31 | pass
32 |
33 |
34 | class AccessToken(AccessTokenSuper):
35 | def getToken(self):
36 | accessToken = requests.post(url=URL_LIST_URL['ACCESS_TOKEN_URL'])
37 | accessTokenJson = accessToken.json()
38 | if dict(accessTokenJson).get('error') == 'invalid_client':
39 | return '获取accesstoken错误,请检查API_KEY,SECRET_KEY是否正确!'
40 | return accessTokenJson
41 |
42 |
43 | ACCESS_TOKEN = AccessToken().getToken()['access_token']
44 |
45 | LICENSE_PLATE_URL = URL_LIST_URL['LICENSE_PLATE'] + '?access_token={}'.format(ACCESS_TOKEN)
46 |
47 |
48 | class LicensePlateSuper(object):
49 | pass
50 |
51 |
52 | class LicensePlate(LicensePlateSuper):
53 |
54 | def __init__(self, image=None, multi_detect=True):
55 | self.HEADER = {
56 | 'Content-Type': 'application/x-www-form-urlencoded',
57 | }
58 | self.IMAGE_CONFIG = {
59 | 'multi_detect': multi_detect,
60 | }
61 |
62 | if image is not None:
63 | imagepath = os.path.exists(image)
64 | if imagepath == True:
65 | images = image
66 | with open(images, 'rb') as images:
67 | self.IMAGE_CONFIG['image'] = base64.b64encode(images.read())
68 |
69 | def postLicensePlate(self):
70 | if self.IMAGE_CONFIG.get('image', None) == None:
71 | return 'image参数不能为空!'
72 | licensePlate = requests.post(url=LICENSE_PLATE_URL, headers=self.HEADER,
73 | data=self.IMAGE_CONFIG)
74 | return licensePlate.json()
75 |
76 |
77 | def api_pic(CPH):
78 | # 测试获取AccessToken
79 | testAccessToken = AccessToken()
80 | # print('Access_token:', testAccessToken.getToken())
81 |
82 | # 车牌号识别
83 | testLicensePlate = LicensePlate(image=CPH)
84 | testLicensePlatejson = testLicensePlate.postLicensePlate()
85 |
86 | testcolor =jsonpath.jsonpath(testLicensePlatejson, '$..color')
87 | testtext =jsonpath.jsonpath(testLicensePlatejson, '$..number')
88 |
89 | testcolorstr = "".join(testcolor)
90 | testtextstr = "".join(testtext)
91 | #print('车牌号api识别:', testcolorstr, testtextstr)
92 | return testcolorstr, testtextstr
93 |
--------------------------------------------------------------------------------
/img_api2.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | import requests
4 | import os
5 | import base64
6 | import json
7 |
8 | ACCESS_TOKEN = ''
9 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
10 |
11 | # ID,KEY的配置信息
12 | INFO_CONFIG = {
13 | 'ID': '15788358',
14 | 'API_KEY': 'ohtGa5yYoQEZ8Try8lnL99UK',
15 | 'SECRET_KEY': 'qaDjyuXkf5MZ28g5C8pwFngDZenhswC3'
16 | }
17 |
18 | # URL配置
19 | URL_LIST_URL = {
20 | # ACCESS_TOKEN_URL用于获取ACCESS_TOKEN, POST请求,
21 | # grant_type必须参数,固定为client_credentials,client_id必须参数,应用的API Key,client_secre 必须参数,应用的Secret Key.
22 | 'ACCESS_TOKEN_URL': 'https://aip.baidubce.com/oauth/2.0/token?' + 'grant_type=client_credentials&client_id={API_KEYS}&client_secret={SECRET_KEYS}&'.format(
23 | API_KEYS=INFO_CONFIG['API_KEY'], SECRET_KEYS=INFO_CONFIG['SECRET_KEY']),
24 | # 人脸识别
25 | 'FACE_PLATE': 'https://aip.baidubce.com/rest/2.0/face/v3/match',
26 |
27 | }
28 |
29 |
30 | class AccessTokenSuper(object):
31 | pass
32 |
33 |
34 | class AccessToken(AccessTokenSuper):
35 | def getToken(self):
36 | accessToken = requests.post(url=URL_LIST_URL['ACCESS_TOKEN_URL'])
37 | accessTokenJson = accessToken.json()
38 | if dict(accessTokenJson).get('error') == 'invalid_client':
39 | return '获取accesstoken错误,请检查API_KEY,SECRET_KEY是否正确!'
40 | return accessTokenJson
41 |
42 |
43 | ACCESS_TOKEN = AccessToken().getToken()['access_token']
44 |
45 | LICENSE_PLATE_URL = URL_LIST_URL['FACE_PLATE'] + '?access_token={}'.format(ACCESS_TOKEN)
46 |
47 |
48 | class faceSuper(object):
49 | pass
50 |
51 |
52 | class face(faceSuper):
53 |
54 | def __init__(self, image=None, image2=None):
55 | self.HEADER = {
56 | 'Content-Type': 'application/json; charset=UTF-8',
57 | }
58 | if image is not None:
59 | imagepath = os.path.exists(image)
60 | if imagepath == True:
61 | images = image
62 | with open(images, 'rb') as images:
63 | img1 = base64.b64encode(images.read())
64 | else:
65 | print("img1 not exits")
66 | return
67 | if image2 is not None:
68 | imagepath2 = os.path.exists(image2)
69 | if imagepath2 == True:
70 | images2 = image2
71 | with open(images2, 'rb') as images2:
72 | img2 = base64.b64encode(images2.read())
73 | else:
74 | print("img2 not exits")
75 | return
76 | self.img = img1
77 | self.imgs = img2
78 | self.IMAGE_CONFIG1 = {"image": str(img1, 'utf-8'), "image_type": "BASE64"}
79 | self.IMAGE_CONFIG2 = {"image": str(img2, 'utf-8'), "image_type": "BASE64"}
80 | self.IMAGE_CONFIG = json.dumps([self.IMAGE_CONFIG1, self.IMAGE_CONFIG2])
81 |
82 | def postface(self):
83 | if (self.img==None and self.imgs==None):
84 | return 'image参数不能为空!'
85 | face = requests.post(url=LICENSE_PLATE_URL, headers=self.HEADER, data=self.IMAGE_CONFIG)
86 | return face.json()
87 |
88 |
89 | def facef(FA1, FA2):
90 | testAccessToken = AccessToken()
91 | testface = face(image=FA1, image2=FA2)
92 | result_json = testface.postface()
93 | result = result_json['result']['score']
94 | print('人脸相似度:', result)
95 | if result > 80:
96 | print("是同一个人")
97 | else:
98 | print("不是同一个人")
99 | return '人脸相似度:' + str(result), result
100 |
101 |
--------------------------------------------------------------------------------
/img_excel.py:
--------------------------------------------------------------------------------
1 | import xlrd
2 | import xlwt
3 | from xlutils import copy
4 |
5 | row = 0
6 | i = 0
7 |
8 |
9 | def create_excel():
10 | global row
11 | row = 0
12 | i = 0
13 | excel_path2 = "data.xls"
14 | w = xlwt.Workbook()
15 | w_sheet = w.add_sheet('1')
16 | alignment = xlwt.Alignment() #创建居中
17 | style = xlwt.XFStyle() # 创建样式
18 | alignment.horz = xlwt.Alignment.HORZ_CENTER
19 | alignment.vert = xlwt.Alignment.VERT_CENTER
20 | style.alignment = alignment # 给样式添加文字居中属性
21 | tall_style = xlwt.easyxf('font:height 720') # 36pt
22 | first_row = w_sheet.row(0)
23 | first_row.set_style(tall_style)
24 | value2 = ["时间", "形状识别车牌颜色", "形状识别车牌号", "颜色识别车牌颜色", "颜色识别车牌号", "api", "图像来源"]
25 | i = 0
26 | while (i <= 6):
27 | clo = i
28 | w_sheet.write(row, clo, value2[i], style)
29 | w_sheet.col(i).width = 7777
30 | i = i + 1
31 | w_sheet.col(6).width = 30000
32 | row = 1
33 | first_row = w_sheet.row(row)
34 | first_row.set_style(tall_style)
35 | w.save(excel_path2)
36 | print("excel创建成功")
37 |
38 |
39 | def excel_add(the_value):
40 | excel_path = "data.xls"
41 | rbook = xlrd.open_workbook(excel_path, formatting_info=True)
42 | wbook = copy.copy(rbook)
43 | w_sheet = wbook.get_sheet(0)
44 | alignment = xlwt.Alignment() #创建居中
45 | style = xlwt.XFStyle() # 创建样式
46 | alignment.horz = xlwt.Alignment.HORZ_CENTER
47 | alignment.vert = xlwt.Alignment.VERT_CENTER
48 | style.alignment = alignment # 给样式添加文字居中属性
49 | tall_style = xlwt.easyxf('font:height 720') # 36pt
50 | global row
51 | first_row = w_sheet.row(row)
52 | first_row.set_style(tall_style)
53 | i = 0
54 | while (i <= 6):
55 | clo = i
56 | w_sheet.write(row, clo, the_value[i], style)
57 | i = i + 1
58 | row = row + 1
59 | wbook.save(excel_path)
60 | print("excel写入成功")
61 |
--------------------------------------------------------------------------------
/img_function.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 | import cv2
5 | import numpy as np
6 | import img_math
7 | import img_recognition
8 |
9 | SZ = 20 # 训练图片长宽
10 | MAX_WIDTH = 1000 # 原始图片最大宽度
11 | Min_Area = 2000 # 车牌区域允许最大面积
12 | PROVINCE_START = 1000
13 |
14 |
15 | class StatModel(object):
16 | def load(self, fn):
17 | self.model = self.model.load(fn)
18 |
19 | def save(self, fn):
20 | self.model.save(fn)
21 |
22 |
23 | class SVM(StatModel):
24 | def __init__(self, C=1, gamma=0.5):
25 | self.model = cv2.ml.SVM_create()
26 | self.model.setGamma(gamma)
27 | self.model.setC(C)
28 | self.model.setKernel(cv2.ml.SVM_RBF)
29 | self.model.setType(cv2.ml.SVM_C_SVC)
30 |
31 | # 训练svm
32 | def train(self, samples, responses):
33 | self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)
34 |
35 | # 字符识别
36 | def predict(self, samples):
37 | r = self.model.predict(samples)
38 | return r[1].ravel()
39 |
40 |
41 | class CardPredictor:
42 | def __init__(self):
43 | pass
44 |
45 | def __del__(self):
46 | self.save_traindata()
47 |
48 | def train_svm(self):
49 | # 识别英文字母和数字
50 | self.model = SVM(C=1, gamma=0.5)
51 | # 识别中文
52 | self.modelchinese = SVM(C=1, gamma=0.5)
53 | if os.path.exists("svm.dat"):
54 | self.model.load("svm.dat")
55 | else:
56 | chars_train = []
57 | chars_label = []
58 |
59 | for root, dirs, files in os.walk("train\\chars2"):
60 | if len(os.path.basename(root)) > 1:
61 | continue
62 | root_int = ord(os.path.basename(root))
63 | for filename in files:
64 | filepath = os.path.join(root, filename)
65 | digit_img = cv2.imread(filepath)
66 | digit_img = cv2.cvtColor(digit_img, cv2.COLOR_BGR2GRAY)
67 | chars_train.append(digit_img)
68 | # chars_label.append(1)
69 | chars_label.append(root_int)
70 |
71 | chars_train = list(map(deskew, chars_train))
72 | chars_train = img_recognition.preprocess_hog(chars_train)
73 | # chars_train = chars_train.reshape(-1, 20, 20).astype(np.float32)
74 | chars_label = np.array(chars_label)
75 | print(chars_train.shape)
76 | self.model.train(chars_train, chars_label)
77 | if os.path.exists("svmchinese.dat"):
78 | self.modelchinese.load("svmchinese.dat")
79 | else:
80 | chars_train = []
81 | chars_label = []
82 | for root, dirs, files in os.walk("train\\charsChinese"):
83 | if not os.path.basename(root).startswith("zh_"):
84 | continue
85 | pinyin = os.path.basename(root)
86 | index = img_recognition.provinces.index(pinyin) + PROVINCE_START + 1 # 1是拼音对应的汉字
87 | for filename in files:
88 | filepath = os.path.join(root, filename)
89 | digit_img = cv2.imread(filepath)
90 | digit_img = cv2.cvtColor(digit_img, cv2.COLOR_BGR2GRAY)
91 | chars_train.append(digit_img)
92 | # chars_label.append(1)
93 | chars_label.append(index)
94 | chars_train = list(map(deskew, chars_train))
95 | chars_train = img_recognition.preprocess_hog(chars_train)
96 | # chars_train = chars_train.reshape(-1, 20, 20).astype(np.float32)
97 | chars_label = np.array(chars_label)
98 | print(chars_train.shape)
99 | self.modelchinese.train(chars_train, chars_label)
100 |
101 | def save_traindata(self):
102 | if not os.path.exists("svm.dat"):
103 | self.model.save("svm.dat")
104 | if not os.path.exists("svmchinese.dat"):
105 | self.modelchinese.save("svmchinese.dat")
106 |
107 | def img_first_pre(self, car_pic_file):
108 | """
109 | :param car_pic_file: 图像文件
110 | :return:已经处理好的图像文件 原图像文件
111 | """
112 | if type(car_pic_file) == type(""):
113 | img = img_math.img_read(car_pic_file)
114 | else:
115 | img = car_pic_file
116 |
117 | pic_hight, pic_width = img.shape[:2]
118 | if pic_width > MAX_WIDTH:
119 | resize_rate = MAX_WIDTH / pic_width
120 | img = cv2.resize(img, (MAX_WIDTH, int(pic_hight * resize_rate)), interpolation=cv2.INTER_AREA)
121 | # 缩小图片
122 |
123 | blur = 5
124 | img = cv2.GaussianBlur(img, (blur, blur), 0)
125 | oldimg = img
126 | img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
127 | # 转化成灰度图像
128 |
129 | Matrix = np.ones((20, 20), np.uint8)
130 | img_opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, Matrix)
131 | img_opening = cv2.addWeighted(img, 1, img_opening, -1, 0)
132 | # 创建20*20的元素为1的矩阵 开操作,并和img重合
133 |
134 | ret, img_thresh = cv2.threshold(img_opening, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
135 | img_edge = cv2.Canny(img_thresh, 100, 200)
136 | # Otsu’s二值化 找到图像边缘
137 |
138 | Matrix = np.ones((4, 19), np.uint8)
139 | img_edge1 = cv2.morphologyEx(img_edge, cv2.MORPH_CLOSE, Matrix)
140 | img_edge2 = cv2.morphologyEx(img_edge1, cv2.MORPH_OPEN, Matrix)
141 | return img_edge2, oldimg
142 |
143 | def img_color_contours(self, img_contours, oldimg):
144 | """
145 | :param img_contours: 预处理好的图像
146 | :param oldimg: 原图像
147 | :return: 已经定位好的车牌
148 | """
149 |
150 | if img_contours.any():
151 | #config.set_name(img_contours)
152 | cv2.imwrite("tmp/img_contours.jpg", img_contours)
153 |
154 | pic_hight, pic_width = img_contours.shape[:2]
155 |
156 | card_contours = img_math.img_findContours(img_contours)
157 | card_imgs = img_math.img_Transform(card_contours, oldimg, pic_width, pic_hight)
158 | colors, car_imgs = img_math.img_color(card_imgs)
159 | predict_result = []
160 | predict_str = ""
161 | roi = None
162 | card_color = None
163 |
164 | for i, color in enumerate(colors):
165 | if color in ("blue", "yello", "green"):
166 | card_img = card_imgs[i]
167 | gray_img = cv2.cvtColor(card_img, cv2.COLOR_BGR2GRAY)
168 | # 黄、绿车牌字符比背景暗、与蓝车牌刚好相反,所以黄、绿车牌需要反向
169 | if color == "green" or color == "yello":
170 | gray_img = cv2.bitwise_not(gray_img)
171 | ret, gray_img = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
172 | x_histogram = np.sum(gray_img, axis=1)
173 | x_min = np.min(x_histogram)
174 | x_average = np.sum(x_histogram) / x_histogram.shape[0]
175 | x_threshold = (x_min + x_average) / 2
176 |
177 | wave_peaks = img_math.find_waves(x_threshold, x_histogram)
178 | if len(wave_peaks) == 0:
179 | print("peak less 0:")
180 | continue
181 | # 认为水平方向,最大的波峰为车牌区域
182 | wave = max(wave_peaks, key=lambda x: x[1] - x[0])
183 | gray_img = gray_img[wave[0]:wave[1]]
184 | # 查找垂直直方图波峰
185 | row_num, col_num = gray_img.shape[:2]
186 | # 去掉车牌上下边缘1个像素,避免白边影响阈值判断
187 | gray_img = gray_img[1:row_num - 1]
188 | y_histogram = np.sum(gray_img, axis=0)
189 | y_min = np.min(y_histogram)
190 | y_average = np.sum(y_histogram) / y_histogram.shape[0]
191 | y_threshold = (y_min + y_average) / 5 # U和0要求阈值偏小,否则U和0会被分成两半
192 | wave_peaks = img_math.find_waves(y_threshold, y_histogram)
193 | if len(wave_peaks) <= 6:
194 | print("peak less 1:", len(wave_peaks))
195 | continue
196 |
197 | wave = max(wave_peaks, key=lambda x: x[1] - x[0])
198 | max_wave_dis = wave[1] - wave[0]
199 | # 判断是否是左侧车牌边缘
200 | if wave_peaks[0][1] - wave_peaks[0][0] < max_wave_dis / 3 and wave_peaks[0][0] == 0:
201 | wave_peaks.pop(0)
202 |
203 | # 组合分离汉字
204 | cur_dis = 0
205 | for i, wave in enumerate(wave_peaks):
206 | if wave[1] - wave[0] + cur_dis > max_wave_dis * 0.6:
207 | break
208 | else:
209 | cur_dis += wave[1] - wave[0]
210 | if i > 0:
211 | wave = (wave_peaks[0][0], wave_peaks[i][1])
212 | wave_peaks = wave_peaks[i + 1:]
213 | wave_peaks.insert(0, wave)
214 | point = wave_peaks[2]
215 | point_img = gray_img[:, point[0]:point[1]]
216 | if np.mean(point_img) < 255 / 5:
217 | wave_peaks.pop(2)
218 |
219 | if len(wave_peaks) <= 6:
220 | print("peak less 2:", len(wave_peaks))
221 | continue
222 |
223 | part_cards = img_math.seperate_card(gray_img, wave_peaks)
224 | for i, part_card in enumerate(part_cards):
225 | # 可能是固定车牌的铆钉
226 |
227 | if np.mean(part_card) < 255 / 5:
228 | print("a point")
229 | continue
230 | part_card_old = part_card
231 |
232 | w = abs(part_card.shape[1] - SZ) // 2
233 |
234 | part_card = cv2.copyMakeBorder(part_card, 0, 0, w, w, cv2.BORDER_CONSTANT, value=[0, 0, 0])
235 | part_card = cv2.resize(part_card, (SZ, SZ), interpolation=cv2.INTER_AREA)
236 | part_card = img_recognition.preprocess_hog([part_card])
237 | if i == 0:
238 | resp = self.modelchinese.predict(part_card)
239 | charactor = img_recognition.provinces[int(resp[0]) - PROVINCE_START]
240 | else:
241 | resp = self.model.predict(part_card)
242 | charactor = chr(resp[0])
243 | # 判断最后一个数是否是车牌边缘,假设车牌边缘被认为是1
244 | if charactor == "1" and i == len(part_cards) - 1:
245 | if part_card_old.shape[0] / part_card_old.shape[1] >= 7: # 1太细,认为是边缘
246 | continue
247 | predict_result.append(charactor)
248 | predict_str = "".join(predict_result)
249 |
250 | roi = card_img
251 | card_color = color
252 | break
253 |
254 | return predict_str, roi, card_color # 识别到的字符、定位的车牌图像、车牌颜色
255 |
256 | def img_only_color(self, filename, oldimg, img_contours):
257 | """
258 | :param filename: 图像文件
259 | :param oldimg: 原图像文件
260 | :return: 已经定位好的车牌
261 | """
262 | pic_hight, pic_width = img_contours.shape[:2]
263 | lower_blue = np.array([100, 110, 110])
264 | upper_blue = np.array([130, 255, 255])
265 | lower_yellow = np.array([15, 55, 55])
266 | upper_yellow = np.array([50, 255, 255])
267 | lower_green = np.array([50, 50, 50])
268 | upper_green = np.array([100, 255, 255])
269 | hsv = cv2.cvtColor(filename, cv2.COLOR_BGR2HSV)
270 | mask_blue = cv2.inRange(hsv, lower_blue, upper_blue)
271 | mask_yellow = cv2.inRange(hsv, lower_yellow, upper_yellow)
272 | mask_green = cv2.inRange(hsv, lower_yellow, upper_green)
273 | output = cv2.bitwise_and(hsv, hsv, mask=mask_blue + mask_yellow + mask_green)
274 | # 根据阈值找到对应颜色
275 |
276 | output = cv2.cvtColor(output, cv2.COLOR_BGR2GRAY)
277 | Matrix = np.ones((20, 20), np.uint8)
278 | img_edge1 = cv2.morphologyEx(output, cv2.MORPH_CLOSE, Matrix)
279 | img_edge2 = cv2.morphologyEx(img_edge1, cv2.MORPH_OPEN, Matrix)
280 |
281 | card_contours = img_math.img_findContours(img_edge2)
282 | card_imgs = img_math.img_Transform(card_contours, oldimg, pic_width, pic_hight)
283 | colors, car_imgs = img_math.img_color(card_imgs)
284 |
285 | predict_result = []
286 | predict_str = ""
287 | roi = None
288 | card_color = None
289 |
290 | for i, color in enumerate(colors):
291 |
292 | if color in ("blue", "yello", "green"):
293 | card_img = card_imgs[i]
294 |
295 | try:
296 | gray_img = cv2.cvtColor(card_img, cv2.COLOR_BGR2GRAY)
297 | except:
298 | print("gray转换失败")
299 |
300 | # 黄、绿车牌字符比背景暗、与蓝车牌刚好相反,所以黄、绿车牌需要反向
301 | if color == "green" or color == "yello":
302 | gray_img = cv2.bitwise_not(gray_img)
303 | ret, gray_img = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
304 | x_histogram = np.sum(gray_img, axis=1)
305 |
306 | x_min = np.min(x_histogram)
307 | x_average = np.sum(x_histogram) / x_histogram.shape[0]
308 | x_threshold = (x_min + x_average) / 2
309 | wave_peaks = img_math.find_waves(x_threshold, x_histogram)
310 | if len(wave_peaks) == 0:
311 | print("peak less 0:")
312 | continue
313 | # 认为水平方向,最大的波峰为车牌区域
314 | wave = max(wave_peaks, key=lambda x: x[1] - x[0])
315 | gray_img = gray_img[wave[0]:wave[1]]
316 | # 查找垂直直方图波峰
317 | row_num, col_num = gray_img.shape[:2]
318 | # 去掉车牌上下边缘1个像素,避免白边影响阈值判断
319 | gray_img = gray_img[1:row_num - 1]
320 | y_histogram = np.sum(gray_img, axis=0)
321 | y_min = np.min(y_histogram)
322 | y_average = np.sum(y_histogram) / y_histogram.shape[0]
323 | y_threshold = (y_min + y_average) / 5 # U和0要求阈值偏小,否则U和0会被分成两半
324 | wave_peaks = img_math.find_waves(y_threshold, y_histogram)
325 | if len(wave_peaks) < 6:
326 | print("peak less 1:", len(wave_peaks))
327 | continue
328 |
329 | wave = max(wave_peaks, key=lambda x: x[1] - x[0])
330 | max_wave_dis = wave[1] - wave[0]
331 | # 判断是否是左侧车牌边缘
332 | if wave_peaks[0][1] - wave_peaks[0][0] < max_wave_dis / 3 and wave_peaks[0][0] == 0:
333 | wave_peaks.pop(0)
334 |
335 | # 组合分离汉字
336 | cur_dis = 0
337 | for i, wave in enumerate(wave_peaks):
338 | if wave[1] - wave[0] + cur_dis > max_wave_dis * 0.6:
339 | break
340 | else:
341 | cur_dis += wave[1] - wave[0]
342 | if i > 0:
343 | wave = (wave_peaks[0][0], wave_peaks[i][1])
344 | wave_peaks = wave_peaks[i + 1:]
345 | wave_peaks.insert(0, wave)
346 |
347 | point = wave_peaks[2]
348 | point_img = gray_img[:, point[0]:point[1]]
349 | if np.mean(point_img) < 255 / 5:
350 | wave_peaks.pop(2)
351 |
352 | if len(wave_peaks) <= 6:
353 | print("peak less 2:", len(wave_peaks))
354 | continue
355 |
356 | part_cards = img_math.seperate_card(gray_img, wave_peaks)
357 |
358 | for i, part_card in enumerate(part_cards):
359 | # 可能是固定车牌的铆钉
360 |
361 | if np.mean(part_card) < 255 / 5:
362 | print("a point")
363 | continue
364 | part_card_old = part_card
365 |
366 | w = abs(part_card.shape[1] - SZ) // 2
367 |
368 | part_card = cv2.copyMakeBorder(part_card, 0, 0, w, w, cv2.BORDER_CONSTANT, value=[0, 0, 0])
369 | part_card = cv2.resize(part_card, (SZ, SZ), interpolation=cv2.INTER_AREA)
370 | part_card = img_recognition.preprocess_hog([part_card])
371 | if i == 0:
372 | resp = self.modelchinese.predict(part_card)
373 | charactor = img_recognition.provinces[int(resp[0]) - PROVINCE_START]
374 | else:
375 | resp = self.model.predict(part_card)
376 | charactor = chr(resp[0])
377 | # 判断最后一个数是否是车牌边缘,假设车牌边缘被认为是1
378 | if charactor == "1" and i == len(part_cards) - 1:
379 | if part_card_old.shape[0] / part_card_old.shape[1] >= 7: # 1太细,认为是边缘
380 | continue
381 | predict_result.append(charactor)
382 | predict_str = "".join(predict_result)
383 |
384 | roi = card_img
385 | card_color = color
386 | break
387 | return predict_str, roi, card_color # 识别到的字符、定位的车牌图像、车牌颜色
388 |
389 | def img_mser(self, filename):
390 | if type(filename) == type(""):
391 | img = img_math.img_read(filename)
392 | else:
393 | img = filename
394 | oldimg = img
395 | mser = cv2.MSER_create(_min_area=600)
396 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
397 | regions, boxes = mser.detectRegions(gray)
398 | colors_img = []
399 | for box in boxes:
400 | x, y, w, h = box
401 | width, height = w, h
402 | if width < height:
403 | width, height = height, width
404 | ration = width / height
405 |
406 | if w * h > 1500 and 3 < ration < 4 and w > h:
407 | cropimg = img[y:y + h, x:x + w]
408 | colors_img.append(cropimg)
409 |
410 |
--------------------------------------------------------------------------------
/img_math.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import cv2
4 | import numpy as np
5 |
6 | MAX_WIDTH = 1000
7 | Min_Area = 2000
8 | SZ = 20
9 | PROVINCE_START = 1000
10 | """
11 | 该文件包含读文件函数
12 | 取零值函数
13 | 矩阵校正函数
14 | 颜色判断函数
15 | """
16 |
17 |
18 | def img_read(filename):
19 | return cv2.imdecode(np.fromfile(filename, dtype=np.uint8), cv2.IMREAD_COLOR)
20 | # 以uint8方式读取filename 放入imdecode中,cv2.IMREAD_COLOR读取彩色照片
21 |
22 |
23 | def find_waves(threshold, histogram):
24 | up_point = -1 # 上升点
25 | is_peak = False
26 | if histogram[0] > threshold:
27 | up_point = 0
28 | is_peak = True
29 | wave_peaks = []
30 | for i, x in enumerate(histogram):
31 | if is_peak and x < threshold:
32 | if i - up_point > 2:
33 | is_peak = False
34 | wave_peaks.append((up_point, i))
35 | elif not is_peak and x >= threshold:
36 | is_peak = True
37 | up_point = i
38 | if is_peak and up_point != -1 and i - up_point > 4:
39 | wave_peaks.append((up_point, i))
40 | return wave_peaks
41 |
42 |
43 | def point_limit(point):
44 | if point[0] < 0:
45 | point[0] = 0
46 | if point[1] < 0:
47 | point[1] = 0
48 |
49 |
50 | def accurate_place(card_img_hsv, limit1, limit2, color):
51 | row_num, col_num = card_img_hsv.shape[:2]
52 | xl = col_num
53 | xr = 0
54 | yh = 0
55 | yl = row_num
56 | row_num_limit = 21
57 | col_num_limit = col_num * 0.8 if color != "green" else col_num * 0.5 # 绿色有渐变
58 | for i in range(row_num):
59 | count = 0
60 | for j in range(col_num):
61 | H = card_img_hsv.item(i, j, 0)
62 | S = card_img_hsv.item(i, j, 1)
63 | V = card_img_hsv.item(i, j, 2)
64 | if limit1 < H <= limit2 and 34 < S and 46 < V:
65 | count += 1
66 | if count > col_num_limit:
67 | if yl > i:
68 | yl = i
69 | if yh < i:
70 | yh = i
71 | for j in range(col_num):
72 | count = 0
73 | for i in range(row_num):
74 | H = card_img_hsv.item(i, j, 0)
75 | S = card_img_hsv.item(i, j, 1)
76 | V = card_img_hsv.item(i, j, 2)
77 | if limit1 < H <= limit2 and 34 < S and 46 < V:
78 | count += 1
79 | if count > row_num - row_num_limit:
80 | if xl > j:
81 | xl = j
82 | if xr < j:
83 | xr = j
84 | return xl, xr, yh, yl
85 |
86 |
87 | def img_findContours(img_contours):
88 | img, contours, hierarchy = cv2.findContours(img_contours, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
89 | contours = [cnt for cnt in contours if cv2.contourArea(cnt) > Min_Area]
90 | print("findContours len = ", len(contours))
91 | # 排除面积最小的点
92 | car_contours = []
93 | for cnt in contours:
94 | ant = cv2.minAreaRect(cnt)
95 | width, height = ant[1]
96 | if width < height:
97 | width, height = height, width
98 | ration = width / height
99 |
100 | if 2 < ration < 5.5:
101 | car_contours.append(ant)
102 | box = cv2.boxPoints(ant)
103 |
104 | return car_contours
105 |
106 | #进行矩形矫正
107 | def img_Transform(car_contours, oldimg, pic_width, pic_hight):
108 | car_imgs = []
109 | for car_rect in car_contours:
110 | if -1 < car_rect[2] < 1:
111 | angle = 1
112 | # 对于角度为-1 1之间时,默认为1
113 | else:
114 | angle = car_rect[2]
115 | car_rect = (car_rect[0], (car_rect[1][0] + 5, car_rect[1][1] + 5), angle)
116 | box = cv2.boxPoints(car_rect)
117 |
118 | heigth_point = right_point = [0, 0]
119 | left_point = low_point = [pic_width, pic_hight]
120 | for point in box:
121 | if left_point[0] > point[0]:
122 | left_point = point
123 | if low_point[1] > point[1]:
124 | low_point = point
125 | if heigth_point[1] < point[1]:
126 | heigth_point = point
127 | if right_point[0] < point[0]:
128 | right_point = point
129 |
130 | if left_point[1] <= right_point[1]: # 正角度
131 | new_right_point = [right_point[0], heigth_point[1]]
132 | pts2 = np.float32([left_point, heigth_point, new_right_point]) # 字符只是高度需要改变
133 | pts1 = np.float32([left_point, heigth_point, right_point])
134 | M = cv2.getAffineTransform(pts1, pts2)
135 | dst = cv2.warpAffine(oldimg, M, (pic_width, pic_hight))
136 | point_limit(new_right_point)
137 | point_limit(heigth_point)
138 | point_limit(left_point)
139 | car_img = dst[int(left_point[1]):int(heigth_point[1]), int(left_point[0]):int(new_right_point[0])]
140 | car_imgs.append(car_img)
141 |
142 | elif left_point[1] > right_point[1]: # 负角度
143 | new_left_point = [left_point[0], heigth_point[1]]
144 | pts2 = np.float32([new_left_point, heigth_point, right_point]) # 字符只是高度需要改变
145 | pts1 = np.float32([left_point, heigth_point, right_point])
146 | M = cv2.getAffineTransform(pts1, pts2)
147 | dst = cv2.warpAffine(oldimg, M, (pic_width, pic_hight))
148 | point_limit(right_point)
149 | point_limit(heigth_point)
150 | point_limit(new_left_point)
151 | car_img = dst[int(right_point[1]):int(heigth_point[1]), int(new_left_point[0]):int(right_point[0])]
152 | car_imgs.append(car_img)
153 |
154 | return car_imgs
155 |
156 |
157 | def img_color(card_imgs):
158 | colors = []
159 | for card_index, card_img in enumerate(card_imgs):
160 |
161 | green = yello = blue = black = white = 0
162 | try:
163 | card_img_hsv = cv2.cvtColor(card_img, cv2.COLOR_BGR2HSV)
164 | except:
165 | print("矫正矩形出错, 转换失败")
166 | # 有转换失败的可能,原因来自于上面矫正矩形出错
167 |
168 | if card_img_hsv is None:
169 | continue
170 | row_num, col_num = card_img_hsv.shape[:2]
171 | card_img_count = row_num * col_num
172 |
173 | for i in range(row_num):
174 | for j in range(col_num):
175 | H = card_img_hsv.item(i, j, 0)
176 | S = card_img_hsv.item(i, j, 1)
177 | V = card_img_hsv.item(i, j, 2)
178 | if 11 < H <= 34 and S > 34:
179 | yello += 1
180 | elif 35 < H <= 99 and S > 34:
181 | green += 1
182 | elif 99 < H <= 124 and S > 34:
183 | blue += 1
184 |
185 | if 0 < H < 180 and 0 < S < 255 and 0 < V < 46:
186 | black += 1
187 | elif 0 < H < 180 and 0 < S < 43 and 221 < V < 225:
188 | white += 1
189 | color = "no"
190 |
191 | limit1 = limit2 = 0
192 | if yello * 2 >= card_img_count:
193 | color = "yello"
194 | limit1 = 11
195 | limit2 = 34 # 有的图片有色偏偏绿
196 | elif green * 2 >= card_img_count:
197 | color = "green"
198 | limit1 = 35
199 | limit2 = 99
200 | elif blue * 2 >= card_img_count:
201 | color = "blue"
202 | limit1 = 100
203 | limit2 = 124 # 有的图片有色偏偏紫
204 | elif black + white >= card_img_count * 0.7:
205 | color = "bw"
206 | colors.append(color)
207 | card_imgs[card_index] = card_img
208 |
209 | if limit1 == 0:
210 | continue
211 | xl, xr, yh, yl = accurate_place(card_img_hsv, limit1, limit2, color)
212 | if yl == yh and xl == xr:
213 | continue
214 | need_accurate = False
215 | if yl >= yh:
216 | yl = 0
217 | yh = row_num
218 | need_accurate = True
219 | if xl >= xr:
220 | xl = 0
221 | xr = col_num
222 | need_accurate = True
223 |
224 | if color == "green":
225 | card_imgs[card_index] = card_img
226 | else:
227 | card_imgs[card_index] = card_img[yl:yh, xl:xr] if color != "green" or yl < (yh - yl) // 4 else card_img[
228 | yl - (
229 | yh - yl) // 4:yh,
230 | xl:xr]
231 |
232 | if need_accurate:
233 | card_img = card_imgs[card_index]
234 | card_img_hsv = cv2.cvtColor(card_img, cv2.COLOR_BGR2HSV)
235 | xl, xr, yh, yl = accurate_place(card_img_hsv, limit1, limit2, color)
236 | if yl == yh and xl == xr:
237 | continue
238 | if yl >= yh:
239 | yl = 0
240 | yh = row_num
241 | if xl >= xr:
242 | xl = 0
243 | xr = col_num
244 | if color == "green":
245 | card_imgs[card_index] = card_img
246 | else:
247 | card_imgs[card_index] = card_img[yl:yh, xl:xr] if color != "green" or yl < (yh - yl) // 4 else card_img[
248 | yl - (
249 | yh - yl) // 4:yh,
250 | xl:xr]
251 |
252 | return colors, card_imgs
253 |
254 |
255 | # 根据设定的阈值和图片直方图,找出波峰,用于分隔字符
256 | def find_waves(threshold, histogram):
257 | up_point = -1 # 上升点
258 | is_peak = False
259 | if histogram[0] > threshold:
260 | up_point = 0
261 | is_peak = True
262 | wave_peaks = []
263 | for i, x in enumerate(histogram):
264 | if is_peak and x < threshold:
265 | if i - up_point > 2:
266 | is_peak = False
267 | wave_peaks.append((up_point, i))
268 | elif not is_peak and x >= threshold:
269 | is_peak = True
270 | up_point = i
271 | if is_peak and up_point != -1 and i - up_point > 4:
272 | wave_peaks.append((up_point, i))
273 | return wave_peaks
274 |
275 | #分离车牌字符
276 | def seperate_card(img, waves):
277 | part_cards = []
278 | for wave in waves:
279 | part_cards.append(img[:, wave[0]:wave[1]])
280 |
281 | return part_cards
282 |
283 |
284 | def img_mser_color(card_imgs):
285 | colors = []
286 | for card_index, card_img in enumerate(card_imgs):
287 | green = yello = blue = black = white = 0
288 | card_img_hsv = cv2.cvtColor(card_img, cv2.COLOR_BGR2HSV)
289 | if card_img_hsv is None:
290 | continue
291 | row_num, col_num = card_img_hsv.shape[:2]
292 | card_img_count = row_num * col_num
293 | for i in range(row_num):
294 | for j in range(col_num):
295 | H = card_img_hsv.item(i, j, 0)
296 | S = card_img_hsv.item(i, j, 1)
297 | V = card_img_hsv.item(i, j, 2)
298 | if 11 < H <= 34 and S > 34:
299 | yello += 1
300 | elif 35 < H <= 99 and S > 34:
301 | green += 1
302 | elif 99 < H <= 124 and S > 34:
303 | blue += 1
304 | if 0 < H < 180 and 0 < S < 255 and 0 < V < 46:
305 | black += 1
306 | elif 0 < H < 180 and 0 < S < 43 and 221 < V < 225:
307 | white += 1
308 | color = "no"
309 | if yello * 2 >= card_img_count:
310 | color = "yello"
311 |
312 | elif green * 2 >= card_img_count:
313 | color = "green"
314 |
315 | elif blue * 2 >= card_img_count:
316 | color = "blue"
317 |
318 | elif black + white >= card_img_count * 0.7:
319 | color = "bw"
320 | colors.append(color)
321 | card_imgs[card_index] = card_img
322 | return colors, card_imgs
323 |
--------------------------------------------------------------------------------
/img_recognition.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | __author__ = '樱花落舞'
3 | import cv2
4 | import numpy as np
5 | from numpy.linalg import norm
6 |
7 | SZ = 20 # 训练图片长宽
8 | MAX_WIDTH = 1000 # 原始图片最大宽度
9 | Min_Area = 2000 # 车牌区域允许最大面积
10 | PROVINCE_START = 1000
11 | # 来自opencv的sample,用于svm训练
12 | def deskew(img):
13 | m = cv2.moments(img)
14 | if abs(m['mu02']) < 1e-2:
15 | return img.copy()
16 | skew = m['mu11'] / m['mu02']
17 | M = np.float32([[1, skew, -0.5 * SZ * skew], [0, 1, 0]])
18 | img = cv2.warpAffine(img, M, (SZ, SZ), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_LINEAR)
19 | return img
20 |
21 |
22 | # 来自opencv的sample,用于svm训练
23 | def preprocess_hog(digits):
24 | samples = []
25 | for img in digits:
26 | gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
27 | gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
28 | mag, ang = cv2.cartToPolar(gx, gy)
29 | bin_n = 16
30 | bin = np.int32(bin_n * ang / (2 * np.pi))
31 | bin_cells = bin[:10, :10], bin[10:, :10], bin[:10, 10:], bin[10:, 10:]
32 | mag_cells = mag[:10, :10], mag[10:, :10], mag[:10, 10:], mag[10:, 10:]
33 | hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
34 | hist = np.hstack(hists)
35 |
36 | # transform to Hellinger kernel
37 | eps = 1e-7
38 | hist /= hist.sum() + eps
39 | hist = np.sqrt(hist)
40 | hist /= norm(hist) + eps
41 |
42 | samples.append(hist)
43 | return np.float32(samples)
44 |
45 |
46 | provinces = [
47 | "zh_cuan", "川",
48 | "zh_e", "鄂",
49 | "zh_gan", "赣",
50 | "zh_gan1", "甘",
51 | "zh_gui", "贵",
52 | "zh_gui1", "桂",
53 | "zh_hei", "黑",
54 | "zh_hu", "沪",
55 | "zh_ji", "冀",
56 | "zh_jin", "津",
57 | "zh_jing", "京",
58 | "zh_jl", "吉",
59 | "zh_liao", "辽",
60 | "zh_lu", "鲁",
61 | "zh_meng", "蒙",
62 | "zh_min", "闽",
63 | "zh_ning", "宁",
64 | "zh_qing", "青",
65 | "zh_qiong", "琼",
66 | "zh_shan", "陕",
67 | "zh_su", "苏",
68 | "zh_sx", "晋",
69 | "zh_wan", "皖",
70 | "zh_xiang", "湘",
71 | "zh_xin", "新",
72 | "zh_yu", "豫",
73 | "zh_yu1", "渝",
74 | "zh_yue", "粤",
75 | "zh_yun", "云",
76 | "zh_zang", "藏",
77 | "zh_zhe", "浙"
78 | ]
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/img_sql.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | import pymysql
4 |
5 |
6 | def sql(TIME, COLOR1, TEXT1, COLOR2, TEXT2, API, SOURCE):
7 | try:
8 | # 打开数据库连接
9 | db = pymysql.connect("localhost", "python", "Python12345@", "chepai")
10 | except:
11 | print("数据库连接失败")
12 | return
13 | # 使用cursor()方法获取操作游标
14 | cursor = db.cursor()
15 |
16 | # SQL 插入语句
17 | sql = "INSERT INTO CARINFO(TIME, \
18 | COLOR1, TEXT1, COLOR2, TEXT2, API, SOURCE) \
19 | VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s')" % \
20 | (TIME, COLOR1, TEXT1, COLOR2, TEXT2, API, SOURCE)
21 |
22 | try:
23 | # 执行sql语句
24 | cursor.execute(sql)
25 | # 提交到数据库执行
26 | db.commit()
27 | print("数据库写入成功")
28 | except:
29 | # 如果发生错误则回滚
30 | db.rollback()
31 | print("数据库写入失败")
32 |
33 | # 关闭数据库连接
34 | db.close()
35 |
36 |
37 | def create_sql():
38 | try:
39 | # 打开数据库连接
40 | db = pymysql.connect("localhost", "python", "Python12345@", "chepai")
41 | except:
42 | print("数据库连接失败")
43 | return
44 | # 使用 cursor() 方法创建一个游标对象 cursor
45 | cursor = db.cursor()
46 |
47 | # 使用预处理语句创建表
48 | sql = """CREATE TABLE CARINFO (
49 | TIME VARCHAR(100),
50 | COLOR1 VARCHAR(100),
51 | TEXT1 VARCHAR(100),
52 | COLOR2 VARCHAR(100),
53 | TEXT2 VARCHAR(100),
54 | API VARCHAR(100),
55 | SOURCE VARCHAR(500))"""
56 |
57 | try:
58 | # 执行sql语句
59 | cursor.execute(sql)
60 | # 提交到数据库执行
61 | db.commit()
62 | print("数据库创建成功")
63 | except:
64 | # 如果发生错误则回滚
65 | db.rollback()
66 | print("数据库已存在")
67 |
68 | # 关闭数据库连接
69 | db.close()
70 |
71 |
72 | def select_sql(NAME):
73 | # 打开数据库连接
74 | try:
75 | # 打开数据库连接
76 | db = pymysql.connect("localhost", "python", "Python12345@", "chepai")
77 | except:
78 | print("注册数据库连接失败")
79 | return
80 |
81 | # 使用cursor()方法获取操作游标
82 | cursor = db.cursor()
83 |
84 | # SQL 查询语句
85 | sql = "SELECT PASSWORD FROM USERS \
86 | WHERE NAME = ('%s')" % (NAME)
87 |
88 | try:
89 | # 执行SQL语句
90 | cursor.execute(sql)
91 | # 获取所有记录列表
92 | results = cursor.fetchall()
93 | for row in results:
94 | password = row[0]
95 | # 打印结果
96 | # print("password=%s" %(password))
97 | # print(password)
98 | return password
99 | except:
100 | return 0
101 |
102 | # 关闭数据库连接
103 | db.close()
104 |
105 |
106 | def sign_sql(NAME, PASSWORD):
107 | # 打开数据库连接
108 | try:
109 | # 打开数据库连接
110 | db = pymysql.connect("localhost", "python", "Python12345@", "chepai")
111 | except:
112 | print("注册数据库连接失败")
113 | return
114 |
115 | # 使用cursor()方法获取操作游标
116 | cursor = db.cursor()
117 |
118 | # SQL 插入语句
119 | sql = "INSERT INTO USERS(NAME, PASSWORD) VALUES ('%s', '%s')" %(NAME, PASSWORD)
120 |
121 | try:
122 | # 执行sql语句
123 | cursor.execute(sql)
124 | # 提交到数据库执行
125 | db.commit()
126 | print("注册数据库写入成功")
127 | except:
128 | # 如果发生错误则回滚
129 | db.rollback()
130 | print("注册数据库写入失败")
131 |
132 | # 关闭数据库连接
133 | db.close()
134 |
135 |
136 | def create_signsql():
137 | try:
138 | # 打开数据库连接
139 | db = pymysql.connect("localhost", "python", "Python12345@", "chepai")
140 | except:
141 | print("数据库连接失败")
142 | return
143 | # 使用 cursor() 方法创建一个游标对象 cursor
144 | cursor = db.cursor()
145 |
146 | # 使用预处理语句创建表
147 | sql = """CREATE TABLE USERS (
148 | NAME VARCHAR(100),
149 | PASSWORD VARCHAR(100))"""
150 |
151 | try:
152 | # 执行sql语句
153 | cursor.execute(sql)
154 | # 提交到数据库执行
155 | db.commit()
156 | print("注册数据库创建成功")
157 | except:
158 | # 如果发生错误则回滚
159 | db.rollback()
160 | print("注册数据库已存在")
161 |
162 | # 关闭数据库连接
163 | db.close()
164 |
--------------------------------------------------------------------------------
/login.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import tkinter as tk
4 | from tkinter import ttk
5 | from tkinter.filedialog import *
6 | import tkinter.messagebox
7 | from PIL import Image, ImageTk
8 | import os
9 | import img_sql
10 |
11 |
12 | class Login(ttk.Frame):
13 | thread_run = False
14 | img_sql.create_signsql()
15 |
16 | def __init__(self, win):
17 | ttk.Frame.__init__(self, win)
18 | frame1 = ttk.Frame(self)
19 | frame2 = ttk.Frame(self)
20 | frame3 = ttk.Frame(self)
21 | win.title("车牌识别")
22 | win.minsize(850, 600)
23 | self.center_window()
24 |
25 | self.pilImage = Image.open("./pic/login.png")
26 | self.tkImage = ImageTk.PhotoImage(image=self.pilImage)
27 | self.image233 = tk.Label(win, image=self.tkImage)
28 | self.image233.pack(side=TOP)
29 |
30 | frame1.pack(side=TOP, fill=tk.Y, expand=1)
31 | frame2.pack(side=TOP, fill=tk.Y, expand=1)
32 | frame3.pack(side=TOP, fill=tk.Y, expand=1)
33 |
34 | # 创建一个`label`名为`Account: `
35 | self.label_account = ttk.Label(frame1, text='账号: ')
36 | self.label_account.pack(side=LEFT)
37 | # 创建一个账号输入框,并设置尺寸
38 | self.input_account = ttk.Entry(frame1, width=30)
39 | self.input_account.pack(side=RIGHT)
40 | # 创建一个`label`名为`Password: `
41 | self.label_password = ttk.Label(frame2, text='密码: ')
42 | self.label_password.pack(side=LEFT)
43 | # 创建一个密码输入框,并设置尺寸
44 | self.input_password = ttk.Entry(frame2, show='*', width=30)
45 | self.input_password.pack(side=RIGHT)
46 | self.input_password.bind('', self.login)
47 | # 创建一个注册系统的按钮
48 | self.signup_button = ttk.Button(frame3, text="注册", width=15, command=self.signup_interface)
49 | self.signup_button.pack(side=LEFT)
50 | # 创建一个注册系统的按钮
51 | self.login_button = ttk.Button(frame3, text="登录", width=15, command=self.backstage_interface)
52 | self.login_button.pack(side=RIGHT)
53 |
54 | self.pack(fill=tk.BOTH, expand=tk.YES, padx="10", pady="10")
55 |
56 | def center_window(self):
57 | screenwidth = log.winfo_screenwidth()
58 | screenheight = log.winfo_screenheight()
59 | log.update()
60 | width = log.winfo_width()
61 | height = log.winfo_height()
62 | size = '+%d+%d' % ((screenwidth - width)/2, (screenheight - height)/2)
63 | log.geometry(size)
64 |
65 | def signup_interface(self):
66 | account = self.input_account.get()
67 | password = self.input_password.get()
68 | if (account == ""):
69 | tkinter.messagebox.showinfo(title='车牌识别管理系统', message='账号不能为空')
70 | return
71 | if (password == ""):
72 | tkinter.messagebox.showinfo(title='车牌识别管理系统', message='密码不能为空')
73 | return
74 | if img_sql.select_sql(account):
75 | tkinter.messagebox.showinfo(title='车牌识别管理系统', message='用户名已注册')
76 | return
77 | img_sql.sign_sql(account, password)
78 | tkinter.messagebox.showinfo(title='车牌识别管理系统', message='注册成功,请登录')
79 |
80 | def backstage_interface(self):
81 | account = self.input_account.get()
82 | password = self.input_password.get()
83 | if not img_sql.select_sql(account):
84 | tkinter.messagebox.showinfo(title='车牌识别管理系统', message='用户名未注册')
85 | return
86 | if (password == img_sql.select_sql(account)):
87 | tkinter.messagebox.showinfo(title='车牌识别管理系统', message='登录成功')
88 | close_window()
89 | os.system("python3 ./main.py")
90 | else:
91 | tkinter.messagebox.showinfo(title='车牌识别管理系统', message='密码错误')
92 |
93 | def login(self, self2):
94 | self.backstage_interface()
95 |
96 |
97 | def close_window():
98 | print("log destroy")
99 | if login.thread_run:
100 | login.thread_run = False
101 | login.thread.join(2.0)
102 | log.destroy()
103 |
104 |
105 | if __name__ == '__main__':
106 | log = tk.Tk()
107 |
108 | login = Login(log)
109 | # close,退出输出destroy
110 | log.protocol('WM_DELETE_WINDOW', close_window)
111 | # 进入消息循环
112 | log.mainloop()
113 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import threading
4 | import time
5 | import tkinter as tk
6 | import cv2
7 | import img_function as predict
8 | import img_math
9 | import img_excel
10 | import img_sql
11 | import img_api
12 | import screencut
13 | from threading import Thread
14 | from tkinter import ttk
15 | from tkinter.filedialog import *
16 | from PIL import Image, ImageTk, ImageGrab
17 | import tkinter.messagebox
18 | import requests
19 | from time import sleep
20 |
21 |
22 | class ThreadWithReturnValue(Thread):
23 | def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None):
24 | Thread.__init__(self, group, target, name, args, kwargs, daemon=daemon)
25 | self._return1 = None
26 | self._return2 = None
27 | self._return3 = None
28 |
29 | def run(self):
30 | if self._target is not None:
31 | self._return1, self._return2, self._return3 = self._target(*self._args, **self._kwargs)
32 |
33 | def join(self):
34 | Thread.join(self)
35 | return self._return1, self._return2, self._return3
36 |
37 |
38 | class Surface(ttk.Frame):
39 | pic_path = ""
40 | viewhigh = 600
41 | viewwide = 600
42 | update_time = 0
43 | thread = None
44 | thread_run = False
45 | camera = None
46 | pic_source = ""
47 | color_transform = {"green": ("绿牌", "#55FF55"), "yello": ("黄牌", "#FFFF00"), "blue": ("蓝牌", "#6666FF")}
48 |
49 | def __init__(self, win):
50 | ttk.Frame.__init__(self, win)
51 | frame_left = ttk.Frame(self)
52 | frame_right1 = ttk.Frame(self)
53 | frame_right2 = ttk.Frame(self)
54 | top = ttk.Frame(self)
55 | win.title("车牌识别")
56 | win.minsize(850, 700)
57 | # win.wm_attributes('-topmost', 1)
58 | self.center_window()
59 |
60 | top.pack(side=TOP, expand=1, fill=tk.Y)
61 | reset_ctl = ttk.Button(top, text="重置窗口", width=10, command=self.reset)
62 | reset_ctl.pack(side=LEFT)
63 | L1 = ttk.Label(top, text='网络地址:')
64 | L1.pack(side=LEFT)
65 | self.p1 = StringVar()
66 | self.user_text = ttk.Entry(top, textvariable=self.p1, width=45)
67 | self.user_text.pack(side = LEFT)
68 | self.user_text.bind('', self.url_pic2)
69 | url_ctl = ttk.Button(top, text="识别网络图片", width=20, command=self.url_pic)
70 | url_ctl.pack(side=RIGHT)
71 |
72 | self.pack(fill=tk.BOTH, expand=tk.YES, padx="10", pady="10")
73 | frame_left.pack(side=LEFT, expand=1)
74 | frame_right1.pack(side=TOP, expand=1, fill=tk.Y)
75 | frame_right2.pack(side=RIGHT, expand=0)
76 | #ttk.Label(frame_left, text='地址:').pack(anchor="nw")
77 |
78 | self.image_ctl = ttk.Label(frame_left)
79 | self.image_ctl.pack(anchor="nw")
80 |
81 | ttk.Label(frame_right1, text='形状定位车牌位置:').grid(column=0, row=0, sticky=tk.W)
82 | from_pic_ctl = ttk.Button(frame_right2, text="来自图片", width=20, command=self.from_pic)
83 | from_vedio_ctl = ttk.Button(frame_right2, text="打开/关闭摄像头", width=20, command=self.from_vedio)
84 | from_video_ctl = ttk.Button(frame_right2, text="拍照并识别", width=20, command=self.video_pic)
85 | from_img_pre = ttk.Button(frame_right2, text="查看预处理图像", width=20, command=self.show_img_pre)
86 | clean_ctrl = ttk.Button(frame_right2, text="清除识别数据", width=20, command=self.clean)
87 | exit_ctrl = ttk.Button(frame_right2, text="api再次识别", width=20, command=self.api_ctl)
88 | self.cut_ctrl = ttk.Button(frame_right2, text="截图识别", width=20, command=self.cut_pic)
89 | camera_ctrl = ttk.Button(frame_right2, text="开关摄像头实时识别(测试)", width=20, command=self.camera_flag)
90 |
91 | self.roi_ctl = ttk.Label(frame_right1)
92 | self.roi_ctl.grid(column=0, row=1, sticky=tk.W)
93 | ttk.Label(frame_right1, text='形状定位识别结果:').grid(column=0, row=2, sticky=tk.W)
94 | self.r_ctl = ttk.Label(frame_right1, text="", font=('Times', '20'))
95 | self.r_ctl.grid(column=0, row=3, sticky=tk.W)
96 | self.color_ctl = ttk.Label(frame_right1, text="", width="20")
97 | self.color_ctl.grid(column=0, row=4, sticky=tk.W)
98 | self.cut_ctrl.pack(anchor="se", pady="5")
99 | camera_ctrl.pack(anchor="se", pady="5")
100 | from_vedio_ctl.pack(anchor="se", pady="5")
101 | from_video_ctl.pack(anchor="se", pady="5")
102 | from_pic_ctl.pack(anchor="se", pady="5")
103 | from_img_pre.pack(anchor="se", pady="5")
104 | clean_ctrl.pack(anchor="se", pady="5")
105 | exit_ctrl.pack(anchor="se", pady="5")
106 |
107 | ttk.Label(frame_right1, text='-------------------------------').grid(column=0, row=5, sticky=tk.W)
108 | ttk.Label(frame_right1, text='颜色定位车牌位置:').grid(column=0, row=6, sticky=tk.W)
109 | self.roi_ct2 = ttk.Label(frame_right1)
110 | self.roi_ct2.grid(column=0, row=7, sticky=tk.W)
111 | ttk.Label(frame_right1, text='颜色定位识别结果:').grid(column=0, row=8, sticky=tk.W)
112 | self.r_ct2 = ttk.Label(frame_right1, text="", font=('Times', '20'))
113 | self.r_ct2.grid(column=0, row=9, sticky=tk.W)
114 | self.color_ct2 = ttk.Label(frame_right1, text="", width="20")
115 | self.color_ct2.grid(column=0, row=10, sticky=tk.W)
116 | ttk.Label(frame_right1, text='-------------------------------').grid(column=0, row=11, sticky=tk.W)
117 |
118 | self.clean()
119 | self.apistr = None
120 | img_excel.create_excel()
121 | img_sql.create_sql()
122 |
123 | self.predictor = predict.CardPredictor()
124 | self.predictor.train_svm()
125 |
126 | def cut_pic(self):
127 | #最小化主窗口
128 | win.state('icon')
129 | sleep(0.2)
130 | filename = "tmp/cut.gif"
131 | im =ImageGrab.grab()
132 | im.save(filename)
133 | im.close()
134 | #显示全屏幕截图
135 | w = screencut.MyCapture(win, filename)
136 | self.cut_ctrl.wait_window(w.top)
137 |
138 | #截图结束,恢复主窗口,并删除临时的全屏幕截图文件
139 | win.state('normal')
140 | os.remove(filename)
141 | self.cameraflag = 0
142 | self.pic_path = "tmp/cut.png"
143 | self.clean()
144 | self.pic_source = "来自截图"
145 | self.pic(self.pic_path)
146 |
147 | def reset(self):
148 | self.reset2()
149 | self.reset2()
150 |
151 | def reset2(self):
152 | win.geometry("850x700")
153 | self.clean()
154 | self.center_window()
155 |
156 | def center_window(self):
157 | screenwidth = win.winfo_screenwidth()
158 | screenheight = win.winfo_screenheight()
159 | win.update()
160 | width = win.winfo_width()
161 | height = win.winfo_height()
162 | size = '+%d+%d' % ((screenwidth - width)/2, (screenheight - height)/2)
163 | #print(size)
164 | win.geometry(size)
165 |
166 | def get_imgtk(self, img_bgr):
167 | img = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
168 | im = Image.fromarray(img)
169 | w, h = im.size
170 | pil_image_resized = self.resize2(w, h, im)
171 | imgtk = ImageTk.PhotoImage(image=pil_image_resized)
172 | return imgtk
173 |
174 | def resize(self, w, h, pil_image):
175 | w_box = 200
176 | h_box = 50
177 | f1 = 1.0*w_box/w
178 | f2 = 1.0*h_box/h
179 | factor = min([f1, f2])
180 | width = int(w*factor)
181 | height = int(h*factor)
182 | return pil_image.resize((width, height), Image.ANTIALIAS)
183 |
184 | def resize2(self, w, h, pil_image):
185 | width = win.winfo_width()
186 | height = win.winfo_height()
187 | w_box = width - 250
188 | h_box = height - 100
189 | f1 = 1.0*w_box/w
190 | f2 = 1.0*h_box/h
191 | factor = min([f1, f2])
192 | width = int(w*factor)
193 | height = int(h*factor)
194 | return pil_image.resize((width, height), Image.ANTIALIAS)
195 |
196 | def show_roi1(self, r, roi, color):
197 | if r:
198 | try:
199 | roi = cv2.cvtColor(roi, cv2.COLOR_BGR2RGB)
200 | roi = Image.fromarray(roi)
201 | w, h = roi.size
202 | pil_image_resized = self.resize(w, h, roi)
203 | self.tkImage1 = ImageTk.PhotoImage(image=pil_image_resized)
204 | # self.imgtk_roi1 = ImageTk.PhotoImage(image=roi)
205 | self.roi_ctl.configure(image=self.tkImage1, state='enable')
206 | except:
207 | pass
208 | self.r_ctl.configure(text=str(r))
209 | self.update_time = time.time()
210 | try:
211 | c = self.color_transform[color]
212 | self.color_ctl.configure(text=c[0], state='enable')
213 | except:
214 | self.color_ctl.configure(state='disabled')
215 | elif self.update_time + 8 < time.time():
216 | self.roi_ctl.configure(state='disabled')
217 | self.r_ctl.configure(text="")
218 | self.color_ctl.configure(state='disabled')
219 |
220 | def show_roi2(self, r, roi, color):
221 | if r:
222 | try:
223 | roi = cv2.cvtColor(roi, cv2.COLOR_BGR2RGB)
224 | roi = Image.fromarray(roi)
225 | w, h = roi.size
226 | pil_image_resized = self.resize(w, h, roi)
227 | self.tkImage2 = ImageTk.PhotoImage(image=pil_image_resized)
228 | #self.imgtk_roi2 = ImageTk.PhotoImage(image=roi)
229 | self.roi_ct2.configure(image=self.tkImage2, state='enable')
230 | except:
231 | pass
232 | self.r_ct2.configure(text=str(r))
233 | self.update_time = time.time()
234 | try:
235 | c = self.color_transform[color]
236 | self.color_ct2.configure(text=c[0], state='enable')
237 | except:
238 | self.color_ct2.configure(state='disabled')
239 | elif self.update_time + 8 < time.time():
240 |
241 | self.roi_ct2.configure(state='disabled')
242 | self.r_ct2.configure(text="")
243 | self.color_ct2.configure(state='disabled')
244 |
245 | def camera_flag(self):
246 | if not self.thread_run:
247 | tkinter.messagebox.showinfo('提示', '请点击 [打开摄像头] 按钮!')
248 | return
249 | if not self.cameraflag:
250 | self.cameraflag = 1
251 | self.thread2 = threading.Thread(target=self.video_pic2)
252 | self.thread2.setDaemon(True)
253 | self.thread2.start()
254 | self.thread_run2 = True
255 | else:
256 | self.cameraflag = 0
257 | self.thread_run2 = False
258 | print("关闭摄像头实时识别 self.cameraflag", self.cameraflag)
259 |
260 | def from_vedio(self):
261 | if self.thread_run:
262 | if self.camera.isOpened():
263 | self.camera.release()
264 | print("关闭摄像头")
265 | self.camera = None
266 | self.thread_run = False
267 | return
268 | if self.camera is None:
269 | self.camera = cv2.VideoCapture(1)
270 | if not self.camera.isOpened():
271 | self.camera = None
272 | print("没有外置摄像头")
273 | self.camera = cv2.VideoCapture(0)
274 | if not self.camera.isOpened():
275 | print("没有内置摄像头")
276 | tkinter.messagebox.showinfo('警告', '摄像头打开失败!')
277 | self.camera = None
278 | return
279 | else:
280 | print("打开内置摄像头")
281 | else:
282 | print("打开外置摄像头")
283 | self.pic_source = "摄像头"
284 | self.cameraflag = 0
285 | self.thread = threading.Thread(target=self.vedio_thread, args=(self,))
286 | self.thread.setDaemon(True)
287 | self.thread.start()
288 | self.thread_run = True
289 |
290 | def pic(self, pic_path):
291 | self.apistr = None
292 | img_bgr = img_math.img_read(pic_path)
293 | first_img, oldimg = self.predictor.img_first_pre(img_bgr)
294 | if not self.cameraflag:
295 | self.imgtk = self.get_imgtk(img_bgr)
296 | self.image_ctl.configure(image=self.imgtk)
297 | th1 = ThreadWithReturnValue(target=self.predictor.img_color_contours, args=(first_img, oldimg))
298 | th2 = ThreadWithReturnValue(target=self.predictor.img_only_color, args=(oldimg, oldimg, first_img))
299 | th1.start()
300 | th2.start()
301 | r_c, roi_c, color_c = th1.join()
302 | r_color, roi_color, color_color = th2.join()
303 |
304 | self.show_roi2(r_color, roi_color, color_color)
305 | self.show_roi1(r_c, roi_c, color_c)
306 | # self.center_window()
307 | localtime = time.asctime(time.localtime(time.time()))
308 | if not self.cameraflag:
309 | if not (r_color or color_color or r_c or color_c):
310 | self.api_ctl()
311 | value = [localtime, color_c, r_c, color_color, r_color, self.apistr, self.pic_source]
312 | img_excel.excel_add(value)
313 | img_sql.sql(value[0], value[1], value[2], value[3], value[4], value[5], value[6])
314 | print(localtime, "|", color_c, r_c, "|", color_color, r_color, "| ", self.apistr, "|", self.pic_source)
315 |
316 | def from_pic(self):
317 | self.thread_run = False
318 | self.thread_run2 = False
319 | self.cameraflag = 0
320 | self.pic_path = askopenfilename(title="选择识别图片", filetypes=[("jpg图片", "*.jpg"), ("png图片", "*.png")])
321 | self.clean()
322 | self.pic_source = "本地文件:" + self.pic_path
323 | self.pic(self.pic_path)
324 |
325 | def vedio_thread(delf,self):
326 | self.thread_run = True
327 | while self.thread_run:
328 | _, img_bgr = self.camera.read()
329 | self.img_bg = img_bgr
330 | self.imgtk = self.get_imgtk(img_bgr)
331 | self.image_ctl.configure(image=self.imgtk)
332 | print("run end")
333 |
334 | def video_pic2(self):
335 | self.thread_run2 = True
336 | predict_time = time.time()
337 | while self.thread_run2:
338 | if self.cameraflag:
339 | if time.time() - predict_time > 2:
340 | print("实时识别中self.cameraflag", self.cameraflag)
341 | cv2.imwrite("tmp/test.jpg", self.img_bg)
342 | self.pic_path = "tmp/test.jpg"
343 | self.pic(self.pic_path)
344 | predict_time = time.time()
345 | print("run end")
346 |
347 | def video_pic(self):
348 | if not self.thread_run:
349 | tkinter.messagebox.showinfo('提示', '请点击 [打开摄像头] 按钮!')
350 | return
351 | self.thread_run = False
352 | self.thread_run2 = False
353 | _, img_bgr = self.camera.read()
354 | cv2.imwrite("tmp/test.jpg", img_bgr)
355 | self.pic_path = "tmp/test.jpg"
356 | self.clean()
357 | self.pic(self.pic_path)
358 | print("video_pic")
359 |
360 | def url_pic(self):
361 | IMAGE_URL = self.getuser()
362 | URL_len = len(IMAGE_URL)
363 | if (IMAGE_URL == ""):
364 | tkinter.messagebox.showinfo('提示', '请输入网址!')
365 | return
366 | if (URL_len > 150):
367 | tkinter.messagebox.showinfo('提示', '网址过长!')
368 | return
369 | r = requests.get(IMAGE_URL)
370 | with open("tmp/url.png", 'wb') as f:
371 | f.write(r.content)
372 | # print(IMAGE_URL)
373 | self.thread_run = False
374 | self.thread_run2 = False
375 | self.cameraflag=0
376 | self.pic_path = "tmp/url.png"
377 | self.clean()
378 | self.pic_source = "网络地址:" + IMAGE_URL
379 | self.pic(self.pic_path)
380 |
381 | def url_pic2(self, self2):
382 | self.url_pic()
383 |
384 | def getuser(self):
385 | user = self.user_text.get() #获取文本框内容
386 | return user
387 |
388 | def api_ctl(self):
389 | if self.thread_run:
390 | return
391 | self.thread_run = False
392 | self.thread_run2 = False
393 | colorstr, textstr = img_api.api_pic(self.pic_path)
394 | self.apistr = colorstr + textstr
395 | self.show_roi1(textstr, None, colorstr)
396 | self.show_roi2(textstr, None, colorstr)
397 | localtime = time.asctime(time.localtime(time.time()))
398 | value = [localtime, None, None, None, None, self.apistr, self.pic_source]
399 | print(localtime, "|", "|", "| ", self.apistr, "|", self.pic_source)
400 | img_excel.excel_add(value)
401 | img_sql.sql(value[0], value[1], value[2], value[3], value[4], value[5], value[6])
402 |
403 | def show_img_pre(self):
404 | if self.thread_run:
405 | return
406 | self.thread_run = False
407 | self.thread_run2 = False
408 | filename = img_math.img_read("tmp/img_contours.jpg")
409 | screenwidth = win.winfo_screenwidth()
410 | screenheight = win.winfo_screenheight()
411 | win.update()
412 | width = win.winfo_width()
413 | height = win.winfo_height()
414 | laji1 = int((screenwidth - width)/2)
415 | laji2 = int((screenheight - height)/2)
416 | cv2.imshow("preimg", filename)
417 | cv2.moveWindow("preimg", laji1+100, laji2)
418 |
419 | def clean(self):
420 | if self.thread_run:
421 | self.cameraflag=0
422 | return
423 | self.thread_run = False
424 | self.thread_run2 = False
425 | # self.center_window()
426 | self.p1.set("")
427 | img_bgr3 = img_math.img_read("pic/hy.png")
428 | self.imgtk2 = self.get_imgtk(img_bgr3)
429 | self.image_ctl.configure(image=self.imgtk2)
430 |
431 | self.r_ctl.configure(text="")
432 | self.color_ctl.configure(text="", state='enable')
433 |
434 | self.r_ct2.configure(text="")
435 | self.color_ct2.configure(text="", state='enable')
436 |
437 | self.pilImage3 = Image.open("pic/locate.png")
438 | w, h = self.pilImage3.size
439 | pil_image_resized = self.resize(w, h, self.pilImage3)
440 | self.tkImage3 = ImageTk.PhotoImage(image=pil_image_resized)
441 | self.roi_ctl.configure(image=self.tkImage3, state='enable')
442 | self.roi_ct2.configure(image=self.tkImage3, state='enable')
443 | # self.roi_ctl.configure(state='disabled')
444 | # self.roi_ct2.configure(state='disabled')
445 |
446 |
447 | def close_window():
448 | print("destroy")
449 | if surface.thread_run:
450 | surface.thread_run = False
451 | surface.thread.join(2.0)
452 | win.destroy()
453 |
454 |
455 | if __name__ == '__main__':
456 | win = tk.Tk()
457 |
458 | surface = Surface(win)
459 | # close,退出输出destroy
460 | win.protocol('WM_DELETE_WINDOW', close_window)
461 | # 进入消息循环
462 | win.mainloop()
463 |
--------------------------------------------------------------------------------
/pic/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/.DS_Store
--------------------------------------------------------------------------------
/pic/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/1.png
--------------------------------------------------------------------------------
/pic/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/2.png
--------------------------------------------------------------------------------
/pic/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/3.png
--------------------------------------------------------------------------------
/pic/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/4.png
--------------------------------------------------------------------------------
/pic/api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/api.png
--------------------------------------------------------------------------------
/pic/hy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/hy.png
--------------------------------------------------------------------------------
/pic/locate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/locate.png
--------------------------------------------------------------------------------
/pic/log.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/log.png
--------------------------------------------------------------------------------
/pic/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/login.png
--------------------------------------------------------------------------------
/pic/sql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/pic/sql.png
--------------------------------------------------------------------------------
/screencut.py:
--------------------------------------------------------------------------------
1 | import tkinter
2 | import tkinter.filedialog
3 | from PIL import ImageGrab
4 | from time import sleep
5 |
6 |
7 | class MyCapture:
8 | def __init__(self, root, png):
9 | # 变量X和Y用来记录鼠标左键按下的位置
10 | self.X = tkinter.IntVar(value=0)
11 | self.Y = tkinter.IntVar(value=0)
12 | self.sel = False
13 | # 屏幕尺寸
14 | self.screenWidth = root.winfo_screenwidth()
15 | self.screenHeight = root.winfo_screenheight()
16 | # 创建顶级组件容器
17 | self.top = tkinter.Toplevel(root, width=self.screenWidth, height=self.screenHeight)
18 | #self.top.update()
19 | #self.top.resizable(0, 0)
20 | self.top.geometry('+0+0')
21 | # 不显示最大化、最小化按钮
22 | self.top.overrideredirect(True)
23 | self.canvas = tkinter.Canvas(self.top, bg='white', width=self.screenWidth, height=self.screenHeight)
24 | # 显示全屏截图,在全屏截图上进行区域截图
25 | self.image = tkinter.PhotoImage(file=png)
26 | self.canvas.create_image(self.screenWidth//2, self.screenHeight//2, image=self.image)
27 | self.canvas.pack()
28 |
29 | # 鼠标左键按下的位置
30 | def onLeftButtonDown(event):
31 | # pdb.set_trace()
32 | self.X.set(event.x)
33 | self.Y.set(event.y)
34 | # 开始截图
35 | self.sel = True
36 | self.canvas.bind('', onLeftButtonDown)
37 |
38 | # 鼠标左键移动,显示选取的区域
39 | def onLeftButtonMove(event):
40 | # pdb.set_trace()
41 | global lastDraw, r, c
42 | try:
43 | # 删除刚画完的图形,要不然鼠标移动的时候是黑乎乎的一片矩形
44 | self.canvas.delete(lastDraw)
45 | self.canvas.delete(r)
46 | self.canvas.delete(c)
47 | except Exception as e:
48 | pass
49 | if not self.sel:
50 | # 没有点击左键时绘制十字线
51 | r = self.canvas.create_line(0, event.y, self.screenWidth, event.y, fill='white')
52 | c = self.canvas.create_line(event.x, 0, self.screenHeight, event.x, fill='white')
53 | #print(event.x, event.y, self.screenWidth, self.screenHeight)
54 | else:
55 | lastDraw = self.canvas.create_rectangle(self.X.get(), self.Y.get(), event.x, event.y, outline='orange')
56 | #print(event.x, event.y, self.screenWidth, self.screenWidth)
57 | self.canvas.bind('', onLeftButtonMove)
58 | # 获取鼠标左键抬起的位置,保存区域截图
59 |
60 | def onLeftButtonUp(event):
61 | self.sel =False
62 | try:
63 | self.canvas.delete(lastDraw)
64 | except Exception as e:
65 | pass
66 | sleep(0.1)
67 | # 考虑鼠标左键从右下方按下而从左上方抬起的截图
68 | left, right = sorted([self.X.get(), event.x])
69 | top, bottom = sorted([self.Y.get(), event.y])
70 | pic =ImageGrab.grab((left+1, top+1, right, bottom))
71 | # 关闭顶级容器
72 | self.top.destroy()
73 | if pic:
74 | pic.save('tmp/cut.png')
75 | self.canvas.bind('', onLeftButtonUp)
76 | self.canvas.pack(fill=tkinter.BOTH, expand=tkinter.YES)
77 |
78 |
79 |
--------------------------------------------------------------------------------
/tmp/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/tmp/.DS_Store
--------------------------------------------------------------------------------
/tmp/cut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/tmp/cut.png
--------------------------------------------------------------------------------
/tmp/img_contours.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/tmp/img_contours.jpg
--------------------------------------------------------------------------------
/tmp/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/tmp/test.jpg
--------------------------------------------------------------------------------
/tmp/url.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dreamhunter2333/python_car/5628393235980716a20446077d10dcf732930c4e/tmp/url.png
--------------------------------------------------------------------------------