首页 >图片操作 > 内容

【深度学习标注数据处理】标注标签处理的工具,和坐标转换集锦

2023年9月18日 22:49

不同的标注工具,产生和保存的标签文件也是不同的。比如:

  1. labelImg保存的是xml文件
  2. labelme保存的是json文件

不同的任务,对标签的需求也不同。比如:

  1. 分类任务,就是one hot形式即可
  2. 目标检测任务,给出矩形框即可,x,y,w,h等等形式
  3. 对于分割任务,则需要给出polygon,由一个个坐标点构成

与此同时,在公开数据集中,不同的数据集的存储形式也不近相同。比如:

  1. voc的数据格式
  2. coco的数据格式

所以,对于标注数据进行处理,格式之间的转换,就成了工程师常常需要操作的事情。这里记录下来,重复的工作快速完成。

一、polygon2bbox

任务描述:

采用labelme标注的图像是多边形Polygon,转为矩形标注BBox xmin,ymin,xmax,ymax读取数据是json文件
import osimport jsonimport numpy as npimport PIL.Imageimport PIL.ImageDrawimport base64from PIL import Imageimport ioimport cv2import matplotlib.pyplot as pltdef polygons_to_mask(img_shape, polygons):    mask = np.zeros(img_shape, dtype=np.uint8)    mask = PIL.Image.fromarray(mask)    xy = list(map(tuple, polygons))    PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)    mask = np.array(mask, dtype=bool)    return maskdef mask2box(mask):  # [x1,y1,w,h]    '''从mask反算出其边框    mask:[h,w]  0、1组成的图片    1对应对象,只需计算1对应的行列号(左上角行列号,右下角行列号,就可以算出其边框)    '''    index = np.argwhere(mask == 1)    rows = index[:, 0]    clos = index[:, 1]    # 解析左上角行列号    left_top_r = np.min(rows)  # y    left_top_c = np.min(clos)  # x    # 解析右下角行列号    right_bottom_r = np.max(rows)    right_bottom_c = np.max(clos)    # return [(left_top_r,left_top_c),(right_bottom_r,right_bottom_c)]    # return [(left_top_c, left_top_r), (right_bottom_c, right_bottom_r)]    return [left_top_c, left_top_r, right_bottom_c, right_bottom_r]  # [x1,y1,x2,y2]def getbbox(points):    # 多边形变矩形框bbox    # img = np.zeros([self.height,self.width],np.uint8)    # cv2.polylines(img, [np.asarray(points)], True, 1, lineType=cv2.LINE_AA)  # 画边界线    # cv2.fillPoly(img, [np.asarray(points)], 1)  # 画多边形 内部像素值为1    polygons = points    mask = polygons_to_mask([1024, 1024], polygons)    return mask2box(mask)  # [x1,y1,w,h]# 构建COCO的annotation字段def annotation(points):    bbox = list(map(float, getbbox(points)))    return bbox# 法一def data_transfer(json_path):    bbox_list = []    with open(json_path, 'r') as fp:        #print(json_path)        data = json.load(fp)  # 加载json文件        for shapes in data['shapes']:            points = shapes['points']            points.append([points[0][0], points[1][1]])            points.append([points[1][0], points[0][1]])            bbox = annotation(points)            bbox_list.append(bbox)    return bbox_listdef contour_label(json_path, image):    with open(json_path, 'r') as fp:        #print(json_path)        data = json.load(fp)  # 加载json文件        for shapes in data['shapes']:            points = shapes['points']            contour = np.array([points])            contour = np.trunc(contour).astype(int)            #print(contour, type(contour))            #print("***")            cv2.drawContours(image, [contour], 0, (0, 0, 255), 2)  # cv2.FILLED填充    return image# 法二:def simple_label(json_path, image):    with open(json_path, 'r') as fp:        #print(json_path)        data = json.load(fp)  # 加载json文件        for shapes in data['shapes']:            points = np.array(shapes['points'])            y, x, y2, x2 = np.min(points[:, 1]), np.min(points[:, 0]), np.max(points[:, 1]), np.max(points[:, 0])            print(y, x, y2, x2)            cv2.rectangle(image, (int(x), int(y)), (int(x2), int(y2)), (0, 0, 255), thickness=2)    return imageif __name__=="__main__":    labelme_json = r"E:\temp\label"    png_json = r"E:\temp\image"    for (path, dirs, files) in os.walk(labelme_json):        for filename in files:            zhong_json_path = os.path.join(path, filename)            img = cv2.imread(os.path.join(png_json, filename.replace(".json", ".jpg")))            img_bbox = img.copy()            img_contour = img.copy()            img_simple_bbox = img.copy()            zhong_contour_image = contour_label(zhong_json_path, img_contour)            zhong_bbox_list = data_transfer(zhong_json_path)            plt.figure(figsize=[15, 5])            plt.subplot(131)            plt.title("contour")            plt.imshow(zhong_contour_image)            for box in zhong_bbox_list:                x, y, x2, y2 = box                cv2.rectangle(img_bbox, (int(x), int(y)), (int(x2), int(y2)), (0, 0, 255), thickness=2)            plt.subplot(132)            plt.title("Method 1:mask2box")            plt.imshow(img_bbox)            simple_image = simple_label(zhong_json_path, img_simple_bbox)            plt.subplot(133)            plt.title("Method 2:np.min[:, 1], np.max(points[:, 0])")            plt.imshow(img_bbox)            plt.show()

