Upload 33 files
Browse files- .gitignore +1 -0
- Dockerfile +13 -0
- README.md +187 -11
- app.py +79 -0
- data/detect.bin +3 -0
- data/eye.bin +3 -0
- data/landmark.bin +3 -0
- data/templates.bin +3 -0
- gradio/demo.py +357 -0
- gradio/face_examples/1.jpg +0 -0
- gradio/face_examples/10.jpg +0 -0
- gradio/face_examples/2.jpg +0 -0
- gradio/face_examples/3.jpg +0 -0
- gradio/face_examples/4.jpg +0 -0
- gradio/face_examples/5.jpg +0 -0
- gradio/face_examples/6.jpg +0 -0
- gradio/face_examples/7.jpg +0 -0
- gradio/face_examples/8.jpg +0 -0
- gradio/face_examples/9.jpg +0 -0
- gradio/idcard_examples/1.jpg +0 -0
- gradio/idcard_examples/2.jpg +0 -0
- gradio/idcard_examples/3.jpg +0 -0
- gradio/live_examples/1.jpg +0 -0
- gradio/live_examples/2.jpg +0 -0
- gradio/live_examples/3.jpg +0 -0
- gradio/live_examples/4.jpg +0 -0
- header/idsdk.h +42 -0
- idsdk.py +23 -0
- license.txt +6 -0
- postman/kby-ai-idcard.postman_collection.json +73 -0
- requirements.txt +2 -0
.gitignore
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
/data
|
Dockerfile
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.8-slim
|
2 |
+
RUN apt-get update -y
|
3 |
+
RUN apt-get install -y libpcsclite-dev psmisc
|
4 |
+
RUN mkdir -p /root/kby-ai-idcard
|
5 |
+
WORKDIR /root/kby-ai-idcard
|
6 |
+
COPY ./libidsdk.so .
|
7 |
+
COPY ./idsdk.py .
|
8 |
+
COPY ./app.py .
|
9 |
+
COPY ./requirements.txt .
|
10 |
+
COPY ./data ./data
|
11 |
+
RUN pip3 install -r requirements.txt
|
12 |
+
CMD [ "python3", "app.py"]
|
13 |
+
EXPOSE 8080
|
README.md
CHANGED
@@ -1,11 +1,187 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<p align="center">
|
2 |
+
<a href="https://play.google.com/store/apps/dev?id=7086930298279250852" target="_blank">
|
3 |
+
<img alt="" src="https://github-production-user-asset-6210df.s3.amazonaws.com/125717930/246971879-8ce757c3-90dc-438d-807f-3f3d29ddc064.png" width=500/>
|
4 |
+
</a>
|
5 |
+
</p>
|
6 |
+
|
7 |
+
👏 Product List
|
8 |
+
|
9 |
+
https://github.com/kby-ai/Product
|
10 |
+
|
11 |
+
👏 We have published the Face Liveness Detection, Face Recognition SDK and ID Card Recognition SDK for the server.
|
12 |
+
|
13 |
+
- [FaceLivenessDetection-Docker](https://github.com/kby-ai/FaceLivenessDetection-Docker)
|
14 |
+
|
15 |
+
- [FaceRecognition-Docker](https://github.com/kby-ai/FaceRecognition-Docker)
|
16 |
+
|
17 |
+
- [IDCardRecognition-Docker](https://github.com/kby-ai/IDCardRecognition-Docker)
|
18 |
+
|
19 |
+
# IDCardRecognition-Docker
|
20 |
+
|
21 |
+
## Introduction
|
22 |
+
|
23 |
+
The demo project demonstrates the server-based recognition capabilities for ID cards, passports, and driver's licenses.
|
24 |
+
|
25 |
+
At the core of this project lies the ID Card Recognition SDK, which has been developed to provide comprehensive support for recognizing ID cards, passports, and driver's licenses from over 180 countries.
|
26 |
+
|
27 |
+
> The demo is integrated with KBY-AI's ID Card Recognition Server SDK.
|
28 |
+
|
29 |
+
> For other solutions, please explore the following:
|
30 |
+
>
|
31 |
+
> [Face Liveness Detection - Android(Basic SDK)](https://github.com/kby-ai/FaceLivenessDetection-Android)
|
32 |
+
>
|
33 |
+
> [Face Liveness Detection - iOS(Basic SDK)](https://github.com/kby-ai/FaceLivenessDetection-iOS)
|
34 |
+
>
|
35 |
+
> [Face Recognition - Android(Stdndard SDK)](https://github.com/kby-ai/FaceRecognition-Android)
|
36 |
+
>
|
37 |
+
> [Face Recognition - iOS(Standard SDK)](https://github.com/kby-ai/FaceRecognition-iOS)
|
38 |
+
>
|
39 |
+
> [Face Recognition - Flutter(Standard SDK)](https://github.com/kby-ai/FaceRecognition-Flutter)
|
40 |
+
>
|
41 |
+
> [Face Recognition - React-Native(Standard SDK)](https://github.com/kby-ai/FaceRecognition-React-Native)
|
42 |
+
>
|
43 |
+
> [Face Attribute - Android(Premium SDK)](https://github.com/kby-ai/FaceAttribute-Android)
|
44 |
+
>
|
45 |
+
> [Face Attribute - iOS(Premium SDK)](https://github.com/kby-ai/FaceAttribute-iOS)
|
46 |
+
|
47 |
+
## Try the API
|
48 |
+
### Online Demo
|
49 |
+
You can test the SDK using images from the following URL:
|
50 |
+
https://web.kby-ai.com
|
51 |
+
|
52 |
+

|
53 |
+
|
54 |
+
### Postman
|
55 |
+
To test the API, you can use Postman. Here are the endpoints for testing:
|
56 |
+
- Test with an image file: Send a POST request to http://18.221.33.238:8082/idcard_recognition
|
57 |
+
- Test with a base64-encoded image: Send a POST request to http://18.221.33.238:8082/idcard_recognition_base64
|
58 |
+
|
59 |
+
You can download the Postman collection to easily access and use these endpoints. [click here](https://github.com/kby-ai/IDCardRecognition-Docker/tree/main/postman/kby-ai-idcard.postman_collection.json)
|
60 |
+
|
61 |
+

|
62 |
+
|
63 |
+
## SDK License
|
64 |
+
|
65 |
+
This project uses KBY-AI's Face Recognition Server SDK, which requires a license per machine.
|
66 |
+
|
67 |
+
- The code below shows how to use the license: https://github.com/kby-ai/IDCardRecognition-Docker/blob/9f8138fa83d39a80a95e71b52048dbfc6579558c/app.py#L14-L25
|
68 |
+
|
69 |
+
- In order to request the license, please provide us with the machine code obtained from the "getMachineCode" function.
|
70 |
+
|
71 |
+
Please contact us:
|
72 |
+
```
|
73 |
+
Email: [email protected]
|
74 |
+
|
75 |
+
Telegram: @kbyai
|
76 |
+
|
77 |
+
WhatsApp: +19092802609
|
78 |
+
|
79 |
+
Skype: live:.cid.66e2522354b1049b
|
80 |
+
|
81 |
+
## How to run
|
82 |
+
|
83 |
+
### 1. System Requirements
|
84 |
+
- CPU: 2 cores or more (Recommended: 2 cores)
|
85 |
+
- RAM: 4 GB or more (Recommended: 8 GB)
|
86 |
+
- HDD: 4 GB or more (Recommended: 8 GB)
|
87 |
+
- OS: Ubuntu 20.04 or later
|
88 |
+
|
89 |
+
### 2. Setup and Test
|
90 |
+
- Clone the project:
|
91 |
+
```
|
92 |
+
git clone https://github.com/kby-ai/IDCardRecognition-Docker.git
|
93 |
+
```
|
94 |
+
- Download the model from Google Drive: [click here](https://drive.google.com/file/d/19vA7ZOlo19BcW8v4iCoCGahUEbgKCo48/view?usp=sharing)
|
95 |
+
```
|
96 |
+
cd IDCardRecognition-Docker
|
97 |
+
|
98 |
+
wget --load-cookies /tmp/cookies.txt "https://docs.google.com/uc?export=download&confirm=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate 'https://docs.google.com/uc?export=download&id=1fmTUG7a9IoMA8QiXR9A0xf3Cr6D5UkdC' -O- | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\1\n/p')&id=1fmTUG7a9IoMA8QiXR9A0xf3Cr6D5UkdC" -O data.zip && rm -rf /tmp/cookies.txt
|
99 |
+
|
100 |
+
unzip data.zip
|
101 |
+
```
|
102 |
+
- Build the Docker image:
|
103 |
+
```
|
104 |
+
sudo docker build --pull --rm -f Dockerfile -t kby-ai-idcard:latest .
|
105 |
+
```
|
106 |
+
- Run the Docker container:
|
107 |
+
```
|
108 |
+
sudo docker run -v ./license.txt:/root/kby-ai-idcard/license.txt -p 8082:8080 kby-ai-idcard
|
109 |
+
```
|
110 |
+
- Send us the machine code and then we will give you a license key.
|
111 |
+
|
112 |
+
After that, update the license.txt file by overwriting the license key that you received. Then, run the Docker container again.
|
113 |
+
|
114 |
+

|
115 |
+
|
116 |
+

|
117 |
+
|
118 |
+
- To test the API, you can use Postman. Here are the endpoints for testing:
|
119 |
+
|
120 |
+
Test with an image file: Send a POST request to http://{xx.xx.xx.xx}:8082/idcard_recognition
|
121 |
+
|
122 |
+
Test with a base64-encoded image: Send a POST request to http://{xx.xx.xx.xx}:8082/idcard_recognition_base64
|
123 |
+
|
124 |
+
You can download the Postman collection to easily access and use these endpoints. [click here](https://github.com/kby-ai/IDCardRecognition-Docker/tree/main/postman/kby-ai-idcard.postman_collection.json)
|
125 |
+
|
126 |
+
### 3. Execute the Gradio demo
|
127 |
+
- Setup Gradio
|
128 |
+
Ensure that you have the necessary dependencies installed.
|
129 |
+
|
130 |
+
Gradio requires Python 3.6 or above.
|
131 |
+
|
132 |
+
You can install Gradio using pip by running the following command:
|
133 |
+
```
|
134 |
+
pip install gradio
|
135 |
+
```
|
136 |
+
- Run the demo
|
137 |
+
Run it using the following command:
|
138 |
+
```
|
139 |
+
cd gradio
|
140 |
+
python demo.py
|
141 |
+
```
|
142 |
+
- You can test within the following URL:
|
143 |
+
http://127.0.0.1:9000
|
144 |
+
|
145 |
+
## About SDK
|
146 |
+
|
147 |
+
### 1. Initializing the SDK
|
148 |
+
|
149 |
+
- Step One
|
150 |
+
|
151 |
+
First, obtain the machine code for activation and request a license based on the machine code.
|
152 |
+
```
|
153 |
+
machineCode = getMachineCode()
|
154 |
+
print("machineCode: ", machineCode.decode('utf-8'))
|
155 |
+
```
|
156 |
+
|
157 |
+
- Step Two
|
158 |
+
|
159 |
+
Next, activate the SDK using the received license.
|
160 |
+
```
|
161 |
+
setActivation(license.encode('utf-8'))
|
162 |
+
```
|
163 |
+
If activation is successful, the return value will be SDK_SUCCESS. Otherwise, an error value will be returned.
|
164 |
+
|
165 |
+
- Step Three
|
166 |
+
|
167 |
+
After activation, call the initialization function of the SDK.
|
168 |
+
```
|
169 |
+
initSDK()
|
170 |
+
```
|
171 |
+
If initialization is successful, the return value will be SDK_SUCCESS. Otherwise, an error value will be returned.
|
172 |
+
|
173 |
+
### 2. APIs
|
174 |
+
|
175 |
+
- ID Card Recognition
|
176 |
+
|
177 |
+
The SDK provides a single API for ID card recognition.
|
178 |
+
|
179 |
+
The function can be used as follows:
|
180 |
+
|
181 |
+
```
|
182 |
+
ret = idcardRecognition(base64_image.encode('utf-8'))
|
183 |
+
```
|
184 |
+
|
185 |
+
The function accepts only one parameter, which should be the base64-encoded format of the image (e.g., JPG, PNG, etc.).
|
186 |
+
|
187 |
+
If the recognition is successful, the function will return a JSON-formatted string containing the recognized information. In case of failure, the return value will be NULL.
|
app.py
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
sys.path.append('.')
|
3 |
+
|
4 |
+
import os
|
5 |
+
import base64
|
6 |
+
import json
|
7 |
+
|
8 |
+
from flask import Flask, request, jsonify
|
9 |
+
from idsdk import getMachineCode
|
10 |
+
from idsdk import setActivation
|
11 |
+
from idsdk import initSDK
|
12 |
+
from idsdk import idcardRecognition
|
13 |
+
|
14 |
+
licensePath = "license.txt"
|
15 |
+
license = ""
|
16 |
+
|
17 |
+
machineCode = getMachineCode()
|
18 |
+
print("machineCode: ", machineCode.decode('utf-8'))
|
19 |
+
|
20 |
+
try:
|
21 |
+
with open(licensePath, 'r') as file:
|
22 |
+
license = file.read()
|
23 |
+
except IOError as exc:
|
24 |
+
print("failed to open license.txt: ", exc.errno)
|
25 |
+
print("license: ", license)
|
26 |
+
|
27 |
+
ret = setActivation(license.encode('utf-8'))
|
28 |
+
print("activation: ", ret)
|
29 |
+
|
30 |
+
ret = initSDK()
|
31 |
+
print("init: ", ret)
|
32 |
+
|
33 |
+
app = Flask(__name__)
|
34 |
+
|
35 |
+
@app.route('/idcard_recognition', methods=['POST'])
|
36 |
+
def idcard_recognition():
|
37 |
+
try:
|
38 |
+
file = request.files['file']
|
39 |
+
|
40 |
+
base64_image = base64.b64encode(file.read()).decode('utf-8')
|
41 |
+
ret = idcardRecognition(base64_image.encode('utf-8'))
|
42 |
+
|
43 |
+
if ret != None:
|
44 |
+
j = json.loads(ret)
|
45 |
+
j.update({"Status": "Ok"})
|
46 |
+
response = jsonify(j)
|
47 |
+
else:
|
48 |
+
response = jsonify({"Status": "Error"})
|
49 |
+
except:
|
50 |
+
response = jsonify({"Status": "Error"})
|
51 |
+
|
52 |
+
response.status_code = 200
|
53 |
+
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
54 |
+
return response
|
55 |
+
|
56 |
+
@app.route('/idcard_recognition_base64', methods=['POST'])
|
57 |
+
def idcard_recognition_base64():
|
58 |
+
try:
|
59 |
+
content = request.get_json()
|
60 |
+
base64_image = content['base64']
|
61 |
+
|
62 |
+
ret = idcardRecognition(base64_image.encode('utf-8'))
|
63 |
+
|
64 |
+
if ret != None:
|
65 |
+
j = json.loads(ret)
|
66 |
+
j.update({"Status": "Ok"})
|
67 |
+
response = jsonify(j)
|
68 |
+
else:
|
69 |
+
response = jsonify({"Status": "Error"})
|
70 |
+
except:
|
71 |
+
response = jsonify({"Status": "Error"})
|
72 |
+
|
73 |
+
response.status_code = 200
|
74 |
+
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
75 |
+
return response
|
76 |
+
|
77 |
+
if __name__ == '__main__':
|
78 |
+
port = int(os.environ.get("PORT", 8080))
|
79 |
+
app.run(host='0.0.0.0', port=port)
|
data/detect.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:0b505c320dd8add047f107549849a307d0c6f518f01c1d3402bce9e13a765146
|
3 |
+
size 28463173
|
data/eye.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:c8281f9113d6fa4cc2f94ac8f4fdd3dbb7004b27adad39ac7175a802f9aaeed1
|
3 |
+
size 2446608
|
data/landmark.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:b95b4e6043add90c16f97f00990973a6f8c6f3511491358772e734aa20f606bd
|
3 |
+
size 10828783
|
data/templates.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:9214b2a4e3a83dffd64264e473ca60abe160bc5a4b9362dabc038e4a8618bfcf
|
3 |
+
size 87370348
|
gradio/demo.py
ADDED
@@ -0,0 +1,357 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import requests
|
3 |
+
import datadog_api_client
|
4 |
+
from PIL import Image
|
5 |
+
|
6 |
+
def check_liveness(frame):
|
7 |
+
url = "http://127.0.0.1:8080/check_liveness"
|
8 |
+
file = {'file': open(frame, 'rb')}
|
9 |
+
|
10 |
+
r = requests.post(url=url, files=file)
|
11 |
+
result = r.json().get('face_state').get('result')
|
12 |
+
|
13 |
+
html = None
|
14 |
+
faces = None
|
15 |
+
if r.json().get('face_state').get('is_not_front') is not None:
|
16 |
+
liveness_score = r.json().get('face_state').get('liveness_score')
|
17 |
+
eye_closed = r.json().get('face_state').get('eye_closed')
|
18 |
+
is_boundary_face = r.json().get('face_state').get('is_boundary_face')
|
19 |
+
is_not_front = r.json().get('face_state').get('is_not_front')
|
20 |
+
is_occluded = r.json().get('face_state').get('is_occluded')
|
21 |
+
is_small = r.json().get('face_state').get('is_small')
|
22 |
+
luminance = r.json().get('face_state').get('luminance')
|
23 |
+
mouth_opened = r.json().get('face_state').get('mouth_opened')
|
24 |
+
quality = r.json().get('face_state').get('quality')
|
25 |
+
|
26 |
+
html = ("<table>"
|
27 |
+
"<tr>"
|
28 |
+
"<th>Face State</th>"
|
29 |
+
"<th>Value</th>"
|
30 |
+
"</tr>"
|
31 |
+
"<tr>"
|
32 |
+
"<td>Result</td>"
|
33 |
+
"<td>{result}</td>"
|
34 |
+
"</tr>"
|
35 |
+
"<tr>"
|
36 |
+
"<td>Liveness Score</td>"
|
37 |
+
"<td>{liveness_score}</td>"
|
38 |
+
"</tr>"
|
39 |
+
"<tr>"
|
40 |
+
"<td>Quality</td>"
|
41 |
+
"<td>{quality}</td>"
|
42 |
+
"</tr>"
|
43 |
+
"<tr>"
|
44 |
+
"<td>Luminance</td>"
|
45 |
+
"<td>{luminance}</td>"
|
46 |
+
"</tr>"
|
47 |
+
"<tr>"
|
48 |
+
"<td>Is Small</td>"
|
49 |
+
"<td>{is_small}</td>"
|
50 |
+
"</tr>"
|
51 |
+
"<tr>"
|
52 |
+
"<td>Is Boundary</td>"
|
53 |
+
"<td>{is_boundary_face}</td>"
|
54 |
+
"</tr>"
|
55 |
+
"<tr>"
|
56 |
+
"<td>Is Not Front</td>"
|
57 |
+
"<td>{is_not_front}</td>"
|
58 |
+
"</tr>"
|
59 |
+
"<tr>"
|
60 |
+
"<td>Face Occluded</td>"
|
61 |
+
"<td>{is_occluded}</td>"
|
62 |
+
"</tr>"
|
63 |
+
"<tr>"
|
64 |
+
"<td>Eye Closed</td>"
|
65 |
+
"<td>{eye_closed}</td>"
|
66 |
+
"</tr>"
|
67 |
+
"<tr>"
|
68 |
+
"<td>Mouth Opened</td>"
|
69 |
+
"<td>{mouth_opened}</td>"
|
70 |
+
"</tr>"
|
71 |
+
"</table>".format(liveness_score=liveness_score, quality=quality, luminance=luminance, is_small=is_small, is_boundary_face=is_boundary_face,
|
72 |
+
is_not_front=is_not_front, is_occluded=is_occluded, eye_closed=eye_closed, mouth_opened=mouth_opened, result=result))
|
73 |
+
|
74 |
+
else:
|
75 |
+
html = ("<table>"
|
76 |
+
"<tr>"
|
77 |
+
"<th>Face State</th>"
|
78 |
+
"<th>Value</th>"
|
79 |
+
"</tr>"
|
80 |
+
"<tr>"
|
81 |
+
"<td>Result</td>"
|
82 |
+
"<td>{result}</td>"
|
83 |
+
"</tr>"
|
84 |
+
"</table>".format(result=result))
|
85 |
+
|
86 |
+
try:
|
87 |
+
image = Image.open(frame)
|
88 |
+
|
89 |
+
for face in r.json().get('faces'):
|
90 |
+
x1 = face.get('x1')
|
91 |
+
y1 = face.get('y1')
|
92 |
+
x2 = face.get('x2')
|
93 |
+
y2 = face.get('y2')
|
94 |
+
|
95 |
+
if x1 < 0:
|
96 |
+
x1 = 0
|
97 |
+
if y1 < 0:
|
98 |
+
y1 = 0
|
99 |
+
if x2 >= image.width:
|
100 |
+
x2 = image.width - 1
|
101 |
+
if y2 >= image.height:
|
102 |
+
y2 = image.height - 1
|
103 |
+
|
104 |
+
face_image = image.crop((x1, y1, x2, y2))
|
105 |
+
face_image_ratio = face_image.width / float(face_image.height)
|
106 |
+
resized_w = int(face_image_ratio * 150)
|
107 |
+
resized_h = 150
|
108 |
+
|
109 |
+
face_image = face_image.resize((int(resized_w), int(resized_h)))
|
110 |
+
|
111 |
+
if faces is None:
|
112 |
+
faces = face_image
|
113 |
+
else:
|
114 |
+
new_image = Image.new('RGB',(faces.width + face_image.width + 10, 150), (80,80,80))
|
115 |
+
|
116 |
+
new_image.paste(faces,(0,0))
|
117 |
+
new_image.paste(face_image,(faces.width + 10, 0))
|
118 |
+
faces = new_image.copy()
|
119 |
+
except:
|
120 |
+
pass
|
121 |
+
|
122 |
+
return [faces, html]
|
123 |
+
|
124 |
+
def compare_face(frame1, frame2):
|
125 |
+
url = "http://127.0.0.1:8081/compare_face"
|
126 |
+
files = {'file1': open(frame1, 'rb'), 'file2': open(frame2, 'rb')}
|
127 |
+
|
128 |
+
r = requests.post(url=url, files=files)
|
129 |
+
|
130 |
+
html = None
|
131 |
+
faces = None
|
132 |
+
|
133 |
+
compare_result = r.json().get('compare_result')
|
134 |
+
compare_similarity = r.json().get('compare_similarity')
|
135 |
+
|
136 |
+
html = ("<table>"
|
137 |
+
"<tr>"
|
138 |
+
"<th>Compare Result</th>"
|
139 |
+
"<th>Value</th>"
|
140 |
+
"</tr>"
|
141 |
+
"<tr>"
|
142 |
+
"<td>Result</td>"
|
143 |
+
"<td>{compare_result}</td>"
|
144 |
+
"</tr>"
|
145 |
+
"<tr>"
|
146 |
+
"<td>Similarity</td>"
|
147 |
+
"<td>{compare_similarity}</td>"
|
148 |
+
"</tr>"
|
149 |
+
"</table>".format(compare_result=compare_result, compare_similarity=compare_similarity))
|
150 |
+
|
151 |
+
try:
|
152 |
+
image1 = Image.open(frame1)
|
153 |
+
image2 = Image.open(frame2)
|
154 |
+
|
155 |
+
face1 = None
|
156 |
+
face2 = None
|
157 |
+
|
158 |
+
if r.json().get('face1') is not None:
|
159 |
+
face = r.json().get('face1')
|
160 |
+
x1 = face.get('x1')
|
161 |
+
y1 = face.get('y1')
|
162 |
+
x2 = face.get('x2')
|
163 |
+
y2 = face.get('y2')
|
164 |
+
|
165 |
+
if x1 < 0:
|
166 |
+
x1 = 0
|
167 |
+
if y1 < 0:
|
168 |
+
y1 = 0
|
169 |
+
if x2 >= image1.width:
|
170 |
+
x2 = image1.width - 1
|
171 |
+
if y2 >= image1.height:
|
172 |
+
y2 = image1.height - 1
|
173 |
+
|
174 |
+
face1 = image1.crop((x1, y1, x2, y2))
|
175 |
+
face_image_ratio = face1.width / float(face1.height)
|
176 |
+
resized_w = int(face_image_ratio * 150)
|
177 |
+
resized_h = 150
|
178 |
+
|
179 |
+
face1 = face1.resize((int(resized_w), int(resized_h)))
|
180 |
+
|
181 |
+
if r.json().get('face2') is not None:
|
182 |
+
face = r.json().get('face2')
|
183 |
+
x1 = face.get('x1')
|
184 |
+
y1 = face.get('y1')
|
185 |
+
x2 = face.get('x2')
|
186 |
+
y2 = face.get('y2')
|
187 |
+
|
188 |
+
if x1 < 0:
|
189 |
+
x1 = 0
|
190 |
+
if y1 < 0:
|
191 |
+
y1 = 0
|
192 |
+
if x2 >= image2.width:
|
193 |
+
x2 = image2.width - 1
|
194 |
+
if y2 >= image2.height:
|
195 |
+
y2 = image2.height - 1
|
196 |
+
|
197 |
+
face2 = image2.crop((x1, y1, x2, y2))
|
198 |
+
face_image_ratio = face2.width / float(face2.height)
|
199 |
+
resized_w = int(face_image_ratio * 150)
|
200 |
+
resized_h = 150
|
201 |
+
|
202 |
+
face2 = face2.resize((int(resized_w), int(resized_h)))
|
203 |
+
|
204 |
+
if face1 is not None and face2 is not None:
|
205 |
+
new_image = Image.new('RGB',(face1.width + face2.width + 10, 150), (80,80,80))
|
206 |
+
|
207 |
+
new_image.paste(face1,(0,0))
|
208 |
+
new_image.paste(face2,(face1.width + 10, 0))
|
209 |
+
faces = new_image.copy()
|
210 |
+
elif face1 is not None and face2 is None:
|
211 |
+
new_image = Image.new('RGB',(face1.width + face1.width + 10, 150), (80,80,80))
|
212 |
+
|
213 |
+
new_image.paste(face1,(0,0))
|
214 |
+
faces = new_image.copy()
|
215 |
+
elif face1 is None and face2 is not None:
|
216 |
+
new_image = Image.new('RGB',(face2.width + face2.width + 10, 150), (80,80,80))
|
217 |
+
|
218 |
+
new_image.paste(face2,(face2.width + 10, 0))
|
219 |
+
faces = new_image.copy()
|
220 |
+
|
221 |
+
except:
|
222 |
+
pass
|
223 |
+
|
224 |
+
return [faces, html]
|
225 |
+
|
226 |
+
def idcard_recognition(frame):
|
227 |
+
url = "http://127.0.0.1:8082/idcard_recognition"
|
228 |
+
files = {'file': open(frame, 'rb')}
|
229 |
+
|
230 |
+
r = requests.post(url=url, files=files)
|
231 |
+
|
232 |
+
html = None
|
233 |
+
images = None
|
234 |
+
mrz = None
|
235 |
+
|
236 |
+
status = r.json().get('Status')
|
237 |
+
table_value = ""
|
238 |
+
|
239 |
+
if r.json().get('MRZ') is not None:
|
240 |
+
mrz = r.json().get('MRZ')
|
241 |
+
|
242 |
+
for key, value in r.json().items():
|
243 |
+
if key == 'Status' or key == 'Images' or key == 'MRZ' or key == 'Position':
|
244 |
+
continue
|
245 |
+
|
246 |
+
mrz_value = ''
|
247 |
+
if mrz is not None and mrz.get(key) is not None:
|
248 |
+
mrz_value = mrz[key]
|
249 |
+
del mrz[key]
|
250 |
+
|
251 |
+
row_value = ("<tr>"
|
252 |
+
"<td>{key}</td>"
|
253 |
+
"<td>{value}</td>"
|
254 |
+
"<td>{mrz_value}</td>"
|
255 |
+
"</tr>".format(key=key, value=value, mrz_value=mrz_value))
|
256 |
+
table_value = table_value + row_value
|
257 |
+
|
258 |
+
|
259 |
+
if mrz is not None:
|
260 |
+
for key, value in mrz.items():
|
261 |
+
if key == 'MRZ':
|
262 |
+
value = value.replace('<', '<')
|
263 |
+
value = value.replace(',', '<p>')
|
264 |
+
|
265 |
+
row_value = ("<tr>"
|
266 |
+
"<td>{key}</td>"
|
267 |
+
"<td>{value}</td>"
|
268 |
+
"<td>{mrz_value}</td>"
|
269 |
+
"</tr>".format(key=key, value='', mrz_value=value))
|
270 |
+
table_value = table_value + row_value
|
271 |
+
|
272 |
+
|
273 |
+
html = ("<table>"
|
274 |
+
"<tr>"
|
275 |
+
"<th style=""width:20%"">Field</th>"
|
276 |
+
"<th style=""width:40%"">Value</th>"
|
277 |
+
"<th style=""width:40%"">MRZ</th>"
|
278 |
+
"</tr>"
|
279 |
+
"<tr>"
|
280 |
+
"<td>Status</td>"
|
281 |
+
"<td>{status}</td>"
|
282 |
+
"<td></td>"
|
283 |
+
"</tr>"
|
284 |
+
"{table_value}"
|
285 |
+
"</table>".format(status=status, table_value=table_value))
|
286 |
+
|
287 |
+
table_value = ""
|
288 |
+
for key, value in r.json().items():
|
289 |
+
if key == 'Images':
|
290 |
+
for image_key, image_value in value.items():
|
291 |
+
row_value = ("<tr>"
|
292 |
+
"<td>{key}</td>"
|
293 |
+
"<td><img src=""data:image/png;base64,{base64_image} width = '200' height= '100' /></td>"
|
294 |
+
"</tr>".format(key=image_key, base64_image=image_value))
|
295 |
+
table_value = table_value + row_value
|
296 |
+
|
297 |
+
images = ("<table>"
|
298 |
+
"<tr>"
|
299 |
+
"<th>Field</th>"
|
300 |
+
"<th>Image</th>"
|
301 |
+
"</tr>"
|
302 |
+
"{table_value}"
|
303 |
+
"</table>".format(table_value=table_value))
|
304 |
+
|
305 |
+
return [html, images]
|
306 |
+
|
307 |
+
with gr.Blocks() as demo:
|
308 |
+
gr.Markdown(
|
309 |
+
"""
|
310 |
+
# KBY-AI Technology
|
311 |
+
We offer SDKs for face recognition, liveness detection, and ID card recognition.
|
312 |
+
"""
|
313 |
+
)
|
314 |
+
with gr.TabItem("Face Liveness Detection"):
|
315 |
+
with gr.Row():
|
316 |
+
with gr.Column():
|
317 |
+
live_image_input = gr.Image(type='filepath')
|
318 |
+
gr.Examples(['live_examples/1.jpg', 'live_examples/2.jpg', 'live_examples/3.jpg', 'live_examples/4.jpg'],
|
319 |
+
inputs=live_image_input)
|
320 |
+
check_liveness_button = gr.Button("Check Liveness")
|
321 |
+
with gr.Column():
|
322 |
+
liveness_face_output = gr.Image(type="pil").style(height=150)
|
323 |
+
livness_result_output = gr.HTML()
|
324 |
+
|
325 |
+
check_liveness_button.click(check_liveness, inputs=live_image_input, outputs=[liveness_face_output, livness_result_output])
|
326 |
+
with gr.TabItem("Face Recognition"):
|
327 |
+
with gr.Row():
|
328 |
+
with gr.Column():
|
329 |
+
compare_face_input1 = gr.Image(type='filepath')
|
330 |
+
gr.Examples(['face_examples/1.jpg', 'face_examples/3.jpg', 'face_examples/5.jpg', 'face_examples/7.jpg', 'face_examples/9.jpg'],
|
331 |
+
inputs=compare_face_input1)
|
332 |
+
compare_face_button = gr.Button("Compare Face")
|
333 |
+
with gr.Column():
|
334 |
+
compare_face_input2 = gr.Image(type='filepath')
|
335 |
+
gr.Examples(['face_examples/2.jpg', 'face_examples/4.jpg', 'face_examples/6.jpg', 'face_examples/8.jpg', 'face_examples/10.jpg'],
|
336 |
+
inputs=compare_face_input2)
|
337 |
+
with gr.Column():
|
338 |
+
compare_face_output = gr.Image(type="pil").style(height=150)
|
339 |
+
compare_result_output = gr.HTML(label='Result')
|
340 |
+
|
341 |
+
compare_face_button.click(compare_face, inputs=[compare_face_input1, compare_face_input2], outputs=[compare_face_output, compare_result_output])
|
342 |
+
with gr.TabItem("ID Card Recognition"):
|
343 |
+
with gr.Row():
|
344 |
+
with gr.Column(scale=3):
|
345 |
+
id_image_input = gr.Image(type='filepath')
|
346 |
+
gr.Examples(['idcard_examples/1.jpg', 'idcard_examples/2.jpg', 'idcard_examples/3.jpg'],
|
347 |
+
inputs=id_image_input)
|
348 |
+
id_recognition_button = gr.Button("ID Card Recognition")
|
349 |
+
with gr.Column(scale=5):
|
350 |
+
id_result_output = gr.HTML()
|
351 |
+
|
352 |
+
with gr.Column(scale=2):
|
353 |
+
image_result_output = gr.HTML()
|
354 |
+
|
355 |
+
id_recognition_button.click(idcard_recognition, inputs=id_image_input, outputs=[id_result_output, image_result_output])
|
356 |
+
|
357 |
+
demo.launch(server_name="0.0.0.0", server_port=9000)
|
gradio/face_examples/1.jpg
ADDED
![]() |
gradio/face_examples/10.jpg
ADDED
![]() |
gradio/face_examples/2.jpg
ADDED
![]() |
gradio/face_examples/3.jpg
ADDED
![]() |
gradio/face_examples/4.jpg
ADDED
![]() |
gradio/face_examples/5.jpg
ADDED
![]() |
gradio/face_examples/6.jpg
ADDED
![]() |
gradio/face_examples/7.jpg
ADDED
![]() |
gradio/face_examples/8.jpg
ADDED
![]() |
gradio/face_examples/9.jpg
ADDED
![]() |
gradio/idcard_examples/1.jpg
ADDED
![]() |
gradio/idcard_examples/2.jpg
ADDED
![]() |
gradio/idcard_examples/3.jpg
ADDED
![]() |
gradio/live_examples/1.jpg
ADDED
![]() |
gradio/live_examples/2.jpg
ADDED
![]() |
gradio/live_examples/3.jpg
ADDED
![]() |
gradio/live_examples/4.jpg
ADDED
![]() |
header/idsdk.h
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
|
3 |
+
#ifdef __cplusplus
|
4 |
+
extern "C" {
|
5 |
+
#endif
|
6 |
+
|
7 |
+
enum SDK_ERROR
|
8 |
+
{
|
9 |
+
SDK_SUCCESS = 0,
|
10 |
+
SDK_LICENSE_KEY_ERROR = -1,
|
11 |
+
SDK_LICENSE_APPID_ERROR = -2,
|
12 |
+
SDK_LICENSE_EXPIRED = -3,
|
13 |
+
SDK_NO_ACTIVATED = -4,
|
14 |
+
SDK_INIT_ERROR = -5,
|
15 |
+
};
|
16 |
+
|
17 |
+
|
18 |
+
/*
|
19 |
+
* Get the machine code for SDK activation
|
20 |
+
*/
|
21 |
+
const char* getMachineCode();
|
22 |
+
|
23 |
+
/*
|
24 |
+
* Activate the SDK using the provided license
|
25 |
+
*/
|
26 |
+
|
27 |
+
int setActivation(char* license);
|
28 |
+
|
29 |
+
/*
|
30 |
+
* Initialize the SDK with the specified model path
|
31 |
+
*/
|
32 |
+
int initSDK();
|
33 |
+
|
34 |
+
/*
|
35 |
+
* The function accepts only one parameter, which should be the base64-encoded format of the image (e.g., JPG, PNG, etc.).
|
36 |
+
* If the recognition is successful, the function will return a JSON-formatted string containing the recognized information. In case of failure, the return value will be NULL.
|
37 |
+
*/
|
38 |
+
char* idcardRecognition(char* image_base64);
|
39 |
+
|
40 |
+
#ifdef __cplusplus
|
41 |
+
}
|
42 |
+
#endif
|
idsdk.py
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
from ctypes import *
|
4 |
+
|
5 |
+
libPath = os.path.abspath(os.path.dirname(__file__)) + '/libidsdk.so'
|
6 |
+
idsdk = cdll.LoadLibrary(libPath)
|
7 |
+
|
8 |
+
getMachineCode = idsdk.getMachineCode
|
9 |
+
getMachineCode.argtypes = []
|
10 |
+
getMachineCode.restype = c_char_p
|
11 |
+
|
12 |
+
setActivation = idsdk.setActivation
|
13 |
+
setActivation.argtypes = [c_char_p]
|
14 |
+
setActivation.restype = c_int32
|
15 |
+
|
16 |
+
initSDK = idsdk.initSDK
|
17 |
+
initSDK.argtypes = []
|
18 |
+
initSDK.restype = c_int32
|
19 |
+
|
20 |
+
idcardRecognition = idsdk.idcardRecognition
|
21 |
+
idcardRecognition.argtypes = [c_char_p]
|
22 |
+
idcardRecognition.restype = c_char_p
|
23 |
+
|
license.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
To obtain the license, please get in touch with us through the following contact details:
|
2 |
+
|
3 |
+
Email: [email protected]
|
4 |
+
Telegram: @kbyai
|
5 |
+
WhatsApp: +19092802609
|
6 |
+
Skype: live:.cid.66e2522354b1049b
|
postman/kby-ai-idcard.postman_collection.json
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"info": {
|
3 |
+
"_postman_id": "ae453c9a-d672-4e3d-bf4e-3847473197bc",
|
4 |
+
"name": "kby-ai-idcard",
|
5 |
+
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
6 |
+
"_exporter_id": "2379931"
|
7 |
+
},
|
8 |
+
"item": [
|
9 |
+
{
|
10 |
+
"name": "idcard_recognition",
|
11 |
+
"request": {
|
12 |
+
"method": "POST",
|
13 |
+
"header": [],
|
14 |
+
"body": {
|
15 |
+
"mode": "formdata",
|
16 |
+
"formdata": [
|
17 |
+
{
|
18 |
+
"key": "file",
|
19 |
+
"type": "file",
|
20 |
+
"src": []
|
21 |
+
}
|
22 |
+
]
|
23 |
+
},
|
24 |
+
"url": {
|
25 |
+
"raw": "http://18.221.33.238:8082/idcard_recognition",
|
26 |
+
"protocol": "http",
|
27 |
+
"host": [
|
28 |
+
"18",
|
29 |
+
"221",
|
30 |
+
"33",
|
31 |
+
"238"
|
32 |
+
],
|
33 |
+
"port": "8082",
|
34 |
+
"path": [
|
35 |
+
"idcard_recognition"
|
36 |
+
]
|
37 |
+
}
|
38 |
+
},
|
39 |
+
"response": []
|
40 |
+
},
|
41 |
+
{
|
42 |
+
"name": "idcard_recognition_base64",
|
43 |
+
"request": {
|
44 |
+
"method": "POST",
|
45 |
+
"header": [],
|
46 |
+
"body": {
|
47 |
+
"mode": "raw",
|
48 |
+
"raw": "{\r\n \"base64\":\"xxx\"\r\n}",
|
49 |
+
"options": {
|
50 |
+
"raw": {
|
51 |
+
"language": "json"
|
52 |
+
}
|
53 |
+
}
|
54 |
+
},
|
55 |
+
"url": {
|
56 |
+
"raw": "http://127.0.0.1:8082/idcard_recognition_base64",
|
57 |
+
"protocol": "http",
|
58 |
+
"host": [
|
59 |
+
"127",
|
60 |
+
"0",
|
61 |
+
"0",
|
62 |
+
"1"
|
63 |
+
],
|
64 |
+
"port": "8082",
|
65 |
+
"path": [
|
66 |
+
"idcard_recognition_base64"
|
67 |
+
]
|
68 |
+
}
|
69 |
+
},
|
70 |
+
"response": []
|
71 |
+
}
|
72 |
+
]
|
73 |
+
}
|
requirements.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
flask
|
2 |
+
flask-cors
|