任意四点按起始点从左上角开始,顺时针输出,代码如下:
#coding:utf-8
import cv2
import numpy as np
if __name__=='__main__':
img = np.zeros((1000, 1000, 3), np.uint8)
# cnt=np.array([[474,143],[448,135],[369,359],[343,350]]) #倾斜的矩形
# cnt=np.array([[500,300],[100,100],[500,100],[100,300]]) #水平矩形
cnt =np.array([[300,304],[187,240],[149,299],[257,362]]) #倾斜矩形
x, y, w, h = cv2.boundingRect(cnt)
img = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 1)
leftTop=np.array([x,y])
rect = cv2.minAreaRect(cnt)
# print(rect)
box = cv2.boxPoints(rect)
box = np.int0(box)
tempList=[]
for i,item in enumerate(box):
dif =item - leftTop
dist = np.sqrt(np.sum(dif * dif))
item=np.append(item,round(dist,2))
item=np.append(item,i)
tempList.append(list(item))
NewResult = sorted(tempList, key=lambda x: x[2]) # 根据第四项距离值默认从小到大排序
lt,rt,rb,lb=[],[],[],[]
print(NewResult[0][3])
if int(NewResult[0][3])==0:
lt=[box[0][0],box[0][1]]
rt=[box[1][0],box[1][1]]
rb=[box[2][0],box[2][1]]
lb=[box[3][0],box[3][1]]
elif int(NewResult[0][3])==1:
lt = [box[1][0], box[1][1]]
rt = [box[2][0], box[2][1]]
rb = [box[3][0], box[3][1]]
lb = [box[0][0], box[0][1]]
elif int(NewResult[0][3])==2:
lt = [box[2][0], box[2][1]]
rt = [box[3][0], box[3][1]]
rb = [box[0][0], box[0][1]]
lb = [box[1][0], box[1][1]]
else:
lt = [box[3][0], box[3][1]]
rt = [box[0][0], box[0][1]]
rb = [box[1][0], box[1][1]]
lb = [box[2][0], box[2][1]]
print(lt,rt,rb,lb)
cv2.drawContours(img, [box], 0, (0, 0, 255), 1) # 测试
cv2.imshow("src",img)
cv2.waitKey(0)
def sort_points_clockwise(PointList):
"""提供一组凸四边形顶点,按照从左上角顶点开始顺时针方向排序
:param points: Numpy矩阵,shape为(4, 2),描述一组凸四边形顶点
:return sorted_points: 经过排序的点
"""
# 直接分别取四个点坐标中x和y的最小值作为最大外接矩形左上顶点
points=np.array(PointList) # 倾斜矩形
outter_rect_l_t = np.append(np.min(points[::, 0]), np.min(points[::, 1]))
# 求距离最大外接矩形左上点最近的点,作为给定四边形的左上顶点
# 这一步应当是np.argmin(np.sqrt(np.sum(np.square(points - (x, y)), axis=1)))
# 但是开不开算数平方根结果都一样,不是特别有必要,还浪费算力,就省了
l_t_point_index = np.argmin(
np.sum(np.square(points - outter_rect_l_t), axis=1))
# 分别拿出来左上角点和剩余三点
l_t_point = points[l_t_point_index]
other_three_points = np.append(points[0:l_t_point_index:],
points[l_t_point_index + 1::],
axis=0)
# 以x轴(此处以(1, 0)矢量视为x轴)为基准,根据剩余三点与x轴夹角角度排序
BASE_VECTOR = np.asarray((1, 0))
BASE_VECTOR_NORM = 1.0 # np.linalg.norm((1, 0))结果为1
other_three_points = sorted(other_three_points,
key=lambda item: np.arccos(
np.dot(BASE_VECTOR, item) /
(BASE_VECTOR_NORM * np.linalg.norm(item))),
reverse=False)
sorted_points = np.append(l_t_point.reshape(-1, 2),
np.asarray(other_three_points),
axis=0)
# lt, rt, rb, lb = [sorted_points[0][0],sorted_points[0][1]], [sorted_points[1][0],sorted_points[1][1]],[sorted_points[2][0],sorted_points[2][1]], [sorted_points[3][0],sorted_points[3][1]]
return sorted_points
更新一下思路,确定左上角的点之后,如果四个点是标准矩形,上述代码可以通用,如果是凸四边形,思路可以稍微调整一下,确认左上角,后续1、根据确认左上角方法,依次确认其他的角,2、其他三个点求跟坐标原点(图像默认左上角为原点),同横方向的夹角,顺时针,角度依次从小大,同理,同纵方向夹角,角度依次从大大小排序,即可得到依左上角为起始点,顺时针旋转。
代码冗余,有好的建议,可以自行修改,留言交流