方法1和方法2都在上面了。这里吧简单点的方法单独抽出来做展示:

def data_transfer(json_path):    bbox_list = []    with open(json_path, 'r') as fp:        #print(json_path)        data = json.load(fp)  # 加载json文件        for shapes in data['shapes']:            points = np.array(shapes['points'])            bbox = [np.min(points[:, 1]), np.min(points[:, 0]), np.max(points[:, 1]), np.max(points[:, 0])]            #print(bbox)            bbox_list.append(bbox)    return bbox_list

二、mask2json

有时候没法直接获取标注的json文件,只有黑白色的mask图像。 这里需要将mask,转为labelme标注的json文件

import osimport cv2import jsondef mask2json():    mask_path = r"Z:\mult_DR\onLine_zhong_labeled\results\mask_pd_qlj"    save_json_path = r"Z:\mult_DR\onLine_zhong_labeled\results\label/"    label = "TB"    for (path, dirs, files) in os.walk(mask_path):        for filename in files:            A = dict()            listbigoption=[]            prefile_path = os.path.join(path, filename)            print(prefile_path)            pred_seged = cv2.imread(prefile_path, 0)            try:                _, contours, _ = cv2.findContours(pred_seged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)            except:                contours, _ = cv2.findContours(pred_seged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)            print(len(contours))            if len(contours) != 0:                for contour in contours:                    if len(contour)>=3:                        listobject = dict()                        listxy = []                        for e in contour:                            listxy.append(e[0].tolist())                            #print(e,e[0][0],e[0][1])                            #x, y = e[0][0], e[0][1]                        print(listxy)                        listobject['points'] = listxy                        listobject['line_color'] = 'null'                        listobject['label'] = label                        listobject['fill_color'] = 'null'                        listbigoption.append(listobject)                A['lineColor'] = [0, 255, 0, 128]                A['imageData'] = 'imageData'                A['fillColor'] = [255, 0, 0, 128]                A['imagePath'] = filename                A['shapes'] = listbigoption                A['flags'] = {}                with open(save_json_path + filename.replace(".png", ".json"), 'w') as f:                    json.dump(A, f)if __name__=="__main__":    mask2json()

三、保存四边形矩形框bbox标注信息

任意四边形坐标标记格式:tl_x,tl_y,tr_x,tr_y,br_x,br_y,bl_x,bl_y。从左上点开始顺时针旋转的四个顶点的坐标,如下图所示:

将TXT文档中标注信息,存储到labelme标注的json文件内,代码如下:

