角度计算终章
角度计算终章
2023/6/1更新start
不知道遇到了什么问题,当多个物体出现在同一张图片时,角度输出的有问题,修改如下:
- 首先新建文件夹还是一样
- 还是得在# segment下的得到坐标点,也就是说之前是在
*xyxy
循环下找坐标点并输出的,是错误的。修改代码如下(放在if save_txt下
#################################################################
im0_h, im0_w, im0_c = im0.shape
for k, seg_list in enumerate(segments):
# 将归一化的点转换为坐标点
new_seg_list = []
for s_point in seg_list:
pt1, pt2 = s_point
new_pt1 = int(pt1 * im0_w)
new_pt2 = int(pt2 * im0_h)
new_seg_list.append([new_pt1, new_pt2])
rect = cv2.minAreaRect(np.array(new_seg_list)) # 得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度)
rect_width = rect[1][0]
rect_hight = rect[1][1]
OrientationAngle = '{:.2f}'.format(rect[2])
if rect_width > rect_hight:
pass
else:
OrientationAngle = '{:.2f}'.format(rect[2] + 90)
rect_box = np.int_(cv2.boxPoints(rect)) # 获取四个顶点坐标
boxlist = [] # 用于收集坐标
boxlist.append(rect_box[0][0])
boxlist.append(rect_box[0][1])
annotator.rect_angle(boxlist, OrientationAngle) # 将角度写在左上角
fangle.write(str('{:.2f}'.format(rect[2])) + '\n') # 保存输出的角度
##################################################################
- 上述代码使用了annotator中的rect_angle函数,annotator是在原图上绘画的函数,在plot.py中,于是我在annotator的最后面加上了写出角度的功能,代码如下,不画出外接矩形是有其他考虑的。
def rect_angle(self, box, angle='', color=(0, 225, 0), txt_color=(255, 255, 255)):
p1 = (int(box[0]), int(box[1]))
tf = max(self.lw - 1, 1) # font thickness
cv2.putText(self.im,
angle, (p1[0], p1[1] - 2),
0,
self.lw / 3,
txt_color,
thickness=tf,
lineType=cv2.LINE_AA)
2023/6/1更新end
YOLOv5的中的实例分割器可以输出segments维度,它是一个列表,如果进行预测的画面中有n片刨花,那么列表中将有n个元素,每个元素都是多个坐标点,坐标点是预测出来的每一片刨花的轮廓坐标值。将这些坐标值反归一化,转换为画面中的真实的坐标值。由于实验所使用的刨花几乎均为矩形(刨花纤维生长方向为长),故可用OpenCV中的minAreaRect函数求出刨花的最小外接矩形,再对minAreaRect函数输出的旋转角度参数根据实际需要进行优化,即可得到每一片刨花的定向角度。最后将角度计算的相关代码融入YOLOv5中,并将最小外接矩形和角度实时的输出。
predict.py代码改进如下:
首先在155行左右新建文件夹
s += '%gx%g ' % im.shape[2:] # print string
################################################################
OrientationAngleDir = str(save_dir) + '/OrientationAngle'
if not os.path.exists(OrientationAngleDir):
os.makedirs(OrientationAngleDir)
OrientationAnglePath = OrientationAngleDir + '\\' + str(p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # OrientationAngleDir.txt
fangle = open(OrientationAnglePath + '.txt', 'a') # 保存定向角度
################################################################
imc = im0.copy() if save_crop else im0 # for save_crop
接着利用save_text中的segments的维度进行求角度
if save_txt: # Write to file
seg = segments[j].reshape(-1) # (n,2) to (n*2)
line = (cls, *seg, conf) if save_conf else (cls, *seg) # label format
with open(f'{txt_path}.txt', 'a') as f:
f.write(('%g ' * len(line)).rstrip() % line + '\n')
#################################################################
im0_h, im0_w, im0_c = im0.shape
for k, seg_list in enumerate(segments):
# 将归一化的点转换为坐标点
new_seg_list = []
for s_point in seg_list:
pt1, pt2 = s_point
new_pt1 = int(pt1 * im0_w)
new_pt2 = int(pt2 * im0_h)
new_seg_list.append([new_pt1, new_pt2])
rect = cv2.minAreaRect(np.array(new_seg_list)) # 得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度)
fangle.write(str('{:.2f}'.format(rect[2])) + '\n')
##################################################################
if save_img or save_crop or view_img: # Add bbox to image
c = int(cls) # integer class
label = None if hide_labels else ('{:.2f}'.format(rect[2]) if hide_conf else f'{names[c]} {conf:.2f}')
annotator.box_label(xyxy, label, color=colors(c, True))
# annotator.draw.polygon(segments[j], outline=colors(c, True), width=3)
最终将原本的标签位置替换为计算出的角度即可。