cadyderwin commited on
Commit
0e436c7
·
verified ·
1 Parent(s): 12dc82c

Upload 18 files

Browse files
Files changed (19) hide show
  1. .gitattributes +2 -0
  2. Dockerfile +23 -0
  3. app.py +131 -0
  4. arial.ttf +3 -0
  5. demo.py +138 -0
  6. examples/1.jpg +0 -0
  7. examples/2.jpg +0 -0
  8. examples/3.jpg +0 -0
  9. install.sh +12 -0
  10. lib/libopymrz.so +0 -0
  11. lib/libopymrzenv.so +3 -0
  12. license.txt +1 -0
  13. model/mrza.bin +3 -0
  14. model/mrzb.bin +3 -0
  15. model/params.bin +3 -0
  16. model/s.bin +3 -0
  17. opymrz.py +27 -0
  18. requirements.txt +4 -0
  19. run.sh +5 -0
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ arial.ttf filter=lfs diff=lfs merge=lfs -text
37
+ lib/libopymrzenv.so filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.8-slim
2
+ WORKDIR /home/opymrz
3
+ COPY ./opymrz.py .
4
+ COPY ./app.py .
5
+ COPY ./demo.py .
6
+ COPY ./license.txt .
7
+ COPY ./requirements.txt .
8
+ COPY ./run.sh .
9
+ COPY ./arial.ttf .
10
+ COPY ./examples ./examples
11
+ COPY ./model ./model
12
+ COPY ./lib/libopyalpr.so ./lib/libopyalpr.so
13
+ COPY ./lib/libopyalprenv.so ./lib/libopyalprenv.so
14
+ COPY ./lib/libtensorflow_framework.so.2.6.0 /usr/lib/libtensorflow_framework.so.2.6.0
15
+ COPY ./lib/libtensorflow.so.2.6.0 /usr/lib/libtensorflow.so.2.6.0
16
+ RUN ln -s /usr/lib/libtensorflow.so.2.6.0 /usr/lib/libtensorflow.so.2 \
17
+ && ln -s /usr/lib/libtensorflow.so.2.6.0 /usr/lib/libtensorflow.so \
18
+ && ln -s /usr/lib/libtensorflow_framework.so.2.6.0 /usr/lib/libtensorflow_framework.so.2 \
19
+ && ln -s /usr/lib/libtensorflow_framework.so.2.6.0 /usr/lib/libtensorflow_framework.so
20
+ RUN pip3 install -r requirements.txt
21
+ RUN chmod a+x run.sh
22
+ CMD ["./run.sh"]
23
+ EXPOSE 9000 7860
app.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ sys.path.append('.')
3
+
4
+ import os
5
+ import numpy as np
6
+ import base64
7
+ import json
8
+ import io
9
+
10
+ from PIL import Image, ExifTags
11
+ from flask import Flask, request, jsonify
12
+ from opymrz import getHWID
13
+ from opymrz import setLicenseKey
14
+ from opymrz import initSDK
15
+ from opymrz import processImage
16
+
17
+ licenseKeyPath = "license.txt"
18
+ license = ""
19
+
20
+ try:
21
+ with open(licenseKeyPath, 'r') as file:
22
+ license = file.read().strip()
23
+ except IOError as exc:
24
+ print("failed to open license.txt: ", exc.errno)
25
+ print("License Key: ", license)
26
+
27
+ hwid = getHWID()
28
+ print("HWID: ", hwid.decode('utf-8'))
29
+
30
+ ret = setLicenseKey(license.encode('utf-8'))
31
+ print("Set License: ", ret)
32
+
33
+ ret = initSDK("model".encode('utf-8'))
34
+ print("Init: ", ret)
35
+
36
+ app = Flask(__name__)
37
+
38
+ def apply_exif_rotation(image):
39
+ try:
40
+ exif = image._getexif()
41
+ if exif is not None:
42
+ for orientation in ExifTags.TAGS.keys():
43
+ if ExifTags.TAGS[orientation] == 'Orientation':
44
+ break
45
+
46
+ # Get the orientation value
47
+ orientation = exif.get(orientation, None)
48
+
49
+ # Apply the appropriate rotation based on the orientation
50
+ if orientation == 3:
51
+ image = image.rotate(180, expand=True)
52
+ elif orientation == 6:
53
+ image = image.rotate(270, expand=True)
54
+ elif orientation == 8:
55
+ image = image.rotate(90, expand=True)
56
+
57
+ except AttributeError:
58
+ print("No EXIF data found")
59
+
60
+ return image
61
+
62
+
63
+ @app.route('/process_image', methods=['POST'])
64
+ def process_image():
65
+ file = request.files['image']
66
+
67
+ try:
68
+ image = apply_exif_rotation(Image.open(file)).convert('RGB')
69
+ except:
70
+ result = "Failed to open file"
71
+ response = jsonify({"resultCode": "Error", "result": result})
72
+
73
+ response.status_code = 200
74
+ response.headers["Content-Type"] = "application/json; charset=utf-8"
75
+ return response
76
+
77
+ image_np = np.asarray(image)
78
+ result = processImage(image_np, image_np.shape[1], image_np.shape[0])
79
+
80
+ if result is None:
81
+ result = "Failed to process image"
82
+ response = jsonify({"resultCode": "Error", "result": result})
83
+
84
+ response.status_code = 200
85
+ response.headers["Content-Type"] = "application/json; charset=utf-8"
86
+ return response
87
+ else:
88
+ result_dict = json.loads(result.decode('utf-8'))
89
+ response = jsonify({"resultCode": "Ok", "result": result_dict})
90
+
91
+ response.status_code = 200
92
+ response.headers["Content-Type"] = "application/json; charset=utf-8"
93
+ return response
94
+
95
+ @app.route('/process_image_base64', methods=['POST'])
96
+ def process_image_base64():
97
+ try:
98
+ content = request.get_json()
99
+ base64_image = content['base64']
100
+
101
+ image_data = base64.b64decode(base64_image)
102
+ image = apply_exif_rotation(Image.open(io.BytesIO(image_data))).convert("RGB")
103
+ except:
104
+ result = "Failed to parse base64"
105
+ response = jsonify({"resultCode": "Error", "result": result})
106
+
107
+ response.status_code = 200
108
+ response.headers["Content-Type"] = "application/json; charset=utf-8"
109
+ return response
110
+
111
+ image_np = np.asarray(image)
112
+ result = processImage(image_np, image_np.shape[1], image_np.shape[0])
113
+
114
+ if result is None:
115
+ result = "Failed to process image"
116
+ response = jsonify({"resultCode": "Error", "result": result})
117
+
118
+ response.status_code = 200
119
+ response.headers["Content-Type"] = "application/json; charset=utf-8"
120
+ return response
121
+ else:
122
+ result_dict = json.loads(result.decode('utf-8'))
123
+ response = jsonify({"resultCode": "Ok", "result": result_dict})
124
+
125
+ response.status_code = 200
126
+ response.headers["Content-Type"] = "application/json; charset=utf-8"
127
+ return response
128
+
129
+ if __name__ == '__main__':
130
+ port = int(os.environ.get("PORT", 9000))
131
+ app.run(host='0.0.0.0', port=port)
arial.ttf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:baa251526d6862712a58e613ef451d8a2b60482142ec6aab1d47fb8e23e21a7c
3
+ size 1045960
demo.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import requests
4
+ import json
5
+ import io
6
+ from gradio.components import Image
7
+ from PIL import Image as PILImage, ImageDraw, ImageFont # This import may be needed if you're processing images
8
+
9
+ from PIL import Image
10
+
11
+ def resize_image_with_aspect_ratio(image, target_height):
12
+ # Get original dimensions
13
+ original_width, original_height = image.size
14
+
15
+ # Calculate the new width to maintain aspect ratio
16
+ aspect_ratio = original_width / original_height
17
+ new_width = int(target_height * aspect_ratio)
18
+
19
+ # Resize the image
20
+ resized_image = image.resize((new_width, target_height), Image.LANCZOS)
21
+ return resized_image
22
+
23
+ def draw_text_with_background(draw, text, position, font, text_color="red", bg_color="white", padding=2):
24
+ # Get the bounding box of the text
25
+ bbox = draw.textbbox(position, text, font=font)
26
+
27
+ # Calculate the background rectangle coordinates
28
+ bg_x0, bg_y0, bg_x1, bg_y1 = bbox[0] - padding, bbox[1] - padding, bbox[2] + padding, bbox[3] + padding
29
+
30
+ # Draw the background rectangle
31
+ draw.rectangle([bg_x0, bg_y0, bg_x1, bg_y1], fill=bg_color)
32
+
33
+ # Draw the text on top of the background
34
+ draw.text(position, text, fill=text_color, font=font)
35
+
36
+ def process_image(image):
37
+ # Convert PIL image to bytes to send in POST request
38
+ img_bytes = io.BytesIO()
39
+ image.save(img_bytes, format="JPEG")
40
+ img_bytes.seek(0)
41
+
42
+
43
+ url = "http://127.0.0.1:9000/process_image"
44
+ files = {'image': img_bytes}
45
+ result = requests.post(url=url, files=files)
46
+
47
+ # Font setup (default font)
48
+ try:
49
+ font = ImageFont.truetype("arial.ttf", int(image.size[1] / 30))
50
+ except IOError:
51
+ font = ImageFont.load_default()
52
+
53
+ draw = ImageDraw.Draw(image)
54
+ if result.ok:
55
+ json_result = result.json()
56
+ if json_result.get("resultCode") == "Error":
57
+ return [image, {"resultCode": "Error", "result": "Failed to process image"}]
58
+
59
+ # plates = json_result.get("result", {}).get("plates", [])
60
+ # for plate in plates:
61
+ # number = plate.get("number")
62
+ # left = plate.get("left")
63
+ # top = plate.get("top")
64
+ # right = plate.get("right")
65
+ # bottom = plate.get("bottom")
66
+ # countryCode = plate.get('countryCode')
67
+ # car = plate.get('car')
68
+
69
+ # if car is not None:
70
+ # car_left = car.get('left')
71
+ # car_top = car.get('top')
72
+ # car_right = car.get('right')
73
+ # car_bottom = car.get('bottom')
74
+ # color = car.get('color')
75
+ # madeBy = car.get('madeBy')
76
+ # model = car.get('model')
77
+ # draw.rectangle([car_left, car_top, car_right, car_bottom], outline="white", width=3)
78
+ # draw_text_with_background(draw, color + "," + madeBy + "," + model, (car_left, car_top - 10), font, text_color="blue", bg_color="white")
79
+
80
+
81
+ # # Draw rectangle and plate number
82
+ # if left is not None:
83
+ # draw.rectangle([left, top, right, bottom], outline="green", width=3)
84
+ # draw_text_with_background(draw, number + "," + countryCode, (left, top - 10), font, text_color="green", bg_color="white")
85
+
86
+
87
+ return [image, json_result]
88
+ else:
89
+ return [image, {"resultCode": "Error", "result": result.text}]
90
+
91
+ with gr.Blocks() as demo:
92
+ gr.Markdown(
93
+ """
94
+ <div style="display: flex;align-items: center;">
95
+ <img alt="Opulentyn Logo" src="https://github.com/user-attachments/assets/5fc78032-bff2-4f7e-a174-7d64b22f506d" width="350"/>
96
+ <div>
97
+ <h1>License Plate Recognition (ANPR/ALPR)</h1>
98
+ <p>We offer <b>on-premises</b> OCR and liveness check solutions available with a <b>perpetual license</b>.</p>
99
+ </div>
100
+ </div>
101
+ ### 🤝 Talk to us
102
+ <div style="display: flex; align-items: center;">
103
+ <a href="https://opulentyn.com" target="_blank">
104
+ <img src="https://img.shields.io/badge/Website-https%3A%2F%2Fopulentyn.com-blue?style=flat&logo=google-chrome&logoColor=white" alt="Website">
105
+ </a>
106
+ &nbsp;&nbsp;&nbsp;&nbsp;
107
+ <a href="mailto:support@opulentyn.com">
108
+ <img src="https://img.shields.io/badge/Email-support%40opulentyn.com-blue?style=flat&logo=gmail&logoColor=white" alt="Email">
109
+ </a>
110
+ &nbsp;&nbsp;&nbsp;&nbsp;
111
+ <a href="https://wa.me/13435013587" target="_blank">
112
+ <img src="https://img.shields.io/badge/WhatsApp-%2B13435013587-blue?logo=whatsapp&logoColor=green" alt="WhatsApp">
113
+ </a>
114
+ &nbsp;&nbsp;&nbsp;&nbsp;
115
+ <a href="https://join.slack.com/t/opulentyn/shared_invite/zt-2s230jtbq-dWBs8XUZcrYim~nUqiimSA" target="_blank">
116
+ <img src="https://img.shields.io/badge/Slack-support--sdk-blueviolet?style=flat&logo=slack&logoColor=white" alt="Slack">
117
+ </a>
118
+ </div>
119
+ """
120
+ )
121
+
122
+ with gr.Row():
123
+ with gr.Column():
124
+ image_input = gr.Image(type='pil')
125
+ gr.Examples(['examples/1.jpg', 'examples/2.jpg', 'examples/3.jpg'],
126
+ inputs=image_input)
127
+ process_button = gr.Button("Process")
128
+ with gr.Column():
129
+ with gr.TabItem("Image"):
130
+ image_output = gr.Image(type="pil")
131
+ with gr.TabItem("Json"):
132
+ json_output = gr.JSON()
133
+
134
+ process_button.click(process_image, inputs=[image_input], outputs=[image_output, json_output])
135
+
136
+ gr.HTML('<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2Fopulentyn%2FLicensePlateRecognition"><img src="https://api.visitorbadge.io/api/combined?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2Fopulentyn%2FLicensePlateRecognition&countColor=%23263759" /></a>')
137
+
138
+ demo.launch(server_name="0.0.0.0", server_port=7860)
examples/1.jpg ADDED
examples/2.jpg ADDED
examples/3.jpg ADDED
install.sh ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ sudo cp lib/libopyalprenv.so /usr/lib
4
+ sudo cp lib/libtensorflow.so.2.6.0 /usr/lib
5
+ sudo ln -s /usr/lib/libtensorflow.so.2.6.0 /usr/lib/libtensorflow.so.2
6
+ sudo ln -s /usr/lib/libtensorflow.so.2.6.0 /usr/lib/libtensorflow.so.1
7
+ sudo ln -s /usr/lib/libtensorflow.so.2.6.0 /usr/lib/libtensorflow.so
8
+
9
+ sudo cp lib/libtensorflow_framework.so.2.6.0 /usr/lib
10
+ sudo ln -s /usr/lib/libtensorflow_framework.so.2.6.0 /usr/lib/libtensorflow_framework.so.2
11
+ sudo ln -s /usr/lib/libtensorflow_framework.so.2.6.0 /usr/lib/libtensorflow_framework.so
12
+
lib/libopymrz.so ADDED
Binary file (143 kB). View file
 