import jsonimport base64from PIL import Imageimport ioimport osimport cv2import numpy as npdef generate_json(file_dir, file_name):    str_json = {}    shapes = []    # 读取坐标    fr = open(os.path.join(file_dir, file_name))    for line in fr.readlines():  # 逐行读取,滤除空格等        print(line.strip())        print(type(line.strip()))        lineArr = line.strip().split(',')        print("lineArr:", lineArr)        points = []        points.append([float(lineArr[0]), float(lineArr[1])])        points.append([float(lineArr[2]), float(lineArr[3])])        points.append([float(lineArr[4]), float(lineArr[5])])        points.append([float(lineArr[6]), float(lineArr[7])])        print(points)  # 从左上点开始顺时针旋转的四个顶点的坐标        shape = {}        shape["label"] = "plate_1"        shape["points"] = points        shape["line_color"] = []        shape["fill_color"] = []        shape["flags"] = {}        shapes.append(shape)    str_json["version"] = "3.14.1"    str_json["flags"] = {}    str_json["shapes"] = shapes    str_json["lineColor"] = [0, 255, 0, 128]    str_json["fillColor"] = [255, 0, 0, 128]    picture_basename = file_name.replace('.txt', '.png')    str_json["imagePath"] = picture_basename    img = cv2.imread(os.path.join(file_dir, picture_basename))    str_json["imageHeight"] = img.shape[0]    str_json["imageWidth"] = img.shape[1]    str_json["imageData"] = base64encode_img(os.path.join(file_dir, picture_basename))    return str_jsondef base64encode_img(image_path):    src_image = Image.open(image_path)    output_buffer = io.BytesIO()    src_image.save(output_buffer, format='JPEG')    byte_data = output_buffer.getvalue()    base64_str = base64.b64encode(byte_data).decode('utf-8')    return base64_strif __name__=="__main__":    """    txt文件和图像(png)文件,均存储在下面这个文件夹下    生成的json文件,也保存到这个文件夹下    """    file_dir = r"E:\temp"    file_name_list = [file_name for file_name in os.listdir(file_dir) \                      if file_name.lower().endswith('txt')]    for file_name in file_name_list:        str_json = generate_json(file_dir, file_name)        json_data = json.dumps(str_json, indent=2, ensure_ascii=False)        jsonfile_name = file_name.replace(".txt", ".json")        f = open(os.path.join(file_dir, jsonfile_name), 'w')        f.write(json_data)        f.close()

检验下生成的json,是否成功。用labelme打开,查看标注结果,进行检验:

四、保存不规则边框polygon标注信息

这里与bbox的区别就在于:

  1. bbox只有四个坐标点,按顺时针一次排布;
  2. polygon是大于2个点都可以的,坐标的排序也是按照顺时针进行排布的。

所以,在poly中坐标点的数量是不固定的。在读取时候,依次将坐标点存储进来就行

import jsonimport base64from PIL import Imageimport ioimport osimport cv2import numpy as npdef generate_json(file_dir, file_name):    str_json = {}    shapes = []    # 读取坐标    fr = open(os.path.join(file_dir, file_name))    for line in fr.readlines():  # 逐行读取,滤除空格等        print(line.strip())        print(type(line.strip()))        lineArr = line.strip().split(',')        print("lineArr:", lineArr)        points = []        for i in range(0, len(lineArr), 2):            points.append([float(lineArr[i]), float(lineArr[i+1])])        print(points)  # 从左上点开始顺时针旋转的四个顶点的坐标        shape = {}        shape["label"] = "plate_1"        shape["points"] = points        shape["line_color"] = []        shape["fill_color"] = []        shape["flags"] = {}        shapes.append(shape)    str_json["version"] = "3.14.1"    str_json["flags"] = {}    str_json["shapes"] = shapes    str_json["lineColor"] = [0, 255, 0, 128]    str_json["fillColor"] = [255, 0, 0, 128]    picture_basename = file_name.replace('.txt', '.png')    str_json["imagePath"] = picture_basename    img = cv2.imread(os.path.join(file_dir, picture_basename))    str_json["imageHeight"] = img.shape[0]    str_json["imageWidth"] = img.shape[1]    str_json["imageData"] = base64encode_img(os.path.join(file_dir, picture_basename))    return str_jsondef base64encode_img(image_path):    src_image = Image.open(image_path)    output_buffer = io.BytesIO()    src_image.save(output_buffer, format='JPEG')    byte_data = output_buffer.getvalue()    base64_str = base64.b64encode(byte_data).decode('utf-8')    return base64_strif __name__=="__main__":    """    txt文件和图像(png)文件,均存储在下面这个文件夹下    生成的json文件,也保存到这个文件夹下    """    file_dir = r"E:\temp\polygon"    file_name_list = [file_name for file_name in os.listdir(file_dir) \                      if file_name.lower().endswith('txt')]    for file_name in file_name_list:        str_json = generate_json(file_dir, file_name)        json_data = json.dumps(str_json, indent=2, ensure_ascii=False)        jsonfile_name = file_name.replace(".txt", ".json")        with open(os.path.join(file_dir, jsonfile_name), 'w') as f:            f.write(json_data)

