针对目标检测标注数据做的数据预处理操作。
# -*- coding: utf-8 -*-"""@File : rotate_images.py@Time : 2020-8-19 21:21@Author : qian733@Description :"""import osimport cv2import shutilimport argparseimport voc_utilsimport numpy as npclass RotateProcessing(object):def __init__(self, angle, center=0, scale=1.0):""":param angle: 旋转角度:param center: 旋转的中心点,默认为图像中心,以0代替:param scale: 图像缩放因子"""self.angle = angleself.center = centerself.scale = scaledef rotate(self, image):(h, w) = image.shape[:2]if not self.center:(cx, cy) = (w / 2, h / 2)else:(cx, cy) = self.center # 二元元组# 设置旋转矩阵matrix = cv2.getRotationMatrix2D((cx, cy), -self.angle, self.scale)cos = np.abs(matrix[0, 0])sin = np.abs(matrix[0, 1])# 计算图像旋转后的新边界new_weight = int((h * sin) + (w * cos))new_height = int((h * cos) + (w * sin))# 调整旋转矩阵的移动距离(t_{x}, t_{y})matrix[0, 2] += (new_weight / 2) - cxmatrix[1, 2] += (new_height / 2) - cyreturn cv2.warpAffine(image, matrix, (new_weight, new_height))def get_rotate_boxes(self, img_shape, gt_bboxes):""":param img_shape::param gt_bboxes: 由TensorFlow返回的预测结果:return:"""num_boxes = len(gt_bboxes)(h, w) = img_shape[0], img_shape[1]mask = np.zeros(shape=(h, w, num_boxes), dtype=np.uint8)for i, box in enumerate(gt_bboxes):y1, x1, y2, x2 = box# 这里的gt是大于0的float,不需要分别乘以长宽,但是需要取整y1, y2 = int(np.floor(y1)), int(np.ceil(y2))x1, x2 = int(np.floor(x1)), int(np.ceil(x2))mask[y1:y2, x1:x2, i] = 1if not self.center:(cx, cy) = (w / 2, h / 2)else:(cx, cy) = self.center # 二元元组matrix = cv2.getRotationMatrix2D((cx, cy), -self.angle, self.scale)cos = np.abs(matrix[0, 0])sin = np.abs(matrix[0, 1])new_weight = int((h * sin) + (w * cos))new_height = int((h * cos) + (w * sin))matrix[0, 2] += (new_weight / 2) - cxmatrix[1, 2] += (new_height / 2) - cynew_mask = cv2.warpAffine(mask, matrix, (new_weight, new_height))if num_boxes == 1:new_mask = new_mask[:, :, np.newaxis]new_gt_boxes = np.zeros_like(gt_bboxes)for i in range(num_boxes):hs, ws = np.where(new_mask[:, :, i] == 1)y1, x1, y2, x2 = 0, 0, 0, 0if len(hs) > 0:y1, y2 = np.min(hs), np.max(hs)if len(ws) > 0:x1, x2 = np.min(ws), np.max(ws)new_gt_boxes[i] = np.array([y1, x1, y2, x2])return new_gt_boxes, new_height, new_weightdef rotate_images_special(args, out_anno, out_jpg, out_bg):""":param args::param out_anno::param out_jpg::param out_bg::return:"""if args.subfile:subfile_list = args.subfile.split("+")else:subfile_list = os.listdir(args.input_path)angle_list = args.angle.split("+")for sub in os.listdir(args.input_path):if sub in subfile_list:print(sub)sub_dir = os.path.join(args.input_path, sub) # 如 root_dir/small_0511 下面放着图像和xml文件anno_dir = sub_dir + "/Annotations/"img_dir = sub_dir + "/JPEGImages/"bg_list = []for anno in os.listdir(anno_dir):xml_path = os.path.join(anno_dir, anno) # xml_, height, width, class_names, gt_boxes = voc_utils.parse_voc(xml_path)# 如果class为空,则进行去重;如果class只有第一类,则进行旋转if args.exclude_class not in class_names:for angle in angle_list:RP = RotateProcessing(int(angle))image_ori = cv2.imread(img_dir + anno.split(".")[0] + ".jpg")image_rotate = RP.rotate(image_ori)cv2.imwrite(out_jpg + "/r" + angle + anno.split(".")[0] + ".jpg", image_rotate)image_rotate_boxes, nH, nW = RP.get_rotate_boxes(image_ori.shape, gt_boxes)voc_utils.save_to_xml_file("r" + angle + anno.split(".")[0] + ".jpg", nH, nW, class_names, image_rotate_boxes, out_anno)def rotate_images(args, out_anno, out_jpg, out_bg):""":param args::param out_anno::param out_jpg::param out_bg::return:"""if args.subfile:subfile_list = args.subfile.split("+")else:subfile_list = os.listdir(args.input_path)angle_list = args.angle.split("+")for sub in os.listdir(args.input_path):if sub in subfile_list:print(sub)sub_dir = os.path.join(args.input_path, sub) # 如 root_dir/small_0511 下面放着图像和xml文件anno_dir = sub_dir + "/Annotations/"img_dir = sub_dir + "/JPEGImages/"bg_list = []for anno in os.listdir(anno_dir):xml_path = os.path.join(anno_dir, anno) # xml_, height, width, class_names, gt_boxes = voc_utils.parse_voc(xml_path)# 如果class为空,则旋转图像并修改xml中对应的图像宽高if not class_names:for angle in angle_list:RP = RotateProcessing(int(angle))image_ori = cv2.imread(img_dir + anno.split(".")[0] + ".jpg")image_rotate = RP.rotate(image_ori)cv2.imwrite(out_jpg + "/r" + anno.split(".")[0]+ "_" + angle + ".jpg", image_rotate)print("touch " + anno.split(".")[0]+ "_" + angle + ".xml")elif args.exclude_class not in class_names:for angle in angle_list:RP = RotateProcessing(int(angle))image_ori = cv2.imread(img_dir + anno.split(".")[0] + ".jpg")image_rotate = RP.rotate(image_ori)cv2.imwrite(out_jpg + "/r" + anno.split(".")[0]+ "_" + angle + ".jpg", image_rotate)image_rotate_boxes, nH, nW = RP.get_rotate_boxes(image_ori.shape, gt_boxes)voc_utils.save_to_xml_file("r" + anno.split(".")[0]+ "_" + angle + ".jpg", nH, nW, class_names,image_rotate_boxes, out_anno)def main():parse = argparse.ArgumentParser()parse.add_argument("--input_path", type=str,default="/sdb/tmp/Behavior_Normalization_Monitoring/data/Tagged_data_crop/small")parse.add_argument("--out_path", type=str,default="/sdb/tmp/Behavior_Normalization_Monitoring/data/Tagged_data_rotate/small")parse.add_argument("--angle", type=str, default="90+180+270")parse.add_argument("--subfile", type=str, default="")parse.add_argument("--exclude_class", type=str, default="phone")arg = parse.parse_args()out_anno = arg.out_path + "/Annotations/"out_jpg = arg.out_path + "/JPEGImages/"out_bg = arg.out_path + "/bg/"if not os.path.exists(arg.out_path):os.makedirs(out_anno)os.makedirs(out_jpg)os.makedirs(out_bg)rotate_images(arg, out_anno, out_jpg, out_bg)if __name__ == '__main__':main()