lib/libopymrzenv.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a7bc2fa32aaab5d33d00b2564bfa78df9f4679fa16eebe4ccdb326dfec07a660
3
+ size 7815696
license.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ahdgG47dPO63awosnVCE6Q/H+Sk32sSJ7Lmvsxp9WoZiSdgej8wh+DjBQ2k2enKtNifOTGW+gqZVFhfcHXkVh4m3xSzQVWSmhUy06suXiH7bKJvzH0NdOY2yI2Mqn5gSqsqwhwQ4+HC5Ol4c3qAUJ0OwmEQx4qxYEofo3LK5uTc=
model/mrza.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4fa21576a1560c2b59dd162f7724ace6d24bb7dc8457655711061c9dc96e3401
3
+ size 206077
model/mrzb.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5f29db8fc03c1967f98db0e1cc199d3833afc9c1b9f6240c41fb5df82e4181cd
3
+ size 854532
model/params.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:652ec3e813f23502e4c864e4a8c72272c41345006d818453e5ae5b593c6e925f
3
+ size 518
model/s.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:202360e0ddf5ada547b21c1da2a4f09ac6fc9cb035e8d1e2480ecdda79bc4554
3
+ size 1452847
opymrz.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ from ctypes import *
4
+ from numpy.ctypeslib import ndpointer
5
+
6
+ libPath = os.path.abspath(os.path.dirname(__file__)) + '/lib/libopymrzenv.so'
7
+ libopymrzenv = cdll.LoadLibrary(libPath)
8
+
9
+ libPath = os.path.abspath(os.path.dirname(__file__)) + '/lib/libopymrz.so'
10
+ libopymrz = cdll.LoadLibrary(libPath)
11
+
12
+ getHWID = libopymrz.getHWID
13
+ getHWID.argtypes = []
14
+ getHWID.restype = c_char_p
15
+
16
+ setLicenseKey = libopymrz.setLicenseKey
17
+ setLicenseKey.argtypes = [c_char_p]
18
+ setLicenseKey.restype = c_int32
19
+
20
+ initSDK = libopymrz.initSDK
21
+ initSDK.argtypes = [c_char_p]
22
+ initSDK.restype = c_int32
23
+
24
+ processImage = libopymrz.processImage
25
+ processImage.argtypes = [ndpointer(c_ubyte, flags='C_CONTIGUOUS'), c_int32, c_int32]
26
+ processImage.restype = c_char_p
27
+
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ flask
2
+ flask-cors
3
+ gradio
4
+ datadog_api_client
run.sh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ cd /home/opyalpr
4
+ exec python3 demo.py &
5
+ exec python3 app.py