同样,labelme打开,查看标注结果:

参考链接:任意四边形坐标标记格式txt文件转labelme标记的json格式文件_skye_95的博客-CSDN博客

五、将labelImg标注的xml BBox文件转成json文件

labelImg只能标注矩形框标签,比较的单一。但是labelme就比较的丰富,能够标注不规则图形。将labelImg标注的BBox标签文件xml,转为labelme格式的json文件

from xml.etree import ElementTree as etimport jsonimport globimport osdef readxml_et(xml_file, save_json_path):    tree = et.ElementTree(file=xml_path)    root = tree.getroot()    A = dict()    listbigoption = []    for child_root in root:        if child_root.tag == 'filename':            imagePath = child_root.text        if child_root.tag == 'object':            listobject = dict()            for xylabel in child_root:                if xylabel.tag == 'name':                    label = xylabel.text                if xylabel.tag == 'bndbox':                    xmin = int(xylabel.find('xmin').text)                    ymin = int(xylabel.find('ymin').text)                    xmax = int(xylabel.find('xmax').text)                    ymax = int(xylabel.find('ymax').text)                    listxy=[[xmin,ymin],[xmax,ymin],[xmax,ymax],[xmin,ymax]]                    listobject['points'] = listxy                    listobject['line_color'] = 'null'                    listobject['label'] = label                    listobject['fill_color'] = 'null'                    listbigoption.append(listobject)                # print(listbigoption)    A['lineColor'] = [0, 255, 0, 128]    A['imageData'] = 'imageData'    A['fillColor'] = [255, 0, 0, 128]    A['imagePath'] = imagePath    A['shapes'] = listbigoption    A['flags'] = {}    with open(save_json_path + imagePath.replace(".png", ".json"), 'w') as f:        json.dump(A, f)if __name__=='__main__':    labelme_xml_path = r'F:\xml_labels'    save_json_path = r"F:\labels/"    for root, dirs, files in os.walk(labelme_xml_path):        for filename in files:  # 遍历所有文件            xml_path = os.path.join(root, filename)            print(xml_path)            readxml_et(xml_path, save_json_path)

六、voc中txt格式的,也转为json格式

存储标注好的数据方式多种多样,有直接存储到txt文件的,还有XML文件、json文件、Excel文件等等。各种格式数据间的转换,也是常会用到的。

from xml.etree import ElementTree as etimport jsonimport globimport osdef readxml_et(file_path, save_json_path):    A = dict()    listbigoption = []    with open(file_path, "r") as f:        for line in f.readlines():            listobject = dict()            line = line.strip('\n')  # 去掉列表中每一个元素的换行符            x_center = int(float(line.split(" ")[1]) * 512)            y_center = int(float(line.split(" ")[2]) * 512)            x_shift = int(float(line.split(" ")[3]) * 512)            y_shift = int(float(line.split(" ")[4]) * 512)            xmin = x_center - x_shift            xmax = x_center + x_shift            ymin = y_center - y_shift            ymax = y_center + y_shift            listxy=[[xmin,ymin],[xmax,ymin],[xmax,ymax],[xmin,ymax]]            listobject['points'] = listxy            listobject['line_color'] = 'null'            listobject['label'] = "jie_jie"            listobject['fill_color'] = 'null'            listbigoption.append(listobject)    A['lineColor'] = [0, 255, 0, 128]    A['imageData'] = 'imageData'    A['fillColor'] = [255, 0, 0, 128]    A['imagePath'] = os.path.basename(file_path).replace(".txt", ".png")    A['shapes'] = listbigoption    A['flags'] = {}    with open(save_json_path + os.path.basename(file_path).replace(".txt", ".json"), 'w') as f:        json.dump(A, f)if __name__=='__main__':    labelme_xml_path = r'F:\txt_label'    save_json_path = r"F:\labels/"    for root, dirs, files in os.walk(labelme_xml_path):        for filename in files:  # 遍历所有文件            xml_path = os.path.join(root, filename)            print(xml_path)            readxml_et(xml_path, save_json_path)

