Skip to content

Commit 87aeede

Browse files
author
jinhailiang
committed
rebuild git indexs for smaller size
0 parents  commit 87aeede

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+8512
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*.pyc
2+
.DS_Store
3+
.idea/
4+
capture/local_*/
5+
*.so

Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM python:3.6.5
2+
COPY ./api /vision/api/
3+
COPY ./service /vision/service/
4+
COPY ./dbnet_crnn /vision/dbnet_crnn
5+
COPY ./requirements.txt /vision/requirements.txt
6+
COPY ./server.py ./vision/server.py
7+
ARG PIP_MIRROR=https://mirrors.aliyun.com/pypi/simple/
8+
WORKDIR /vision
9+
RUN mkdir capture\
10+
&& pip install --upgrade pip -i ${PIP_MIRROR}\
11+
&& pip install -r requirements.txt -i ${PIP_MIRROR}
12+
CMD ["python3", "server.py"]

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 美团点评
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Vision UI
2+
3+
![GitHub](https://img.shields.io/badge/Python-3.6-blue)
4+
![GitHub](https://img.shields.io/github/license/Meituan-Dianping/vision-diff)
5+
![GitHub](https://img.shields.io/docker/cloud/build/brighthai/vision-ui)
6+
7+
## 什么是Vision UI
8+
9+
Vision UI是一组图像处理算法,来源于美团视觉测试工具,提供如视觉对比(增量式对比)、图像融合和文本识别。
10+
11+
本项目无需训练模型,基于训练模型的项目在[Vision-ml](https://github.com/Meituan-Dianping/vision)
12+
13+
## 特性
14+
15+
* 超越像素对比-[视觉对比](resources/vision_diff_cn.md)
16+
17+
* 基于模板匹配-[图像融合](resources/vision_merge.md)
18+
19+
* 集成模型-[文本识别](resources/vision_text.md)
20+
21+
22+
## 效果展示
23+
### 图像融合
24+
| 1.png | 2.png | 3.png | merge |
25+
| ------------------------------ | -------------------------------- | -------------------------------- | ------------------------------------- |
26+
| ![](image/1_0.png) | ![](image/1_1.png) | ![](image/1_2.png) | ![](image/1_merge.png)
27+
28+
### 视觉对比
29+
30+
| base | comparison | diff |
31+
| ------------------------------ | -------------------------------- | ------------------------------------- |
32+
| ![](image/base_1.png) | ![](image/comp_1.png) | ![](image/diff_1.png) |
33+
34+
35+
36+
37+
## License
38+
39+
This project is licensed under the [MIT](./LICENSE)
40+
41+

api/vision_api.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from flask import jsonify
2+
from flask import request
3+
from flask import Blueprint
4+
from flask import make_response
5+
from service.image_diff import ImageDiff
6+
from service.image_merge import Stitcher
7+
from service.image_similar import HashSimilar
8+
from service.image_text import get_image_text
9+
from service.image_utils import get_pop_v
10+
11+
vision = Blueprint('vision', __name__, url_prefix='/vision')
12+
13+
14+
@vision.route('/diff', methods=["POST"])
15+
def vision_diff():
16+
data = {
17+
"code": 0,
18+
"data": ImageDiff().get_image_score(request.json['image1'], request.json['image2'],
19+
request.json['image_diff_name'])
20+
}
21+
return jsonify(data)
22+
23+
24+
@vision.route('/merge', methods=["POST"])
25+
def vision_merge():
26+
data = {
27+
"code": 0,
28+
"data": Stitcher(request.json['image_list']).image_merge(
29+
request.json['name'],
30+
without_padding=request.json.get('without_padding')
31+
)
32+
}
33+
return jsonify(data)
34+
35+
36+
@vision.route('/similar', methods=["POST"])
37+
def vision_similar():
38+
data = {
39+
"code": 0,
40+
"data": HashSimilar().get_hash_similar(request.json['image1'], request.json['image2'])
41+
}
42+
return jsonify(data)
43+
44+
45+
@vision.route('/pop', methods=["POST"])
46+
def vision_pop():
47+
data = {
48+
"code": 0,
49+
"data": get_pop_v(request.json['image'])
50+
}
51+
return jsonify(data)
52+
53+
54+
@vision.route('/text', methods=["POST"])
55+
def vision_text():
56+
data = {
57+
"code": 0,
58+
"data": get_image_text(request.json['image'])
59+
}
60+
resp = make_response(jsonify(data))
61+
resp.headers["Content-Type"] = "application/json;charset=utf-8"
62+
return resp

capture/image_1.png

243 KB
Loading

dbnet_crnn/image_text.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import cv2
2+
import copy
3+
import numpy as np
4+
import dbnet_crnn.tools.utility as utility
5+
from service.image_utils import get_center_pos
6+
import dbnet_crnn.tools.predict_det as predict_det
7+
import dbnet_crnn.tools.predict_rec as predict_rec
8+
9+
10+
def sorted_boxes(dt_boxes):
11+
"""
12+
Sort text boxes in order from top to bottom, left to right
13+
args:
14+
dt_boxes(array):detected text boxes with shape [4, 2]
15+
return:
16+
sorted boxes(array) with shape [4, 2]
17+
"""
18+
num_boxes = dt_boxes.shape[0]
19+
sorted_boxes = sorted(dt_boxes, key=lambda x: (x[0][1], x[0][0]))
20+
_boxes = list(sorted_boxes)
21+
22+
for i in range(num_boxes - 1):
23+
if abs(_boxes[i+1][0][1] - _boxes[i][0][1]) < 10 and (_boxes[i + 1][0][0] < _boxes[i][0][0]):
24+
tmp = _boxes[i]
25+
_boxes[i] = _boxes[i + 1]
26+
_boxes[i + 1] = tmp
27+
return _boxes
28+
29+
30+
class ImageText(object):
31+
def __init__(self):
32+
args = utility.parse_args()
33+
self.text_detector = predict_det.TextDetector(args, model_path='dbnet_crnn/modelv1.1/det/')
34+
self.text_recognizer = predict_rec.TextRecognizer(args, model_path='dbnet_crnn/modelv1.1/rec/')
35+
36+
def get_rotate_crop_image(self, img, points):
37+
'''
38+
img_height, img_width = img.shape[0:2]
39+
left = int(np.min(points[:, 0]))
40+
right = int(np.max(points[:, 0]))
41+
top = int(np.min(points[:, 1]))
42+
bottom = int(np.max(points[:, 1]))
43+
img_crop = img[top:bottom, left:right, :].copy()
44+
points[:, 0] = points[:, 0] - left
45+
points[:, 1] = points[:, 1] - top
46+
'''
47+
img_crop_width = int(
48+
max(
49+
np.linalg.norm(points[0] - points[1]),
50+
np.linalg.norm(points[2] - points[3])))
51+
img_crop_height = int(
52+
max(
53+
np.linalg.norm(points[0] - points[3]),
54+
np.linalg.norm(points[1] - points[2])))
55+
pts_std = np.float32([[0, 0], [img_crop_width, 0],
56+
[img_crop_width, img_crop_height],
57+
[0, img_crop_height]])
58+
M = cv2.getPerspectiveTransform(points, pts_std)
59+
dst_img = cv2.warpPerspective(img, M, (img_crop_width, img_crop_height),
60+
borderMode=cv2.BORDER_REPLICATE,
61+
flags=cv2.INTER_CUBIC)
62+
dst_img_height, dst_img_width = dst_img.shape[0:2]
63+
if dst_img_height * 1.0 / dst_img_width >= 1.5:
64+
dst_img = np.rot90(dst_img)
65+
return dst_img
66+
67+
def get_ocr(self, img, max_side_len):
68+
ori_im = img.copy()
69+
dt_boxes = self.text_detector(img, max_side_len)
70+
if dt_boxes is None:
71+
return None, None
72+
img_crop_list = []
73+
dt_boxes = sorted_boxes(dt_boxes)
74+
for bno in range(len(dt_boxes)):
75+
tmp_box = copy.deepcopy(dt_boxes[bno])
76+
img_crop = self.get_rotate_crop_image(ori_im, tmp_box)
77+
img_crop_list.append(img_crop)
78+
rec_res = self.text_recognizer(img_crop_list)
79+
return dt_boxes, rec_res
80+
81+
def get_text(self, img, max_side_len, score_thresh=0.6):
82+
result = []
83+
dt_boxes, rec_res = self.get_ocr(img, max_side_len)
84+
for roi_ocr in list(zip(dt_boxes, rec_res)):
85+
roi_score = roi_ocr[1][1]
86+
if roi_score > score_thresh:
87+
result.append({
88+
'pos': get_center_pos(roi_ocr[0]),
89+
'text': roi_ocr[1][0],
90+
'score': round(float(roi_score), 2)
91+
})
92+
return result
93+
94+
95+
image_text = ImageText()

dbnet_crnn/modelv1.1/det/model

337 KB
Binary file not shown.

dbnet_crnn/modelv1.1/det/params

2.19 MB
Binary file not shown.

dbnet_crnn/modelv1.1/rec/model

440 KB
Binary file not shown.

0 commit comments

Comments
 (0)