# -*-coding:utf-8 -*-
import cv2
import math
import numpy as np
from PIL import Image
from io import BytesIO
class Angle():
def HSVDistance(self,c1, c2):
y1 = 0.299 * c1[:, :, 0] + 0.587 * c1[:, :, 1] + 0.114 * c1[:, :, 2]
u1 = -0.14713 * c1[:, :, 0] - 0.28886 * c1[:, :, 1] + 0.436 * c1[:, :, 2]
v1 = 0.615 * c1[:, :, 0] - 0.51498 * c1[:, :, 1] - 0.10001 * c1[:, :, 2]
y2 = 0.299 * c2[:, 0] + 0.587 * c2[:, 1] + 0.114 * c2[:, 2]
u2 = -0.14713 * c2[:, 0] - 0.28886 * c2[:, 1] + 0.436 * c2[:, 2]
v2 = 0.615 * c2[:, 0] - 0.51498 * c2[:, 1] - 0.10001 * c2[:, 2]
rlt = np.sqrt((y1 - y2) * (y1 - y2) + (u1 - u2) * (u1 - u2) + (v1 - v2) * (v1 - v2))
return rlt
def pjtp(self,bj, qm):
zxdx = bj.shape[0] // 2
zxdy = bj.shape[1] // 2
zxdx2 = qm.shape[0] // 2
zxdy2 = qm.shape[1] // 2
k = 95
k2 = 105
points2 = np.zeros((360, 360, 3))
theta = np.radians(np.arange(360))
thetaHdx = np.cos(theta)
thetaHdy = np.sin(theta)
x = zxdx + k2 * thetaHdx
y = zxdy + k2 * thetaHdy
points = bj[x.astype(int), y.astype(int)]
x = zxdx2 + k * thetaHdx
y = zxdy2 + k * thetaHdy
points2[0, :] = qm[x.astype(int), y.astype(int)]
for i in range(1, 360):
points2[i, i:] = points2[0, :360 - i]
points2[i, :i] = points2[0, 360 - i:]
jj = np.sum(self.HSVDistance(points2, points), axis=1)
k = np.argmin(jj)
return k
def display_grayscale_image(self,image, outer_image):
cv2.imshow('Grayscale Image', image)
cv2.imshow('Grayscale Image2', outer_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
def ocr(self,bg_bytes,angle_bytes):
inner_image = cv2.imdecode(np.frombuffer(bg_bytes, np.uint8), cv2.IMREAD_COLOR)
outer_image = cv2.imdecode(np.frombuffer(angle_bytes, np.uint8), cv2.IMREAD_COLOR)
inner_image = cv2.cvtColor(inner_image, cv2.COLOR_BGR2HSV)
outer_image = cv2.cvtColor(outer_image, cv2.COLOR_BGR2HSV)
# self.display_grayscale_image(inner_image, outer_image)
return self.pjtp(inner_image, outer_image)
class OCR():
def circle_point_px(self,img, accuracy_angle, r=None):
rows, cols, _ = img.shape
assert 360 % accuracy_angle == 0
x0, y0 = r0, _ = (rows // 2, cols // 2)
if r: r0 = r
angles = np.arange(0, 360, accuracy_angle)
cos_angles = np.cos(np.deg2rad(angles))
sin_angles = np.sin(np.deg2rad(angles))
x = x0 + r0 * cos_angles
y = y0 + r0 * sin_angles
x = np.round(x).astype(int)
y = np.round(y).astype(int)
circle_px_list = img[x, y]
return circle_px_list
def rotate(self,image, angle, center=None, scale=1.0): # 1
(h, w) = image.shape[:2] # 2
if center is None: # 3
center = (w // 2, h // 2) # 4
M = cv2.getRotationMatrix2D(center, angle, scale) # 5
rotated = cv2.warpAffine(image, M, (w, h)) # 6
return rotated
def HSVDistance(self,c1, c2):
y1 = 0.299 * c1[0] + 0.587 * c1[1] + 0.114 * c1[2]
u1 = -0.14713 * c1[0] - 0.28886 * c1[1] + 0.436 * c1[2]
v1 = 0.615 * c1[0] - 0.51498 * c1[1] - 0.10001 * c1[2]
y2 = 0.299 * c2[0] + 0.587 * c2[1] + 0.114 * c2[2]
u2 = -0.14713 * c2[0] - 0.28886 * c2[1] + 0.436 * c2[2]
v2 = 0.615 * c2[0] - 0.51498 * c2[1] - 0.10001 * c2[2]
rlt = math.sqrt((y1 - y2) * (y1 - y2) + (u1 - u2) * (u1 - u2) + (v1 - v2) * (v1 - v2))
return rlt
def discern(self,inner_image_brg, outer_image_brg, result_img=None, ):
inner_image_brg = cv2.imread(inner_image_brg)
outer_image_brg = cv2.imread(outer_image_brg)
inner_image = cv2.cvtColor(inner_image_brg, cv2.COLOR_BGR2HSV)
outer_image = cv2.cvtColor(outer_image_brg, cv2.COLOR_BGR2HSV)
# cv2.imshow('inner_source', inner_image)
# cv2.imshow('outer_source', outer_image)
all_deviation = []
for result in range(0, 180):
inner = self.rotate(inner_image, -result) # 顺时针
outer = self.rotate(outer_image, result)
inner_circle_point_px = self.circle_point_px(inner, 1, (inner.shape[0] // 2) - 5)
outer_circle_point_px = self.circle_point_px(outer, 1, (inner.shape[0] // 2) + 5)
total_deviation = 0
for i in range(len(inner_circle_point_px)):
in_px = inner_circle_point_px[i]
out_px = outer_circle_point_px[i]
deviation = self.HSVDistance(in_px, out_px)
total_deviation += deviation
all_deviation.append(total_deviation)
result = all_deviation.index(min(all_deviation))
if result_img:
inner = self.rotate(inner_image_brg, -result) # 顺时针
outer = self.rotate(outer_image_brg, result)
left_point = outer.shape[0] / 2 - inner.shape[0] / 2
right_point = outer.shape[0] / 2 + inner.shape[0] / 2
replace_area = outer[int(left_point):int(right_point), int(left_point):int(right_point)]
outer[int(left_point):int(right_point), int(left_point):int(right_point)] = replace_area + inner
cv2.imwrite(result_img, outer)
return result
def crop_to_square(self,image):
height, width = image.shape[:2]
size = min(height, width)
start_y = (height - size) // 2
start_x = (width - size) // 2
cropped = image[start_y:start_y + size, start_x:start_x + size]
return cropped
def single_discern(self,inner_image_brg_bytes, outer_image_brg_bytes, result_img=None, pic_circle_radius=98):
# 实际图片圆半径 pic_circle_radius
inner_image_brg = cv2.imdecode(np.frombuffer(inner_image_brg_bytes, np.uint8), cv2.IMREAD_COLOR)
outer_image_brg = cv2.imdecode(np.frombuffer(outer_image_brg_bytes, np.uint8), cv2.IMREAD_COLOR)
inner_image = cv2.cvtColor(inner_image_brg, cv2.COLOR_BGR2HSV)
outer_image = cv2.cvtColor(outer_image_brg, cv2.COLOR_BGR2HSV)
outer_image = self.crop_to_square(outer_image)
all_deviation = []
for result in range(0, 360):
inner = self.rotate(inner_image, -result) # 顺时针
outer = self.rotate(outer_image, 0)
inner_circle_point_px = self.circle_point_px(inner, 1, pic_circle_radius - 5)
outer_circle_point_px = self.circle_point_px(outer, 1, pic_circle_radius + 5)
total_deviation = np.sum([self.HSVDistance(in_px, out_px) for in_px, out_px in zip(inner_circle_point_px, outer_circle_point_px)])
all_deviation.append(total_deviation)
result = all_deviation.index(min(all_deviation))
if result_img:
inner = self.rotate(inner_image_brg, -result) # 顺时针
outer = self.rotate(outer_image_brg, 0)
outer = self.crop_to_square(outer)
size = inner.shape[0]
left_point = int((outer.shape[0] - size) / 2)
right_point = left_point + size
replace_area = outer[left_point:right_point, left_point:right_point].copy()
outer[left_point:right_point, left_point:right_point] = replace_area + inner
cv2.imwrite(result_img, outer)
return result
def slide_rotate(slide,bg,path=None):
def circle_point_px(img, accuracy_angle, r=None):
rows, cols, _ = img.shape
assert 360 % accuracy_angle == 0
x0, y0 = r0, _ = (rows // 2, cols // 2)
if r: r0 = r
# 起始角度阈值,精度差值
angles = np.arange(20, 360, accuracy_angle)
cos_angles = np.cos(np.deg2rad(angles))
sin_angles = np.sin(np.deg2rad(angles))
x = x0 + r0 * cos_angles
y = y0 + r0 * sin_angles
x = np.round(x).astype(int)
y = np.round(y).astype(int)
circle_px_list = img[x, y]
return circle_px_list
def rotate(image, angle, center=None, scale=1.0): # 1
(h, w) = image.shape[:2] # 2
if center is None: # 3
center = (w // 2, h // 2) # 4
M = cv2.getRotationMatrix2D(center, angle, scale) # 5
rotated = cv2.warpAffine(image, M, (w, h)) # 6
return rotated
def HSVDistance(c1, c2):
y1 = 0.299 * c1[0] + 0.587 * c1[1] + 0.114 * c1[2]
u1 = -0.14713 * c1[0] - 0.28886 * c1[1] + 0.436 * c1[2]
v1 = 0.615 * c1[0] - 0.51498 * c1[1] - 0.10001 * c1[2]
y2 = 0.299 * c2[0] + 0.587 * c2[1] + 0.114 * c2[2]
u2 = -0.14713 * c2[0] - 0.28886 * c2[1] + 0.436 * c2[2]
v2 = 0.615 * c2[0] - 0.51498 * c2[1] - 0.10001 * c2[2]
rlt = math.sqrt((y1 - y2) * (y1 - y2) + (u1 - u2) * (u1 - u2) + (v1 - v2) * (v1 - v2))
return rlt
def crop_to_square(image):
height, width = image.shape[:2]
size = min(height, width)
start_y = (height - size) // 2
start_x = (width - size) // 2
cropped = image[start_y:start_y + size, start_x:start_x + size]
return cropped
def single_discern(inner_image_brg_path, outer_image_brg_path, result_img=None, pic_circle_radius=110,out_size=18,accuracy_angle=5):
'''
:param inner_image_brg_path: 内圆图片路径
:param outer_image_brg_path: 外圆图片路径
:param result_img: 保存结果图片路径
:param pic_circle_radius: 图片中圆的半径
:param out_size: 外圆半径切割大小
:param accuracy_angle: 精度
'''
inner_image_brg = np.asarray(Image.open(BytesIO(inner_image_brg_path)).convert("RGB"))
outer_image_brg = np.asarray(Image.open(BytesIO(outer_image_brg_path)))
inner_image = cv2.cvtColor(inner_image_brg, cv2.COLOR_BGR2HSV)
outer_image = cv2.cvtColor(outer_image_brg, cv2.COLOR_BGR2HSV)
outer_image = crop_to_square(outer_image)
outer = rotate(outer_image, 0)
all_deviation = []
for result in range(0, 360, 2):
if result < 20:# 角度阈值
all_deviation.append(999999)
else:
inner = rotate(inner_image, -result) # 顺时针
inner_circle_point_px = circle_point_px(inner, accuracy_angle, pic_circle_radius - out_size)
outer_circle_point_px = circle_point_px(outer, accuracy_angle, pic_circle_radius + out_size)
total_deviation = np.sum([HSVDistance(in_px, out_px) for in_px, out_px in zip(inner_circle_point_px, outer_circle_point_px)])
all_deviation.append(total_deviation)
result = all_deviation.index(min(all_deviation))
if result_img:
inner = rotate(inner_image_brg, -result) # 顺时针
outer = rotate(outer_image_brg, 0)
outer = crop_to_square(outer)
size = inner.shape[0]
left_point = int((outer.shape[0] - size) / 2)
right_point = left_point + size
replace_area = outer[left_point:right_point, left_point:right_point].copy()
outer[left_point:right_point, left_point:right_point] = replace_area + inner
cv2.imwrite(result_img, outer)
return result
return single_discern(slide, bg, path)
if __name__ == '__main__':
slide = open('slide.jpg','rb').read()
bg = open('bg.jpg','rb').read()
# angel = slide_rotate(slide, bg, 'result.png')
# print(angel)
import time
start_time = time.time()
angle = OCR().single_discern(slide, bg, 'result.jpg')
print(angle)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"Elapsed time: {elapsed_time * 1000:.2f} milliseconds")
这个是一个识别旋转验证码 速度太慢,请帮我优化下
最新发布