七、labelme标注的json文件,打印到原图image上

每次看label me标注好的信息,都需要用这个标注软件再次打开,就显得很麻烦。能不能把标注的信息,打印到原始图像上,这样发给别人对照或者展示的时候,就可以直接查看标注的位置和类别了。

import numpy as npimport cv2import osimport jsondef loadFont(path):    with open(path, 'r', encoding='utf8')as fp:        json_data = json.load(fp)    return json_datadef genarete_mask_label(label_info, filename):    shapes = label_info['shapes']    mask_temp = np.zeros((512, 512))    for i in range(len(shapes)):        points = shapes[i]["points"]        contour = np.array([points])        contour = np.trunc(contour).astype(int)        print(contour, type(contour))        print("***")        cv2.drawContours(mask_temp, [contour], 0, (255, 255, 255), cv2.FILLED)  # 填充    print(r"G:\NCP_ResUNet\V_TEST\data\2_1\mask/" + filename.replace(".json",".png"))    cv2.imwrite(r"G:\NCP_ResUNet\V_TEST\data\2_1\mask/" +  filename.replace(".json",".png"), mask_temp)def draw_mask_image(label_info, filepath):    shapes = label_info['shapes']    raw_PATH = filepath.replace(".json", ".png").replace("labels", "images")    print(raw_PATH)    raw_temp = cv2.imread(raw_PATH)    for i in range(len(shapes)):        points = shapes[i]["points"]        contour = np.array([points])        contour = np.trunc(contour).astype(int)        print(contour, type(contour))        print("***")        cv2.drawContours(raw_temp, [contour], 0, (0, 0, 255), 1)   # 勾勒边界    print(filepath.replace(".json", ".png").replace("labels", "label_png"))    cv2.imwrite(filepath.replace(".json", ".png").replace("labels", "label_png"), raw_temp)if __name__ == '__main__':    # 路径中不要有中文字符    raw_path = r"F:\labels"    for root, dirs, files in os.walk(raw_path):        for filename in files:  # 遍历所有文件            filepath=os.path.join(root,filename)            if filename[len(filename) - 4:len(filename)] == 'json':                label_info = loadFont(filepath)                print(label_info)                draw_mask_image(label_info, filepath)

八、labelme的json数据转换成coco数据读取所需的json文件

普通的由labelme标注生成的文件,一个json对应一个标注图。单coco数据集要求将训练集和验证集的所有标签汇集在一个json文件内

