ismot xangcastle commited on
Commit
3c84e45
·
0 Parent(s):

Duplicate from Prevantec/platerecognition

Browse files

Co-authored-by: Cesar Abel Ramirez <[email protected]>

.gitattributes ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tflite filter=lfs diff=lfs merge=lfs -text
29
+ *.tgz filter=lfs diff=lfs merge=lfs -text
30
+ *.wasm filter=lfs diff=lfs merge=lfs -text
31
+ *.xz filter=lfs diff=lfs merge=lfs -text
32
+ *.zip filter=lfs diff=lfs merge=lfs -text
33
+ *.zst filter=lfs diff=lfs merge=lfs -text
34
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ .idea
2
+ plates
3
+ flagged
README.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Platerecognition
3
+ emoji: 📊
4
+ colorFrom: purple
5
+ colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: 3.12.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: openrail
11
+ duplicated_from: Prevantec/platerecognition
12
+ ---
13
+
14
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import cv2
4
+ from norfair import Detection, Tracker, Video
5
+ from detector.utils import detect_plates, detect_chars, imcrop, send_request, draw_text
6
+ from threading import Thread
7
+
8
+ DISTANCE_THRESHOLD_BBOX: float = 0.7
9
+ DISTANCE_THRESHOLD_CENTROID: int = 30
10
+ MAX_DISTANCE: int = 10000
11
+
12
+
13
+ def yolo_to_norfair(yolo_detections):
14
+ norfair_detections = []
15
+ detections_as_xyxy = yolo_detections.xyxy[0]
16
+ for detection_as_xyxy in detections_as_xyxy:
17
+ bbox = np.array(
18
+ [
19
+ [detection_as_xyxy[0].item(), detection_as_xyxy[1].item()],
20
+ [detection_as_xyxy[2].item(), detection_as_xyxy[3].item()],
21
+ ]
22
+ )
23
+ scores = np.array(
24
+ [detection_as_xyxy[4].item(), detection_as_xyxy[4].item()]
25
+ )
26
+ norfair_detections.append(
27
+ Detection(
28
+ points=bbox, scores=scores, label=int(detection_as_xyxy[-1].item())
29
+ )
30
+ )
31
+ return norfair_detections
32
+
33
+
34
+ def fn_image(foto):
35
+ plates_text = []
36
+ plates = detect_plates(foto)
37
+ records = plates.pandas().xyxy[0].to_dict(orient='records')
38
+ if records:
39
+ for plate in records:
40
+ xi, yi, xf, yf = int(plate['xmin']), int(plate['ymin']), int(plate['xmax']), int(plate['ymax'])
41
+ crop = imcrop(foto, (xi, yi, xf, yf))
42
+ if len(crop) > 0:
43
+ cv2.rectangle(foto, (xi, yi), (xf, yf), (0, 255, 0), 2)
44
+ text = detect_chars(crop)
45
+ draw_text(foto, text, (xi, yi))
46
+ plates_text.append(text)
47
+ return foto, plates_text
48
+
49
+
50
+ def fn_video(video, initial_time, duration):
51
+ tracker = Tracker(
52
+ distance_function="iou_opt",
53
+ distance_threshold=DISTANCE_THRESHOLD_BBOX,
54
+ )
55
+ cap = cv2.VideoCapture(video)
56
+ fps = cap.get(cv2.CAP_PROP_FPS)
57
+ image_size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
58
+ final_video = cv2.VideoWriter('output.mp4', cv2.VideoWriter_fourcc(*'VP90'), fps, image_size)
59
+ num_frames = 0
60
+ min_frame = int(initial_time * fps)
61
+ max_frame = int((initial_time + duration) * fps)
62
+ plates = {}
63
+ while cap.isOpened():
64
+ try:
65
+ ret, frame = cap.read()
66
+ gpu_frame = cv2.cuda_GpuMat()
67
+ gpu_frame.upload(frame)
68
+ if not ret:
69
+ break
70
+ frame_copy = frame.copy()
71
+ except Exception as e:
72
+ print(e)
73
+ continue
74
+ if num_frames < min_frame:
75
+ num_frames += 1
76
+ continue
77
+ yolo_detections = detect_plates(gpu_frame)
78
+ detections = yolo_to_norfair(yolo_detections)
79
+ tracked_objects = tracker.update(detections=detections)
80
+ for obj in tracked_objects:
81
+ if obj.last_detection is not None:
82
+ bbox = obj.last_detection.points
83
+ bbox = int(bbox[0][0]), int(bbox[0][1]), int(bbox[1][0]), int(bbox[1][1])
84
+ if obj.id not in plates.keys():
85
+ crop = imcrop(gpu_frame, bbox)
86
+ text = detect_chars(crop)
87
+ plates[obj.id] = text
88
+ thread = Thread(target=send_request, args=(frame_copy, text, bbox))
89
+ thread.start()
90
+
91
+ cv2.rectangle(
92
+ gpu_frame,
93
+ (bbox[0], bbox[1]),
94
+ (bbox[2], bbox[3]),
95
+ (0, 255, 0),
96
+ 2,
97
+ )
98
+ draw_text(gpu_frame, plates[obj.id], (bbox[0], bbox[1]))
99
+ cv2.putText(
100
+ gpu_frame,
101
+ plates[obj.id],
102
+ (bbox[0], bbox[1]),
103
+ cv2.FONT_HERSHEY_SIMPLEX,
104
+ 1,
105
+ (0, 255, 0),
106
+ 2,
107
+ )
108
+ final_video.write(gpu_frame)
109
+ num_frames += 1
110
+ if num_frames == max_frame:
111
+ break
112
+ cap.release()
113
+ final_video.release()
114
+ return 'output.mp4', [plates[k] for k in plates.keys()]
115
+
116
+
117
+ image_interface = gr.Interface(
118
+ fn=fn_image,
119
+ inputs="image",
120
+ outputs=["image", "text"],
121
+ title="Buscar números de placa en una imagen",
122
+ allow_flagging=False,
123
+ allow_screenshot=False,
124
+ )
125
+
126
+ video_interface = gr.Interface(
127
+ fn=fn_video,
128
+ inputs=[
129
+ gr.Video(type="file", label="Video"),
130
+ gr.Slider(0, 600, value=0, label="Tiempo inicial en segundos", step=1),
131
+ gr.Slider(0, 10, value=4, label="Duración en segundos", step=1),
132
+ ],
133
+ outputs=["video", "text"],
134
+ title="Buscar números de placa en un video",
135
+ allow_flagging=False,
136
+ allow_screenshot=False,
137
+ )
138
+
139
+ webcam_interface = gr.Interface(
140
+ fn_image,
141
+ inputs=[
142
+ gr.Image(source='webcam', streaming=True),
143
+ ],
144
+ outputs=gr.Image(type="file"),
145
+ live=True,
146
+ title="Buscar placa con la cámara",
147
+ allow_flagging=False,
148
+ allow_screenshot=False,
149
+ )
150
+
151
+ if __name__ == "__main__":
152
+ gr.TabbedInterface(
153
+ [image_interface, video_interface],
154
+ ["Fotos", "Videos"],
155
+ ).launch()
detector/__init__.py ADDED
File without changes
detector/static/chars.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:216d9926ea5ac6195b420b98b668fe8a404f180753e83032904bbcf90906b76d
3
+ size 14516597
detector/static/plates.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:34eb52d76e7dcf3e5a5d855ddb8ca95d88633c45bfa08f52e0985e2735e9754c
3
+ size 173134301
detector/utils.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import numpy as np
3
+ import cv2
4
+ import os
5
+ from datetime import datetime
6
+ from json import dumps
7
+ import requests
8
+
9
+ BASE_DIR = os.path.abspath(os.getcwd())
10
+
11
+ device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
12
+ print('Loading models...', device)
13
+
14
+ model_plates = torch.hub.load('ultralytics/yolov5', 'custom',
15
+ path=os.path.join(BASE_DIR, 'detector', 'static', 'plates.pt'), device=device)
16
+
17
+ model_chars = torch.hub.load('ultralytics/yolov5', 'custom',
18
+ path=os.path.join(BASE_DIR, 'detector', 'static', 'chars.pt'), device=device)
19
+
20
+
21
+ def pad_img_to_fit_bbox(img, x1, x2, y1, y2):
22
+ img = np.pad(img, ((np.abs(np.minimum(0, y1)), np.maximum(y2 - img.shape[0], 0)),
23
+ (np.abs(np.minimum(0, x1)), np.maximum(x2 - img.shape[1], 0)), (0, 0)), mode="constant")
24
+ y1 += np.abs(np.minimum(0, y1))
25
+ y2 += np.abs(np.minimum(0, y1))
26
+ x1 += np.abs(np.minimum(0, x1))
27
+ x2 += np.abs(np.minimum(0, x1))
28
+ return img, x1, x2, y1, y2
29
+
30
+
31
+ def imcrop(img, bbox):
32
+ x1, y1, x2, y2 = bbox
33
+ if x1 < 0 or y1 < 0 or x2 > img.shape[1] or y2 > img.shape[0]:
34
+ img, x1, x2, y1, y2 = pad_img_to_fit_bbox(img, x1, x2, y1, y2)
35
+ return img[y1:y2, x1:x2, :]
36
+
37
+
38
+ def detect_plates(img):
39
+ return model_plates(img)
40
+
41
+
42
+ def detect_chars(img):
43
+ img = cv2.resize(img, (640, 320))
44
+ detect = model_chars(img)
45
+ records = detect.pandas().xyxy[0].to_dict(orient='records')
46
+ text = ''
47
+ if records:
48
+ records = sorted(records, key=lambda d: d['xmin'])
49
+ text = ''.join([i.get('name') for i in records])
50
+ return text
51
+
52
+
53
+ def draw_text(img, text,
54
+ pos=(0, 0),
55
+ font_scale=1,
56
+ font_thickness=2,
57
+ text_color=(0, 255, 0),
58
+ text_color_bg=(0, 0, 0)
59
+ ):
60
+ x, y = pos
61
+ text_size, _ = cv2.getTextSize(text, 0, font_scale, font_thickness)
62
+ text_w, text_h = text_size
63
+ cv2.rectangle(img, pos, (x + text_w, y - text_h), text_color_bg, -1)
64
+ cv2.putText(img, text, (x, y), 0, font_scale, text_color, font_thickness)
65
+
66
+
67
+ def send_request(frame, text, bbox):
68
+ cv2.rectangle(
69
+ frame,
70
+ (bbox[0], bbox[1]),
71
+ (bbox[2], bbox[3]),
72
+ (0, 255, 0),
73
+ 2,
74
+ )
75
+ draw_text(frame, text, (bbox[0], bbox[1]))
76
+ url = "https://api.prevantec.com/toll-plates"
77
+ data = {
78
+ "number": text,
79
+ "camera": "camera_1",
80
+ "spot_on": str(datetime.now()),
81
+ }
82
+ if not os.path.exists(os.path.join(BASE_DIR, 'plates')):
83
+ os.makedirs(os.path.join(BASE_DIR, 'plates'))
84
+ filename = os.path.join(BASE_DIR, 'plates', f'{text}.jpg')
85
+ cv2.imwrite(filename, frame)
86
+ payload = {'data': dumps(data)}
87
+ files = [
88
+ ('files', (f'{text}.jpg', open(filename, 'rb'), 'image/jpg'))
89
+ ]
90
+ headers = {}
91
+ requests.request("POST", url, headers=headers, data=payload, files=files)
requirements.txt ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ absl-py==1.3.0
2
+ aiohttp==3.8.3
3
+ aiosignal==1.3.1
4
+ anyio==3.6.2
5
+ appnope==0.1.3
6
+ asttokens==2.2.0
7
+ async-timeout==4.0.2
8
+ attrs==22.1.0
9
+ backcall==0.2.0
10
+ bcrypt==4.0.1
11
+ cachetools==5.2.0
12
+ certifi==2021.5.30
13
+ cffi==1.15.1
14
+ chardet==4.0.0
15
+ charset-normalizer==2.1.1
16
+ click==8.1.3
17
+ commonmark==0.9.1
18
+ contourpy==1.0.6
19
+ cryptography==38.0.4
20
+ cycler==0.11.0
21
+ decorator==5.1.1
22
+ easyocr==1.6.2
23
+ executing==1.2.0
24
+ fastapi==0.88.0
25
+ ffmpy==0.3.0
26
+ filterpy==1.4.5
27
+ fonttools==4.38.0
28
+ frozenlist==1.3.3
29
+ fsspec==2022.11.0
30
+ gitdb==4.0.10
31
+ GitPython==3.1.29
32
+ glob2==0.7
33
+ google-auth==2.15.0
34
+ google-auth-oauthlib==0.4.6
35
+ gradio==3.12.0
36
+ grpcio==1.51.1
37
+ h11==0.12.0
38
+ httpcore==0.15.0
39
+ httpx==0.23.1
40
+ idna==3.4
41
+ imageio==2.22.4
42
+ importlib-metadata==5.1.0
43
+ imutils==0.5.4
44
+ ipython==8.7.0
45
+ jedi==0.18.2
46
+ Jinja2==3.1.2
47
+ kiwisolver==1.4.4
48
+ linkify-it-py==1.0.3
49
+ Markdown==3.4.1
50
+ markdown-it-py==2.1.0
51
+ MarkupSafe==2.1.1
52
+ matplotlib==3.6.2
53
+ matplotlib-inline==0.1.6
54
+ mdit-py-plugins==0.3.3
55
+ mdurl==0.1.2
56
+ multidict==6.0.3
57
+ networkx==2.8.8
58
+ ninja==1.11.1
59
+ norfair==2.1.1
60
+ numpy==1.23.5
61
+ oauthlib==3.2.2
62
+ opencv-python==4.5.5.64
63
+ opencv-python-headless==4.5.4.60
64
+ orjson==3.8.3
65
+ packaging==21.3
66
+ pandas==1.5.2
67
+ paramiko==2.12.0
68
+ parso==0.8.3
69
+ pexpect==4.8.0
70
+ pickleshare==0.7.5
71
+ Pillow==9.3.0
72
+ prompt-toolkit==3.0.33
73
+ protobuf==3.20.3
74
+ psutil==5.9.4
75
+ ptyprocess==0.7.0
76
+ pure-eval==0.2.2
77
+ pyasn1==0.4.8
78
+ pyasn1-modules==0.2.8
79
+ pyclipper==1.3.0.post4
80
+ pycparser==2.21
81
+ pycryptodome==3.16.0
82
+ pydantic==1.10.2
83
+ pydub==0.25.1
84
+ Pygments==2.13.0
85
+ PyNaCl==1.5.0
86
+ pyparsing==3.0.9
87
+ python-bidi==0.4.2
88
+ python-dateutil==2.8.2
89
+ python-dotenv==0.21.0
90
+ python-multipart==0.0.5
91
+ pytz==2022.6
92
+ PyWavelets==1.4.1
93
+ PyYAML==6.0
94
+ requests==2.28.1
95
+ requests-oauthlib==1.3.1
96
+ requests-toolbelt==0.10.1
97
+ rfc3986==1.5.0
98
+ rich==12.6.0
99
+ rsa==4.9
100
+ scikit-image==0.19.3
101
+ scipy==1.9.3
102
+ seaborn==0.12.1
103
+ Shapely==1.8.5.post1
104
+ six==1.16.0
105
+ smmap==5.0.0
106
+ sniffio==1.3.0
107
+ stack-data==0.6.2
108
+ starlette==0.22.0
109
+ tensorboard==2.11.0
110
+ tensorboard-data-server==0.6.1
111
+ tensorboard-plugin-wit==1.8.1
112
+ thop==0.1.1.post2209072238
113
+ tifffile==2022.10.10
114
+ torch==1.13.0
115
+ torchvision==0.14.0
116
+ tqdm==4.64.1
117
+ traitlets==5.6.0
118
+ typing_extensions==4.4.0
119
+ uc-micro-py==1.0.1
120
+ urllib3==1.26.13
121
+ uvicorn==0.20.0
122
+ wcwidth==0.2.5
123
+ websockets==10.4
124
+ Werkzeug==2.2.2
125
+ wget==3.2
126
+ yarl==1.8.2
127
+ zipp==3.11.0