update
Browse files
PP-OCRv6_medium_det/src/example.py
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
sys.dont_write_bytecode = True
|
| 3 |
+
|
| 4 |
+
import cv2
|
| 5 |
+
import numpy
|
| 6 |
+
import pyclipper
|
| 7 |
+
|
| 8 |
+
from helper import onnxSessionBuild
|
| 9 |
+
|
| 10 |
+
pathModel = "./PP-OCRv6_medium_det/"
|
| 11 |
+
|
| 12 |
+
limitSideLength = 960
|
| 13 |
+
limitSideLengthMax = 4000
|
| 14 |
+
binaryThreshold = 0.2
|
| 15 |
+
boxThreshold = 0.45
|
| 16 |
+
unclipRatio = 1.4
|
| 17 |
+
candidateMax = 3000
|
| 18 |
+
sideMinimum = 3
|
| 19 |
+
|
| 20 |
+
meanList = numpy.array([0.485, 0.456, 0.406], dtype=numpy.float32)
|
| 21 |
+
standardList = numpy.array([0.229, 0.224, 0.225], dtype=numpy.float32)
|
| 22 |
+
|
| 23 |
+
onnxSession = onnxSessionBuild(f"{pathModel}onnx/pp-ocrV6_medium_det.onnx")
|
| 24 |
+
|
| 25 |
+
def imageResize(image):
|
| 26 |
+
imageHeight, imageWidth = image.shape[0:2]
|
| 27 |
+
|
| 28 |
+
ratio = 1.0
|
| 29 |
+
|
| 30 |
+
if max(imageHeight, imageWidth) > limitSideLength:
|
| 31 |
+
if imageHeight > imageWidth:
|
| 32 |
+
ratio = float(limitSideLength) / imageHeight
|
| 33 |
+
else:
|
| 34 |
+
ratio = float(limitSideLength) / imageWidth
|
| 35 |
+
|
| 36 |
+
resizeHeight = int(imageHeight * ratio)
|
| 37 |
+
resizeWidth = int(imageWidth * ratio)
|
| 38 |
+
|
| 39 |
+
if max(resizeHeight, resizeWidth) > limitSideLengthMax:
|
| 40 |
+
ratio = float(limitSideLengthMax) / max(resizeHeight, resizeWidth)
|
| 41 |
+
|
| 42 |
+
resizeHeight = int(resizeHeight * ratio)
|
| 43 |
+
resizeWidth = int(resizeWidth * ratio)
|
| 44 |
+
|
| 45 |
+
resizeHeight = max(int(round(resizeHeight / 32) * 32), 32)
|
| 46 |
+
resizeWidth = max(int(round(resizeWidth / 32) * 32), 32)
|
| 47 |
+
|
| 48 |
+
return cv2.resize(image, (resizeWidth, resizeHeight))
|
| 49 |
+
|
| 50 |
+
def boxOrder(contour):
|
| 51 |
+
rectangle = cv2.minAreaRect(contour)
|
| 52 |
+
|
| 53 |
+
pointList = sorted(list(cv2.boxPoints(rectangle)), key=lambda point: point[0])
|
| 54 |
+
|
| 55 |
+
index1 = 0
|
| 56 |
+
index2 = 1
|
| 57 |
+
index3 = 2
|
| 58 |
+
index4 = 3
|
| 59 |
+
|
| 60 |
+
if pointList[1][1] > pointList[0][1]:
|
| 61 |
+
index1 = 0
|
| 62 |
+
index4 = 1
|
| 63 |
+
else:
|
| 64 |
+
index1 = 1
|
| 65 |
+
index4 = 0
|
| 66 |
+
|
| 67 |
+
if pointList[3][1] > pointList[2][1]:
|
| 68 |
+
index2 = 2
|
| 69 |
+
index3 = 3
|
| 70 |
+
else:
|
| 71 |
+
index2 = 3
|
| 72 |
+
index3 = 2
|
| 73 |
+
|
| 74 |
+
return [pointList[index1], pointList[index2], pointList[index3], pointList[index4]], min(rectangle[1])
|
| 75 |
+
|
| 76 |
+
def boxScore(probabilityMap, box):
|
| 77 |
+
mapHeight, mapWidth = probabilityMap.shape[0:2]
|
| 78 |
+
|
| 79 |
+
boxLocal = box.copy()
|
| 80 |
+
|
| 81 |
+
xMinimum = max(0, min(int(numpy.floor(box[:, 0].min())), mapWidth - 1))
|
| 82 |
+
xMaximum = max(0, min(int(numpy.ceil(box[:, 0].max())), mapWidth - 1))
|
| 83 |
+
yMinimum = max(0, min(int(numpy.floor(box[:, 1].min())), mapHeight - 1))
|
| 84 |
+
yMaximum = max(0, min(int(numpy.ceil(box[:, 1].max())), mapHeight - 1))
|
| 85 |
+
|
| 86 |
+
mask = numpy.zeros((yMaximum - yMinimum + 1, xMaximum - xMinimum + 1), dtype=numpy.uint8)
|
| 87 |
+
|
| 88 |
+
boxLocal[:, 0] = boxLocal[:, 0] - xMinimum
|
| 89 |
+
boxLocal[:, 1] = boxLocal[:, 1] - yMinimum
|
| 90 |
+
|
| 91 |
+
cv2.fillPoly(mask, boxLocal.reshape(1, -1, 2).astype(numpy.int32), 1)
|
| 92 |
+
|
| 93 |
+
return cv2.mean(probabilityMap[yMinimum:yMaximum + 1, xMinimum:xMaximum + 1], mask)[0]
|
| 94 |
+
|
| 95 |
+
def boxUnclip(box):
|
| 96 |
+
area = cv2.contourArea(box)
|
| 97 |
+
length = cv2.arcLength(box, True)
|
| 98 |
+
|
| 99 |
+
distance = area * unclipRatio / length
|
| 100 |
+
|
| 101 |
+
offsetObject = pyclipper.PyclipperOffset()
|
| 102 |
+
|
| 103 |
+
offsetObject.AddPath(box, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
|
| 104 |
+
|
| 105 |
+
return numpy.array(offsetObject.Execute(distance))
|
| 106 |
+
|
| 107 |
+
def inference(image):
|
| 108 |
+
resultList = []
|
| 109 |
+
|
| 110 |
+
imageHeight, imageWidth = image.shape[0:2]
|
| 111 |
+
imageResized = imageResize(image)
|
| 112 |
+
|
| 113 |
+
tensor = (imageResized.astype(numpy.float32) / 255.0 - meanList) / standardList
|
| 114 |
+
tensor = numpy.expand_dims(tensor.transpose((2, 0, 1)), axis=0).astype(numpy.float32)
|
| 115 |
+
|
| 116 |
+
tensorOutputList = onnxSession.run(None, {"x": tensor})
|
| 117 |
+
|
| 118 |
+
probabilityMap = tensorOutputList[0][0][0]
|
| 119 |
+
bitmap = (probabilityMap > binaryThreshold).astype(numpy.uint8)
|
| 120 |
+
|
| 121 |
+
scaleWidth = imageWidth / float(bitmap.shape[1])
|
| 122 |
+
scaleHeight = imageHeight / float(bitmap.shape[0])
|
| 123 |
+
|
| 124 |
+
contourList, hierarchy = cv2.findContours(bitmap * 255, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
|
| 125 |
+
|
| 126 |
+
for a in range(min(len(contourList), candidateMax)):
|
| 127 |
+
pointList, sideLength = boxOrder(contourList[a])
|
| 128 |
+
|
| 129 |
+
if sideLength < sideMinimum:
|
| 130 |
+
continue
|
| 131 |
+
|
| 132 |
+
score = boxScore(probabilityMap, numpy.array(pointList).reshape(-1, 2))
|
| 133 |
+
|
| 134 |
+
if score < boxThreshold:
|
| 135 |
+
continue
|
| 136 |
+
|
| 137 |
+
pointList, sideLength = boxOrder(boxUnclip(numpy.array(pointList)).reshape(-1, 1, 2))
|
| 138 |
+
|
| 139 |
+
if sideLength < sideMinimum + 2:
|
| 140 |
+
continue
|
| 141 |
+
|
| 142 |
+
coordinateList = []
|
| 143 |
+
|
| 144 |
+
for b in range(len(pointList)):
|
| 145 |
+
x = max(0, min(int(round(pointList[b][0] * scaleWidth)), imageWidth))
|
| 146 |
+
y = max(0, min(int(round(pointList[b][1] * scaleHeight)), imageHeight))
|
| 147 |
+
|
| 148 |
+
coordinateList.append([x, y])
|
| 149 |
+
|
| 150 |
+
resultList.append({
|
| 151 |
+
"score": score,
|
| 152 |
+
"coordinate": coordinateList
|
| 153 |
+
})
|
| 154 |
+
|
| 155 |
+
return resultList
|
| 156 |
+
|
| 157 |
+
image = cv2.imread(sys.argv[1])
|
| 158 |
+
|
| 159 |
+
itemList = inference(image)
|
| 160 |
+
|
| 161 |
+
for a in range(len(itemList)):
|
| 162 |
+
print(f"{itemList[a]['score']:.6f} | {itemList[a]['coordinate']}")
|