import argparseimport jsonimport matplotlib.pyplot as pltimport skimage.io as ioimport cv2from labelme import utilsimport numpy as npimport globimport PIL.Imageimport osclass MyEncoder(json.JSONEncoder):    def default(self, obj):        if isinstance(obj, np.integer):            return int(obj)        elif isinstance(obj, np.floating):            return float(obj)        elif isinstance(obj, np.ndarray):            return obj.tolist()        else:            return super(MyEncoder, self).default(obj)class labelme2coco(object):    def __init__(self, labelme_json=[], save_json_path='./tran.json'):        '''        :param labelme_json: 所有labelme的json文件路径组成的列表        :param save_json_path: json保存位置        '''        self.labelme_json = labelme_json        self.save_json_path = save_json_path        self.images = []        self.categories = []        self.annotations = []        # self.data_coco = {}        self.label = []        self.annID = 1        self.height = 0        self.width = 0        self.save_json()    # 由json文件构建COCO    def data_transfer(self):        for num, json_file in enumerate(self.labelme_json):            print(json_file)            with open(json_file, 'r') as fp:                data = json.load(fp)  # 加载json文件                self.images.append(self.image(json_file, data, num))                for shapes in data['shapes']:                    label = shapes['label']                    if label not in self.label:                        self.categories.append(self.categorie(label))                        self.label.append(label)                    points = shapes['points']                    points.append([points[0][0],points[1][1]])                    points.append([points[1][0],points[0][1]])                    self.annotations.append(self.annotation(points, label, num))                    self.annID += 1    # 构建COCO的image字段    def image(self, json_file, data, num):        """        {            "height": 1024,            "width": 1024,            "id": 1,            "file_name": "1.2.156.112536.2.560.7050106199066.1346626203150.42_2519_3027_0.140_0.140.png"        },        """        image = {}        #img = utils.img_b64_to_arr(data['imageData'])  # 解析原图片数据        #print(data['imagePath'])        #img=io.imread(os.path.join(r"F:\lingjun2019\detectron2\Dataset_DR\database\images",data['imagePath'])) # 通过图片路径打开图片        img = io.imread(os.path.join(r"F:\DR-TB\iter2\database\images", os.path.basename(json_file).replace(".json", ".png")))        #img = cv2.imread(data['imagePath'], 0)        height, width = img.shape[:2]        #print(height,width)        #height, width = data['imageHeight'], data['imageWidth']        img = None        image['height'] = height        image['width'] = width        image['id'] = num + 1        #image['file_name'] = data['imagePath'].split('/')[-1]        image['file_name'] = os.path.basename(json_file).replace(".json", ".png")        self.height = height        self.width = width        return image    # 构建类别    def categorie(self, label):        """        "categories": [        {            "supercategory": "component",            "id": 1,            "name": "TB"        }        ],        """        categorie = {}        categorie['supercategory'] = 'component'        categorie['id'] = len(self.label) + 1  # 0 默认为背景        categorie['name'] = label        return categorie    # 构建COCO的annotation字段    def annotation(self, points, label, num):        """        {            "segmentation": [            ],            "iscrowd": 0,            "image_id": 5,            "bbox": [            ],            "area": 37101.0,            "category_id": 1,            "id": 1        },        """        annotation = {}        annotation['segmentation'] = [list(np.asarray(points).flatten())]        annotation['iscrowd'] = 0        annotation['image_id'] = num + 1        # annotation['bbox'] = str(self.getbbox(points)) # 使用list保存json文件时报错(不知道为什么)        # list(map(int,a[1:-1].split(','))) a=annotation['bbox'] 使用该方式转成list        annotation['bbox'] = list(map(float, self.getbbox(points)))        annotation['area'] = annotation['bbox'][2] * annotation['bbox'][3]        annotation['category_id'] = self.getcatid(label)        #annotation['category_id'] = 1        annotation['id'] = self.annID        return annotation    def getcatid(self, label):        for categorie in self.categories:            if label == categorie['name']:                return categorie['id']        return 1    def getbbox(self, points):        # img = np.zeros([self.height,self.width],np.uint8)        # cv2.polylines(img, [np.asarray(points)], True, 1, lineType=cv2.LINE_AA)  # 画边界线        # cv2.fillPoly(img, [np.asarray(points)], 1)  # 画多边形 内部像素值为1        polygons = points        mask = self.polygons_to_mask([self.height, self.width], polygons)        return self.mask2box(mask)    def mask2box(self, mask):   # [x1,y1,w,h]        '''从mask反算出其边框        mask:[h,w]  0、1组成的图片        1对应对象,只需计算1对应的行列号(左上角行列号,右下角行列号,就可以算出其边框)        '''        # np.where(mask==1)        index = np.argwhere(mask == 1)        rows = index[:, 0]        clos = index[:, 1]        # 解析左上角行列号        left_top_r = np.min(rows)  # y        left_top_c = np.min(clos)  # x        # 解析右下角行列号        right_bottom_r = np.max(rows)        right_bottom_c = np.max(clos)        # return [(left_top_r,left_top_c),(right_bottom_r,right_bottom_c)]        # return [(left_top_c, left_top_r), (right_bottom_c, right_bottom_r)]        # return [left_top_c, left_top_r, right_bottom_c, right_bottom_r]  # [x1,y1,x2,y2]        return [left_top_c, left_top_r, right_bottom_c - left_top_c,                right_bottom_r - left_top_r]  # [x1,y1,w,h] 对应COCO的bbox格式    def polygons_to_mask(self, img_shape, polygons):        mask = np.zeros(img_shape, dtype=np.uint8)        mask = PIL.Image.fromarray(mask)        xy = list(map(tuple, polygons))        PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)        mask = np.array(mask, dtype=bool)        return mask    def data2coco(self):        data_coco = {}        data_coco['images'] = self.images           # 构建COCO的image字段        data_coco['categories'] = self.categories   # 构建COCO的categories字段(标注类别数量和类别name信息)        data_coco['annotations'] = self.annotations # 构建COCO的annotations字段        return data_coco    def save_json(self):        self.data_transfer()        self.data_coco = self.data2coco()        # 保存json文件        json.dump(self.data_coco, open(self.save_json_path, 'w'), indent=4, cls=MyEncoder)  # indent=4 更加美观显示labelme_json = glob.glob(r'F:\database\label/*.json')labelme2coco(labelme_json, r'F:\database\annotations/train_label.json')

