工具类
import math
import cv2 as cv
import numpy as np
from shapely.geometry import Point, Polygon
def log(*args):
print(args)
# 显示图像
def show(title, image):
cv.namedWindow(title, cv.WINDOW_NORMAL)
cv.imshow(zh_ch(title), image)
pass
# 解决中文乱码问题
def zh_ch(string):
return string.encode("gbk").decode(errors="ignore")
# 图像缩放
def resize(img, fx):
return cv.resize(img, None, fx=fx, fy=fx)
# 图像平移
def move(src, x, y):
# 构建平移矩阵
M = np.float32([[1, 0, x], [0, 1, y]])
# 应用平移矩阵
move = cv.warpAffine(src, M, (src.shape[1], src.shape[0]))
return move
pass
# 旋转图像全部
# opencv的旋转会保持图片大小不变,旋转后空白地方补黑,多的地方丢失.所以这里写一个无损旋转函数
def rotationAll(src, angle):
# 拿到原图的宽高中心点
h, w = src.shape[:2]
cX = w / 2
cY = h / 2
# 拿到旋转矩阵,默认是逆时针,我们习惯顺时针,所以这里角度取反
M = cv.getRotationMatrix2D((cX, cY), -angle, 1.0)
# 默认旋转后图像保持原图大小,那么转出去的部分就会丢失,我们这里保留图像所有内容,那么图像就会变大
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# 计算新图像的大小
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
M[0, 2] += (nW / 2) - cX
M[1, 2] += (nH / 2) - cY
rotated_image = cv.warpAffine(src, M, (nW, nH))
return rotated_image
pass
# 旋转图像像素点
# 结合rotationAll()函数使用,将旋转前的像素映射到旋转后的图像中
def rotationAllPoint(src, points, angle):
# 拿到原图的宽高中心点
h, w = src.shape[:2]
cX = w / 2
cY = h / 2
# 拿到旋转矩阵,默认是逆时针,我们习惯顺时针,所以这里角度取反
M = cv.getRotationMatrix2D((cX, cY), -angle, 1.0)
# 默认旋转后图像保持原图大小,那么转出去的部分就会丢失,我们这里保留图像所有内容,那么图像就会变大
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# 计算新图像的大小
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
M[0, 2] += (nW / 2) - cX
M[1, 2] += (nH / 2) - cY
# 要映射的点
pts = np.float32(points).reshape([-1, 2])
pts = np.hstack([pts, np.ones([len(pts), 1])]).T
target_point = np.dot(M, pts)
target_point = [[target_point[0][x], target_point[1][x]] for x in range(len(target_point[0]))]
return target_point
pass
# 旋转图像中的点还原到原图坐标
# 结合rotationAll()函数使用,将旋转后图像中的点映射到旋转前图像中
def restorePoint(point, rotate, src, angle):
centerSrc = (src.shape[1] / 2, src.shape[0] / 2)
centerRotate = (rotate.shape[1] / 2, rotate.shape[0] / 2)
# 旋转后图像和原图大小不一样,先计算差值
difference = (point[0] - (centerRotate[0] - centerSrc[0]), point[1] - (centerRotate[1] - centerSrc[1]))
result = rotatePoint(centerSrc, difference, -angle)
return result
pass
# 一个点绕中心点旋转一定角度后的坐标
def rotatePoint(center, rotater, angle):
# 角度转弧度
radian = angle * math.pi / 180
# 三角函数计算坐标
x = (rotater[0] - center[0]) * math.cos(radian) - (rotater[1] - center[1]) * math.sin(radian) + center[0]
y = (rotater[0] - center[0]) * math.sin(radian) + (rotater[1] - center[1]) * math.cos(radian) + center[1]
return (x, y)
pass
# 绘制点
def drawPoint(canvas, p):
try:
cv.circle(canvas, (round(p[0]), round(p[1])), 1, (0, 0, 255), 3)
except Exception:
log(p)
log("绘制点异常")
pass
# 绘制线
def drawLine(canvas, p1, p2):
cv.line(canvas, (round(p1[0]), round(p1[1])), (round(p2[0]), round(p2[1])), (0, 0, 255), 2)
pass
# 绘制矩形
def drawRectangle(canvas, p1, p2):
cv.rectangle(canvas, (round(p1[0]), round(p1[1])), (round(p2[0]), round(p2[1])), (0, 0, 255), 2)
pass
# 绘制矩形
def drawRectangle2(canvas, p1, w, h):
cv.rectangle(canvas, (round(p1[0]), round(p1[1])), (round(p1[0] + w), round(p1[1] + h)), (0, 0, 255), 2)
pass
# 绘制多边形,多个点连起来
def drawPolylines(canvas, points):
# 坐标数据取整
points_temp = []
for point in points:
points_temp.append([round(point[0]), round(point[1])])
pass
# 坐标数组转点集np.arry[]
pts = np.array(points_temp)
cv.polylines(canvas, [pts], True, (0, 0, 255), 2)
pass
# 绘制文本
def drawText(canvas, text, p):
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(canvas, text, (round(p[0]), round(p[1])), font, 2, (0, 0, 255), 2, cv.LINE_AA)
pass
# 获取两点间距离
def getDistance(p1, p2):
distance = math.pow((p1[0] - p2[0]), 2) + math.pow((p1[1] - p2[1]), 2)
distance = math.sqrt(distance)
return distance
# 已知三个角和一条边,求另2条边
def calSide(angles, a):
angleA = angles[0]
angleB = angles[1]
angleC = angles[2]
b = math.sin(angleB / 180 * math.pi) * a
c = math.cos(angleB / 180 * math.pi) * a
return b, c
# 计算线段中点1到点2的方向
def calAngleLine(p1, p2):
angle = 0
x1, y1 = p1
x2, y2 = p2
# 水平
if y1 == y2:
# 右
if x1 < x2:
angle = 0
# 左
elif x1 > x2:
angle = 180
# 同一个点
else:
angle = 0
# 向上
elif y1 > y2:
# 右上
if x1 < x2:
angle = 360 - calAngle(p1, p2, (x2, y1))[0]
# 左上
elif x1 > x2:
angle = 180 + calAngle(p1, p2, (x2, y1))[0]
# 上
else:
angle = 270
# 向下
else:
# 右下
if x1 < x2:
angle = calAngle(p1, p2, (x2, y1))[0]
# 左下
elif x1 > x2:
angle = 180 - calAngle(p1, p2, (x2, y1))[0]
# 下
else:
angle = 90
return angle
# 计算三个点绘制三角形的角度,返回值是个数组,里面的角度对应传递3个点的顺序
def calAngle(p1, p2, p3):
angles = []
a = math.sqrt((p2[0] - p3[0]) * (p2[0] - p3[0]) + (p2[1] - p3[1]) * (p2[1] - p3[1]))
b = math.sqrt((p1[0] - p3[0]) * (p1[0] - p3[0]) + (p1[1] - p3[1]) * (p1[1] - p3[1]))
c = math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]))
A = math.degrees(math.acos((a * a - b * b - c * c) / (-2 * b * c)))
B = math.degrees(math.acos((b * b - a * a - c * c) / (-2 * a * c)))
C = math.degrees(math.acos((c * c - a * a - b * b) / (-2 * a * b)))
angles.append(A)
angles.append(B)
angles.append(C)
return angles
# 计算2个角度之间的差
def angleDifference(angle1, angle2):
return 180 - abs(abs(angle1 - angle2) - 180)
pass
# 角度校正,360=0,361=1
def rectifyAngle(angle):
# u.log(angle)
if angle >= 360:
angle = angle - 360
elif angle < 0:
angle = angle + 360
if (angle < 0) | (angle >= 360):
return rectifyAngle(angle)
return angle
# 计算一个点在一定角度上多远距离的点坐标
def calPoint4AngleDistance(center, angle, distance):
angle = rectifyAngle(angle)
x, y = center
point = ()
if angle >= 360:
angle %= 360
# 右
if angle == 0:
point = (x + distance, y)
pass
# 下
elif angle == 90:
point = (x, y + distance)
pass
# 左
elif angle == 180:
point = (x - distance, y)
pass
# 上
elif angle == 270:
point = (x, y - distance)
pass
# 右下
elif angle > 0 and angle < 90:
angles = []
angles.append(90)
angles.append(angle)
angles.append(90 - angle)
b, c = calSide(angles, distance)
point = (x + c, y + b)
pass
# 左下
elif angle > 90 and angle < 180:
angles = []
angles.append(90)
angles.append(180 - angle)
angles.append(angle - 90)
b, c = calSide(angles, distance)
point = (x - c, y + b)
pass
# 左上
elif angle > 180 and angle < 270:
angles = []
angles.append(90)
angles.append(angle - 180)
angles.append(270 - angle)
b, c = calSide(angles, distance)
point = (x - c, y - b)
pass
# 右上
elif angle > 270 and angle < 360:
angles = []
angles.append(90)
angles.append(360 - angle)
angles.append(angle - 270)
b, c = calSide(angles, distance)
point = (x + c, y - b)
pass
return point
# 获取图像中白色像素点数量
def getWhiteCount(src):
count = 0
w, h = src.shape
for j in range(w):
for k in range(h):
if src[j, k] == (255.0):
count += 1
return count
pass
# 获取白色像素点坐标集
def getWhiteCount(src):
points = []
w, h = src.shape
for j in range(w):
for k in range(h):
if src[j, k] == (255.0):
points.append([j, k])
return points
pass
# 提取图像中所有白色像素点的坐标
def getWhitePoints(src):
whites = []
w, h = src.shape
for j in range(w):
for k in range(h):
if src[j, k] == (255.0):
whites.append([k, j])
return whites
pass
# 角度校正
def rectifyAngle(angle):
# print(angle)
if angle >= 360:
angle = angle - 360
elif angle < 0:
angle = angle + 360
if (angle < 0) | (angle >= 360):
return rectifyAngle(angle)
return angle
# 判断2个矩形有没有重合点
def rectOverlay(rect1, rect2):
lt1, rt1, lb1, rb1 = rect1
lt2, rt2, lb2, rb2 = rect2
x1 = lt1[0]
y1 = lt1[1]
w1 = rt1[0] - x1
h1 = lb1[1] - y1
x2 = lt2[0]
y2 = lt2[1]
w2 = rt2[0] - x2
h2 = lb2[1] - y2
if x1 > x2 + w2 or x2 > x1 + w1:
return False
if y1 > y2 + h2 or y2 > y1 + h1:
return False
return True
pass
# 判断一个点在不在一个多边形内
def pointInPolylines(point, points):
# 定义多边形的顶点
polygon = Polygon(points)
# 定义要判断的点
point = Point(point)
# 判断点是否在多边形内
inside = polygon.contains(point)
return inside
pass