ᕕ( ᐛ )ᕗ Wu555's blog

角度计算终章

角度计算终章

2023/6/1更新start

不知道遇到了什么问题,当多个物体出现在同一张图片时,角度输出的有问题,修改如下:

  1. 首先新建文件夹还是一样
  2. 还是得在# 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') # 保存输出的角度

                    ##################################################################
  1. 上述代码使用了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)

最终将原本的标签位置替换为计算出的角度即可。