九、python opencv minAreaRect 生成最小外接矩形

画一个任意四边形(任意多边形都可以)的最小外接矩形,那么点集cnt 存放的就是该四边形的4个顶点坐标(点集里面有4个点)

cnt = np.array([[x1,y1],[x2,y2],[x3,y3],[x4,y4]]) # 必须是array数组的形式rect = cv2.minAreaRect(cnt) # 得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度)box = cv2.cv.BoxPoints(rect) # 获取最小外接矩形的4个顶点坐标(ps: cv2.boxPoints(rect) for OpenCV 3.x)box = np.int0(box)# 画出来cv2.drawContours(img, [box], 0, (255, 0, 0), 1)cv2.imwrite('contours.png', img)

函数 cv2.minAreaRect() 返回一个Box2D结构rect:(最小外接矩形的中心(x,y),(宽度,高度),旋转角度),但是要绘制这个矩形,我们需要矩形的4个顶点坐标box, 通过函数 cv2.cv.BoxPoints() 获得,返回形式[ [x0,y0], [x1,y1], [x2,y2], [x3,y3] ]。

得到的最小外接矩形的4个顶点顺序:中心坐标、宽度、高度、旋转角度(是度数形式,不是弧度数)的对应关系如下:

注意:

旋转角度θ是水平轴(x轴)逆时针旋转,直到碰到矩形的第一条边停住,此时该边与水平轴的夹角。并且这个边的边长是width,另一条边边长是height。也就是说,在这里,width与height不是按照长短来定义的。
在opencv中,坐标系原点在左上角,相对于x轴,逆时针旋转角度为负,顺时针旋转角度为正。所以,θ∈(-90度,0]。

原文链接:https://blog.csdn.net/lanyuelvyun/article/details/76614872

十、自动化修改labelme标注保存好的json文件

labelme标注好后,会自动的生成一个json文件。但是如果需要对标记好的文件内的字段进行批量修改,那么一个个点开再保存,那效率太低了。这里利用python,先获取json存储的信息,修改后,再保存下来。

这里以改变json文件内的label为例。如果你想要修改其他的参数,比如说坐标值、甚至是base64的图像,都可以。

# -*- coding=utf-8 -*-import jsonimport numpy as npimport globimport jsondef get_new_json(filepath):    flag = False    move_flag=False    listbigoption = []    A = dict()    with open(filepath, 'r', encoding='utf-8') as f:        json_data = json.load(f)        # if json_data['shapes'] == []:        #     print(filepath)        # print(json_data['shapes'])        # print(len(json_data['shapes']))        for shapes in json_data['shapes']:            label = shapes['label']            print(label)            noduleMalignant = label.split('_')[-1]            shapes['label'] = 'nodule_'+noduleMalignant            print(shapes['label'])            flag = True    f.close()    return json_data, flag, move_flagclass MyEncoder(json.JSONEncoder):    def default(self, obj):        if isinstance(obj, np.integer):            return int(obj)        elif isinstance(obj, np.floating):            return float(obj)        elif isinstance(obj, np.ndarray):            return obj.tolist()        else:            return super(MyEncoder, self).default(obj)def rewrite_json_file(filepath, json_data):    with open(filepath, 'w') as f:        json.dump(json_data, f, indent=4, cls=MyEncoder)    f.close()import matplotlib.pyplot as pltdef oneDocument():    labelme_json = glob.glob(r'X:\qlj\database\处理前\malignant_1\json/*.json')    n=0    label_list = []    for num, json_path in enumerate(labelme_json):        # print(json_path)        m_json_data, flag, move_flag = get_new_json(json_path)        rewrite_json_file(json_path, m_json_data)if __name__ == '__main__':    oneDocument()

十一、由yolov5学习矩形坐标变换

11.1、xywh2xyxy

def xywh2xyxy(x):    print('x:', x)    # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)    y[:, 0] = x[:, 0] - x[:, 2] / 2  # top left x    y[:, 1] = x[:, 1] - x[:, 3] / 2  # top left y    y[:, 2] = x[:, 0] + x[:, 2] / 2  # bottom right x    y[:, 3] = x[:, 1] + x[:, 3] / 2  # bottom right y    print('y:', y)    return y

输入和输出的坐标信息如下所示:

x: tensor([[188.29141,  55.49617,  56.29586,  95.01012],        [188.17989,  55.49852,  55.87830,  95.67655],        [183.24368,  54.52598,  66.56559,  99.71941],        [188.91458,  55.26056,  58.75016,  93.95803],        [368.82562,  50.15098,  74.95942,  97.38110],        ])y: tensor([[160.14348,   7.99111, 216.43935, 103.00124],        [160.24074,   7.66025, 216.11903, 103.33680],        [149.96089,   4.66628, 216.52647, 104.38568],        [159.53951,   8.28154, 218.28966, 102.23957],        [331.34592,   1.46043, 406.30533,  98.84154]])

11.2、xyxy2xywh

def xyxy2xywh(x):    # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] where xy1=top-left, xy2=bottom-right    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)    y[:, 0] = (x[:, 0] + x[:, 2]) / 2  # x center    y[:, 1] = (x[:, 1] + x[:, 3]) / 2  # y center    y[:, 2] = x[:, 2] - x[:, 0]  # width    y[:, 3] = x[:, 3] - x[:, 1]  # height    return y

11.3、xywhn2xyxy

从归一化坐标 (x = 0,1) (y = 0,1) 转换到像素坐标 (x = 0, w) (x = 0, h)

def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0):    # Convert nx4 boxes from [x, y, w, h] normalized to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)    y[:, 0] = w * (x[:, 0] - x[:, 2] / 2) + padw  # top left x    y[:, 1] = h * (x[:, 1] - x[:, 3] / 2) + padh  # top left y    y[:, 2] = w * (x[:, 0] + x[:, 2] / 2) + padw  # bottom right x    y[:, 3] = h * (x[:, 1] + x[:, 3] / 2) + padh  # bottom right y    return y

11.4、xyn2xy

从归一化坐标 (x = 0,1) (y = 0,1) 转换到像素分割坐标 (x = 0, w) (x = 0, h)

def xyn2xy(x, w=640, h=640, padw=0, padh=0):    # Convert normalized segments into pixel segments, shape (n,2)    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)    y[:, 0] = w * x[:, 0] + padw  # top left x    y[:, 1] = h * x[:, 1] + padh  # top left y    return y


参考文章:https://blog.csdn.net/wsLJQian/article/details/113590115

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时候联系我们修改或删除,在此表示感谢。

特别提醒:

1、请用户自行保存原始数据,为确保安全网站使用完即被永久销毁,如何人将无法再次获取。

2、如果上次文件较大或者涉及到复杂运算的数据,可能需要一定的时间,请耐心等待一会。

3、请按照用户协议文明上网,如果发现用户存在恶意行为,包括但不限于发布不合适言论妄图

     获取用户隐私信息等行为,网站将根据掌握的情况对用户进行限制部分行为、永久封号等处罚。

4、如果文件下载失败可能是弹出窗口被浏览器拦截,点击允许弹出即可,一般在网址栏位置设置

5、欢迎将网站推荐给其他人,网站持续更新更多功能敬请期待,收藏网站高效办公不迷路。

      



登录后回复

共有0条评论