python脚本对labelme标注的数据集进行镜面旋转扩充数据集(修复)

先前做了一个类似的python脚本对labelme标注的数据集进行镜面旋转扩充数据集_标定数据集图像镜像旋转 py-CSDN博客,最近使用时发现有一点bug,修复了一下,在对非正方形图像进行镜面翻转时会出现标签偏移。主要是之前的工作都是基于正方形图像的,所以没发现这些问题,给出了新的翻转,旋转代码,同时给出了对labelme标签及图像进行切割成1000*1000尺寸的代码以供参考。

对labelme 及图像进行镜面旋转

#旋转图片,如果高度大于宽度,就旋转90度
from PIL import Image
import glob 
import math 
import os
import os.path as osp
import base64
import json
def rolationer(img_path,angel,descritions=''):
    """
    实现图片反时针旋转功能:旋转角度为90度,180度,270度,
    如果同文件夹下有同名json文件,也会对json文件进行旋转
    """
    save_dir = os.path.dirname(img_path) 
    basename = os.path.basename(img_path)
    json_basename = basename.split('.')[:-1][0]+'.json'
    json_path = osp.join(save_dir, json_basename)
    save_json_path = osp.join(save_dir, descritions+json_basename)
    save_img_path = osp.join(save_dir, descritions+basename)
    # 判断json文件是否存在
    is_exists = os.path.exists(json_path)
    if is_exists:
        f = open(json_path, encoding='utf-8')
        setting = json.load(f)
        width = setting['imageWidth']
        height = setting['imageHeight']
        mid_width = width / 2
        mid_height = height / 2
        for i2 in range(len(setting['shapes'])):
            for i3 in range(len(setting['shapes'][i2]['points'])):
                temp_x = setting['shapes'][i2]['points'][i3][0]
                temp_y = setting['shapes'][i2]['points'][i3][1]
                if angel==180:
                    new_x = (temp_x -  mid_width)*math.cos(math.radians(angel)) - (temp_y - mid_height)*math.sin(math.radians(angel)) + mid_width
                    new_y = (temp_x -  mid_width)*math.sin(math.radians(angel)) + (temp_y - mid_height)*math.cos(math.radians(angel)) + mid_height 
                    if new_y > height:
                        new_y = height
                    if new_x > width:
                        new_x = width
                elif angel==90 or angel==270:
                    new_x = (temp_x -  mid_width)*math.cos(math.radians(angel)) - (temp_y - mid_height)*math.sin(math.radians(angel)) + mid_height
                    new_y = (temp_x -  mid_width)*math.sin(math.radians(angel)) + (temp_y - mid_height)*math.cos(math.radians(angel)) + mid_width
                    if new_y > width:
                        new_y = width
                    if new_x > height:
                        new_x = height
                if new_x < 0:
                    new_x = 0
                if new_y < 0:
                    new_y = 0
                setting['shapes'][i2]['points'][i3][0] = new_x
                setting['shapes'][i2]['points'][i3][1] = new_y
        setting['imageWidth'] = height
        setting['imageHeight'] = width
        setting['imagePath'] = descritions+basename
        pri_image = Image.open(img_path)
        if angel==90:
            pri_image.transpose(Image.Transpose.ROTATE_270).save(save_img_path)
        elif angel==180:
            pri_image.transpose(Image.Transpose.ROTATE_180).save(save_img_path)
        elif angel==270:
            pri_image.transpose(Image.Transpose.ROTATE_90).save(save_img_path)
        else:
            print('输入正确的角度!')
            return
        # 将转换后的图片进行base64加密
        with open(save_img_path, 'rb') as f:
            setting['imageData'] = base64.b64encode(f.read()).decode()
        string = json.dumps(setting,indent=4)
        # 将修改后的json写入文件
        with open(save_json_path, 'w', encoding='utf-8') as f:
            f.write(string)
            f.close()
    else:
        pri_image = Image.open(img_path)
        if angel==90:
            pri_image.transpose(Image.Transpose.ROTATE_270).save(save_img_path)
        elif angel==180:
            pri_image.transpose(Image.Transpose.ROTATE_180).save(save_img_path)
        elif angel==270:
            pri_image.transpose(Image.Transpose.ROTATE_90).save(save_img_path)
        else:
            print('输入正确的角度!')
            return
        
def mirroror(img_path,mode,descritions):
    """实现图片左右翻转和上下翻转功能,mode=0表示左右翻转,mode=1表示上下翻转,如果同文件夹下有同名json文件,也会对json文件进行翻转"""
        # 图片路径
    save_dir = os.path.dirname(img_path) 
    basename = os.path.basename(img_path)
    json_basename = basename.split('.')[:-1][0]+'.json'
    json_path = osp.join(save_dir, json_basename)
    save_json_path = osp.join(save_dir, descritions+json_basename)
    save_img_path = osp.join(save_dir, descritions+basename)
    is_exists = os.path.exists(json_path)
    if is_exists:
        f = open(json_path, encoding='utf-8')
        setting = json.load(f)
        width = setting['imageWidth']
        height = setting['imageHeight']
        mid_width = width / 2
        mid_height = height / 2
        for i2 in range(len(setting['shapes'])):
            for i3 in range(len(setting['shapes'][i2]['points'])):
                temp_x = setting['shapes'][i2]['points'][i3][0]
                temp_y = setting['shapes'][i2]['points'][i3][1]
                if mode==0:
                    if temp_x > mid_width:
                        dis = temp_x - mid_width
                        new_x = mid_width - dis
                    elif temp_x < mid_width:
                        dis = mid_width - temp_x
                        new_x = mid_width + dis
                    else:
                        new_x = temp_x
                    new_y = temp_y
                elif mode==1:
                    if temp_y > mid_height:
                        dis = temp_y - mid_height
                        new_y = mid_height - dis
                    elif temp_y < mid_height:
                        dis = mid_height - temp_y
                        new_y = mid_height + dis
                    else:
                        new_y = temp_y
                    new_x = temp_x
                setting['shapes'][i2]['points'][i3][0] = new_x
                setting['shapes'][i2]['points'][i3][1] = new_y    
        setting['imagePath'] = descritions+basename
        pri_image = Image.open(img_path)
        if mode == 0:
            pri_image.transpose(Image.Transpose.FLIP_LEFT_RIGHT).save(save_img_path)
        elif mode == 1:
            # 上下镜面翻转FLIP_TOP_BOTTOM
            pri_image.transpose(Image.Transpose.FLIP_TOP_BOTTOM).save(save_img_path)
        else:
            print('输入正确的mode!')
            return
        with open(save_img_path, 'rb') as f:
            setting['imageData'] = base64.b64encode(f.read()).decode()
        string = json.dumps(setting)
        # 将修改后的json写入文件
        with open(save_json_path, 'w', encoding='utf-8') as f:
            f.write(string)
            f.close()
    else:
        if mode == 0:
            pri_image.transpose(Image.Transpose.FLIP_LEFT_RIGHT).save(save_img_path)
        elif mode == 1:
            # 上下镜面翻转FLIP_TOP_BOTTOM
            pri_image.transpose(Image.Transpose.FLIP_TOP_BOTTOM).save(save_img_path)
        else:
            print('输入正确的mode!')
            return

对labelme标注进行切割


import cv2 as cv
import matplotlib.pyplot as pl
import os
import numpy as np
import labelme_generator as lg
import glob
import re 
import json
from alive_progress import alive_bar
#修复输出json尺寸不对的问题
'''

将标注好的图片(jpg+json)文件,切割成固定尺寸的默认为1000*1000  input ipg+json -> output jpg+json
例如对于一张3721*5732的图片
算法会将这张图片分割成 
            0000-1000   1000-2000   2000-3000   3000-4000 
0000-1000       00          01          02         03        
1000-2000       10          11          12         13
2000-3000       20          21          22         23           
3000-4000       30          31          32         33
4000-5000       40          41          42         43
5000-6000       50          51          52         53
共计4*6=24张图,不足的像素用黑色补足
需要的函数
1.读取文件:json 和 jpg 
2.补足函数
3.切割图片函数
4.切割json函数
    计算量较大:思路1:首先依据json绘制单块的mask img 对该图片运用切割函数
    很复杂,思路2:遍历每个shape polygon points 判别以下列表
        情况1.points完全在框内,则 任意points[[x1, y1], [x2, y2], ...]有 a<x<b,c<y<d,
        情况2.points在两个及以上框内
        判别情况1和2的方法,对于任意点x,y 例如(500,1740)有int(x/1000.0)=0,int(y/1000.0)=1 有area=int(x/1000.0)*10+int(y/1000.0)=1,对应01区域
        由此会获得一个points<--->area的对应关系,处在边界上的两边点area应该例如这样   ...,1,1,1,1,2,2,2,2,...
        可取出变值的points 线性差值计算出一个在边界上的点(x,y),加入点集后,分割取出,
'''
#================================================================
#                   图片切割函数
#================================================================
def blackmaker(img):
    '''
    以黑色填充补全图片
    
    '''
    if img.shape[0]%1000.0==0 and img.shape[1]%1000.0==0 :
        return(img)
    else :
        img_extend=np.zeros((int(img.shape[0]/1000.0+1)*1000,int(img.shape[1]/1000.0+1)*1000,3),'uint8')
        img_extend[:img.shape[0],:img.shape[1],:]=img_extend[0:img.shape[0],0:img.shape[1],:]+img
        return img_extend

def cutimg_counters(img):
    '''
    返回切割点
    '''
    point_list=[]
    if img.shape[0]%1000.0==0 and img.shape[1]%1000.0==0 :
        for i in range(int(img.shape[0]/1000)):
            beH=i*1000
            hEnd=beH+1000
            for j in range(int(img.shape[1]/1000)):
                
                beW=j*1000
                wLen=beW+1000
                point_list.append([beH,hEnd,beW,wLen])
    else:
        print('error!切割失败!')
        print(img.shape)
    return point_list

def cutimg(img,beH,hEnd,beW,wLen):
    '''
    # 读取要被切割的图片
    img = cv.imread("D:/pig.jpg")
    #beH 要被切割的开始的像素的高度值
    # hEnd 要被切割的结束的像素的高度值
    #beW 要被切割的开始的像素的宽度值
    #wLen  要被切割的结束的像素的宽度值
    # 对图片进行切割
    dstImg = img[beH:hEnd,beW:wLen]
    '''
    
    dstImg = img[beH:hEnd,beW:wLen]
    
    return dstImg

def imgcutor(img,point_list,img_name,img_format):
    '''
    执行图片切割,返回图片集 和 对应区域标识
    '''
    imgname=os.path.basename(img_name).strip('.jpg').strip ('.png').strip(".JPG").strip(img_format)
    imgpicker=[]
    cutimg_decorator=[]
    for i in range(len(point_list)):
        imgpicker.append(cutimg(img,point_list[i][0],point_list[i][1],point_list[i][2],point_list[i][3]))
        cutimg_decorator.append(imgname+"_"+str(int(point_list[i][2]/1000))+str(int(point_list[i][0]/1000)))
    
    return imgpicker,cutimg_decorator 




#================================================================
#                   labelme json 切割函数
#================================================================

def draw_polygon(shape_list,imgshape,z=3):
    '''
    绘制一个多边形,带填充的颜色BGR=(0,255,0),这里用作绘制mask
    --------------
    
    input:\n
        shape_list=[[],[],[],...]\n
        imgshape=[x,y]\n
        z:通道数\n
    output:\n
        polygon_image:单体mask\n
        [x,y,w,h]:box框\n
        cv.rectangle(c, (d[0], d[1]), (d[0]+d[2], d[1]+d[3]), (0, 0, 255), 1)
    '''
    if z==1:
        color=255
    elif z==3:
        color=(0,255,0)
    im = np.zeros([imgshape[0], imgshape[1],z], dtype = np.uint8)
    b=shape_list.copy()
    b=np.asarray(b,np.int32)
    b=np.reshape(b,(b.shape[0],1,b.shape[1]))
    #cv.polylines(im, a, 1, 255)
    polygon_image=cv.fillPoly(im,[b] , color)
    x,y,w,h = cv.boundingRect(b)
    
    return polygon_image ,[x,y,w,h]

def imgpick_pack():
    
    
    pass


    
def json_cut(img_format,shapes,imgshape,imagePath,version,flags,lineColor,fillColor):
    '''
    负责将shape绘制到单mask上,切割寻找轮廓点,直接读取json shapes字典集合 
    '''
    json_list = []
    signal=0
    for j in shapes: #读取字典集合
        label=j["label"] #读取label
        points=j["points"] #读取points
        line_color=j["line_color"]
        fill_color=j["fill_color"]
        shape_type=j["shape_type"]
        flags2=j["flags"] #与json区分
        polygon_image,bounding=draw_polygon(points,imgshape) #获得mask和mask box框
        polygon_image=blackmaker(polygon_image)
        points_label=cutimg_counters(polygon_image) #返回切割点
        imgpicker2,cutimg_decorator2=imgcutor(polygon_image,points_label,imagePath,img_format) 
        #获取切割轮廓
        
        
        
        #创建json文件
        if signal==0:
            for index in range(len(imgpicker2)):
                #json_list.append(lg.jsoncreator([],cutimg_decorator2[index]+img_format,0,imgshape[0], imgshape[1],version,flags,lineColor,fillColor))
                json_list.append(lg.jsoncreator([],cutimg_decorator2[index]+img_format,0,1000, 1000,version,flags,lineColor,fillColor))
        signal+=1
        ##检查空元素
        #
        for index in range(len(imgpicker2)-1,-1,-1): #倒序遍历
            if imgpicker2[index].any()==0:
                imgpicker2.pop(index)
                cutimg_decorator2.pop(index)
            #else :
                #print(cutimg_decorator2[index])
        imgpicker2=json_get_points(imgpicker2) 
        '''
        此时已经获得了只有分割后的points(imgpicker)和对应区域名(cutimg_decorator)
        对于每个区域存在以下情况
            1.有一个或多个points
            2.没有points
        现在打算先初始化每个区域的json格式,再进行剔除
        '''
        imgpicker2=json_to_points(imgpicker2,label,shape_type,line_color,fill_color,flags2)
        #若区域存在并相同,则添加到存在的json里
        for index in range(len(imgpicker2)):
            for l in range(len(json_list)):
                if cutimg_decorator2[index]+img_format==json_list[l]["imagePath"]:#need c
                    a=json_list[l]["shapes"]
                    b=imgpicker2[index]
                    json_list[l]["shapes"].append(imgpicker2[index])
    return json_list    
        
        
        
        
def json_to_points(imgpicker,label,shape_type,line_color,fill_color,flags):
    '''
    打包成shapes里面的字典,返回原列表
    '''
    for index in range(len(imgpicker)):
        imgpicker[index]=lg.single_shapetype_creator(label,imgpicker[index],shape_type,line_color,fill_color,flags)
    return imgpicker


def json_get_points(imgpicker):
    '''
    提取对应区块多边形点,直接返回原列表
    '''
    for index in range(len(imgpicker)): #获取每个imgpicker里面的mask多边形点

        gray=cv.cvtColor(imgpicker[index],cv.COLOR_BGR2GRAY)
        et,thresh=cv.threshold(gray, 20, 255, cv.THRESH_BINARY)
        contours, hierarchy = cv.findContours(thresh,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
        contours=sorted(contours,key=cv.contourArea,reverse=True) #按面积大排序
        if len(contours) == 0:
            imgpicker[index]=[]
        else:
            cnt_max=lg.lesscnt(contours[0]) #简化点
            imgpicker[index]=lg.con_packeger(cnt_max) ##提取多边形点

    return imgpicker
            
            
#================================================================
#                   写入\读取\路径更改函数
#================================================================


def dirmaker(path,signal=False,printtext='alreadly exit!'):
    '''
    用于创建目录
    '''
    try :
        os.makedirs(path)
    
    except:
        if signal == True:
            print(printtext)        
            
        else :
            pass

def jsonreader(labelmefile_json):
    '''
    用于打开json文件
    '''
    with open (labelmefile_json, encoding='utf-8') as jsonfile:
            setting = json.load(jsonfile)  # 读取json
            # 获取当前图片尺寸
            #width = setting['imageWidth']
            #height = setting['imageHeight']        
            #遍历shapes
            #for i2 in range(len(setting['shapes'])):
                #pass
    return setting






#================================================================
#                   执行与测试函数
#================================================================
def data_checking(file1, file2):
    '''
    检查集合名字是否一一对应(去除后缀
    '''
    if len(file1) != len(file2):
        return 0
    check_bool=1
    for i in range(len(file1)):
        m = re.search('(?<=\.)[^.]*$',file1 [i])
        n =re.search('(?<=\.)[^.]*$',file2 [i])
        if file1 [i].strip(m.group(0)) != file2 [i].strip(n.group(0)) :
            check_bool=0
    return check_bool


def showimg(img):
#show img 
    img=cv.cvtColor(img,cv.COLOR_BGR2RGB)
    pl.imshow(img)
    pl.show()
    
def run_cut(labelmefilepath='labelme generator output/',outputfilepath='labelme_cut_output/',img_format=".jpg"):
    '''
    主函数 
    '''
    #读取
    img_list = glob.glob(labelmefilepath + "*" + img_format)
    json_list= glob.glob(labelmefilepath + "*.json" )
    
    #检查
    if data_checking(img_list,json_list):
        print("=======================================")
        print("       文件关系对应正确")
        print("       读取文件总数:%s"%len(img_list))
        print("=======================================")
        #===图片切割===
        with alive_bar(len(img_list)) as bar:
            for i in range(len(img_list)):
                #print("-----------------------------")
                bar.text='Read:%s:'%img_list[i]
                #创建输出目录
                save_path=os.path.join(outputfilepath,os.path.basename(img_list[i]).strip(img_format))
                dirmaker(save_path)

                img=cv.imread(img_list[i])
                img=blackmaker(img)
                point_list=cutimg_counters(img)
                imgpicker,cutimg_decorator=imgcutor(img,point_list,img_list[i],img_format)
            #===json切割===
                setting=jsonreader(json_list[i]) #读取json
                version =setting["version"]
                flags =setting["flags"]
                lineColor =setting["lineColor"]
                fillColor =setting["fillColor"]
                imagePath=setting["imagePath"]
                shapes=setting["shapes"] #字典集合
                shape_h=setting["imageHeight"]
                shape_w=setting["imageWidth"]
                jsonlist=json_cut(img_format,shapes,[shape_h,shape_w],imagePath,version,flags,lineColor,fillColor) #这里认为imagePath为不带路径的名字
            #===打包json===

                #创建图片,返回对应json
                for index in range(len(imgpicker)):
                    imgname=cutimg_decorator[index]+img_format
                    imageData=lg.img_to_json(imgpicker[index],save_path,imgname)
                    jsonlist[index]["imageData"]=imageData

                    jsonname=cutimg_decorator[index]+".json"
                    jsonpath=os.path.join(save_path,jsonname)
                    lg.jsonpackage(jsonlist[index],jsonpath)
                bar()
                #bar.text="切割%s完成,切割数量%s"%(os.path.basename(img_list[i]),len(imgpicker))
                #print("-----------------------")
                #print("切割%s完成,"%os.path.basename(img_list[i]))
                #print("切割数量%s,"%len(imgpicker))
                #print("-----------------------")
    print("=======================================")            
    print("输出完成 输出结果保存:%s"%outputfilepath)
    print("=======================================")

    

    
    
    
    
    
    
    
    
    
if __name__ == "__main__":

    run_cut()

调用的labelme_generator.py如下:





#------------------------------------------
#   用已经识别生成的mask生成labelme标记文件
#------------------------------------------
#仍存在JPG文件先执行JPGtojpg

"""

请不要随意更改产生的图片名字,不然匹配不上
需要实现的功能:
    1.转化标签
    2.转化多边形F
    转化json
    1和2难以对应。。可能还需要一些手段
        拟引入box框,box框ID对应一个标签,用box框生成一个蒙版屏蔽不感兴趣区域->
        调用findContours-》获取polygon点
    box框和标签都导入csv中储存,参数为4个角点参数,一个标签参数
算法实现上有点问题,表现为box框里若有其他的石头mask,识别轮廓就有问题
建议更改为利用img_onlyonemask_out里的图片单体mask配合box来实现效果
"""

import os
import glob
import pandas as pd
import json
import cv2 as cv
import numpy as np
import base64
import re
#import matplotlib.pyplot as plt




def con_packeger(con_amax):
    """
    从contour中生成点集

    """
    polygonponit_list=[]
    con_list=con_amax.tolist()
    for num in range(len(con_list)):
        ponit_p=[con_list[num][0][0],con_list[num][0][1]]
        polygonponit_list.append(ponit_p)
    
    return polygonponit_list


def jsoncreator(shapes,imagePath,imageData,imageHeight,imageWidth,version="3.16.7",flags={},lineColor=[0,255,0,128],fillColor=[255,0,0,128]):
    """
    创建一个标准的labelme格式的json内建文件
    
    """
    a={
        "version":"3.16.7",
        "flags": {},
        "shapes": 
            [
                
            ],
        "lineColor": [
        0,
        255,
        0,
        128
        ],
        "fillColor": [
        255,
        0,
        0,
        128
        ],
        "imagePath": "",
        "imageData":"",
        "imageHeight": 0,
        "imageWidth": 0
        
        }
    a["lineColor"]=lineColor
    a["fillColor"]=fillColor
    a["version"]=version
    a["flags"]=flags
    a["shapes"]=shapes
    a["imagePath"]=imagePath
    a["imageData"]=imageData
    a["imageHeight"]=imageHeight
    a["imageWidth"]=imageWidth
    return a

def single_shapetype_creator(label,polygonponit_list,shape_type="polygon",line_color=None,fill_color=None,flags={}):
    """
    写入单个形状
    """
    b={
        "label":label,
        "line_color": None,
        "fill_color": None,
        "points": polygonponit_list,
        "shape_type": shape_type,
        "flags": {}
    }
    b["line_color"] = line_color
    b["fill_color"] = fill_color
    b["flags"] = flags
    
    return b

def shape_dir_creator(*single_shapetype_creator):
    """
    生成shape列表,没用
    """
    shapes=list( single_shapetype_creator)
    return shapes

def img_to_json(img,save_path,imgname):
    """
    将原图片拷贝到输出目录下并转为json数据,img由cv2读取
    """
    
    img_path_with_name=os.path.join(save_path,imgname)
    cv.imwrite(img_path_with_name,img)
    with open(img_path_with_name, "rb") as f:
        imgdata_json= base64.b64encode(f.read()).decode()
    return imgdata_json

def jsonpackage(dir,jsonpath):
    """
    写入json文件
    """
    with open(jsonpath, "w") as f:
        json.dump(dir, f,indent=2) 
        
def labelme_generate_p1(img,mask_img,class_name_list,left_list,top_list,right_list,bottom_list):
    """
    总体json打包器 part1
    
    """
    shapes=[]
    for k in range(len(class_name_list)):
        
        box_mask_img=cv.rectangle(np.zeros(np.shape(img), dtype=np.uint8), (left_list[k],top_list[k]), (right_list[k],bottom_list[k]),(0,255,0),-1) #绘制一个box实心框当做感兴趣的蒙版
        box_mask_img=cv.cvtColor(box_mask_img,cv.COLOR_BGR2GRAY)
        mask_masked = cv.add(mask_img, np.zeros(np.shape(img), dtype=np.uint8), mask=box_mask_img) #提取mask 感兴趣区域
        
        mask_masked=cv.cvtColor(mask_masked,cv.COLOR_BGR2GRAY)
        ret,thresh=cv.threshold(mask_masked, 20, 255, cv.THRESH_BINARY)
        #contours, hierarchy = cv.findContours(thresh,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_TC89_L1)
        
        contours, hierarchy = cv.findContours(thresh,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
        #可能会识别出多个轮廓,挑选最大con_amax的那个
        con_area=0
        for con in contours:
            if con_area<cv.contourArea(con):
                con_area=cv.contourArea(con)
                con_amax=con 
        if con_area==0:
            continue
        polygonponit_list=con_packeger(con_amax) #提取多边形点
        label=str(class_name_list[k])+"_%s"%k  #标签类似于stone_5
        shapes.append(single_shapetype_creator(label,polygonponit_list,shape_type="polygon"))
    return shapes

def labelme_generate_p1_2(img,onemask_img_path,class_name_list,left_list,top_list):
    """
    总体json打包器 part1 为单体mask准备的
    
    """
    shapes=[]
    

    for k in range(len(class_name_list)):
        #单蒙版轮廓查找
        onemask_img=cv.imread(onemask_img_path[k])
        onemask_img_gray=cv.cvtColor(onemask_img,cv.COLOR_BGR2GRAY)
        ret,thresh=cv.threshold(onemask_img_gray, 20, 255, cv.THRESH_BINARY)
        
        #box_mask_img=cv.rectangle(np.zeros(np.shape(img), dtype=np.uint8), (left_list[k],top_list[k]), (right_list[k],bottom_list[k]),(0,255,0),-1) #绘制一个box实心框当做感兴趣的蒙版
        #box_mask_img=cv.cvtColor(box_mask_img,cv.COLOR_BGR2GRAY)
        #mask_masked = cv.add(mask_img, np.zeros(np.shape(img), dtype=np.uint8), mask=box_mask_img) #提取mask 感兴趣区域
        #
        #mask_masked=cv.cvtColor(mask_masked,cv.COLOR_BGR2GRAY)
        #ret,thresh=cv.threshold(mask_masked, 20, 255, cv.THRESH_BINARY)
        #contours, hierarchy = cv.findContours(thresh,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_TC89_L1)
        contours, hierarchy = cv.findContours(thresh,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
        #可能会识别出多个轮廓,挑选最大con_amax的那个
        contours = sorted(contours, key=cv.contourArea, reverse=True)
        con_amax=contours[0]
        con_amax=lesscnt(con_amax)
        con_amax[:,0,0]=con_amax[:,0,0]+left_list[k]
        con_amax[:,0,1]=con_amax[:,0,1]+top_list[k]
        polygonponit_list=con_packeger(con_amax) #提取多边形点
        label=str(class_name_list[k])+"_%s"%k  #标签类似于stone_5
        shapes.append(single_shapetype_creator(label,polygonponit_list,shape_type="polygon"))
    return shapes


#轮廓点简化
def lesspointlist(pointlist):
    '''
    轮廓点简化
    ----------
    input:\n
    pointlist=[[42, 0], [40, 2], [38, 2], [37, 3], [35, 3], [34, 4], [33, 4], [32, 5], [31, 5], [25, 11], [25, 12], [23, 14], [23, 15], [19, 19], [19, 20], [18, 21], [18, 22], [16, 24], [16, 25], [15, 26], [15, 27], [14, 
    28], [14, 29], [12, 31], [12, 32], [11, 33], [11, 34], [10, 35], [10, 36], [9, 37], [9, 38], [8, 39], [8, 40], [7, 41], [7, 43], [6, 44], [6, 46], [5, 47], [5, 48], [4, 49], [4, 51], [3, 52], [3, 54], [4, 55], [4, 57], [6, 59], [6, 60], [9, 63], [10, 63], [12, 65], [13, 65], [14, 66], [15, 66], [16, 67], [17, 67], [18, 68], [38, 68], [39, 67], [41, 67], [42, 66], [45, 66], [46, 65], [47, 65], [57, 55], [57, 54], [61, 50], [61, 49], [62, 48], [62, 44], [63, 43], [63, 34], [64, 33], [64, 24], [65, 23], [65, 15], [66, 14], [66, 5], [65, 4], [65, 2], [64, 1], [64, 0]]
    \noutput:\n
    pointlist=[[64, 0], [42, 0], [31, 5], [25, 11], [12, 31], [3, 52], [4, 57], [9, 63], [18, 68], [38, 68], [47, 65], [61, 50], [63, 43], [66, 14], [66, 5]]

    '''
    cnt3=np.asarray(pointlist,np.int32)
    cnt3=np.reshape(cnt3,(cnt3.shape[0],1,cnt3.shape[1]))
    polyFit = cv.approxPolyDP(cnt3,1, True)
    pointlist=np.reshape(polyFit,(polyFit.shape[0],polyFit.shape[2])).tolist()
    return pointlist

def lesscnt(cnt):
    '''
    轮廓点简化
    ----------
    输入cnt2=contours[0],cnt格式同输出polyfit''' 
    
    if len(cnt) >3:
        polyFit = cv.approxPolyDP(cnt,3, True)
        return polyFit
    else:
        return cnt
    #cv.polylines(fitContour, [polyFit], True, 255, 1)
    

if __name__ == "__main__":
    # 原图片路径
    img_path = "img/"
    # mask路径,弃用
    mask_path = "img_onlymask_out/"
    # 单体mask路径,现在分开输出了
    mask_path2 = "img_onlyonemask_out/"
    #box框和标签路径
    data_path = "img_out/"
    # 生成数据的保存路径,包括原图和json文件
    save_path = "labelme generator output/"
    # 当前数据集图片格式
    file_format = ".jpg"
    data_format=".csv"

    # 替换格式jpg -> json 
    replace_format = ".json"
    data_replace_format=" box data.csv"

    #匹配图片和mask 格式.jpg -> onlymask.jpg 弃用了全体mask
    mask_replace_format = " onlymask.jpg"

    #匹配图片和mask 格式.jpg -> onlyonemask  
    mask_replace_format2 = " onlyonemask" #imagename+mask_replace_format2+str(stoneID)+file_format




    try :
        os.mkdir(save_path)
    except:
        pass

    # 获取数据集目录的图片数据集
    img_list = glob.glob(img_path + "*" + file_format)
    #mask_flist = glob.glob(mask_path2 + "*" + file_format)
    mask_file_list=os.listdir(mask_path2) #获取单体mask的文件夹列表
    
    #mask_file_list = glob.glob(mask_path2)  
    data_list = glob.glob(data_path + "*" + data_format)

    print("读取图片:"+str(img_list))
    print("读取mask图片文件夹:"+str(mask_file_list))
    print("读取标签:"+str(data_list))

    
    
    
    # 1.遍历图片
    for i in range(len(img_list)):
        imgname_withpath = img_list[i]  #获取一个图片地址
        maskfilename_withpath = os.path.join(mask_path2,mask_file_list[i] )#获取一个单体mask文件夹地址,由于名字一样,是对应的
        #maskname_withpath = mask_list[i]
        data_withpath=data_list[i] #获取一个boxdata地址,由于名字除了后缀都差不多,基本是对应的

        maskname_list_withpath = glob.glob(maskfilename_withpath+ "/*" + file_format) #获取一个单体mask文件夹里的mask图片地址列表
        print("读取单体mask文件数量%s"%len(maskname_list_withpath))
        #数字分类
        try :
            maskname_list_withpath.sort(key=lambda x: int(re.search('(?<=onlyonemask)\d\d*',x).group(0)))  #匹配onlyonemask后面的数字,并以此排序
        except :
            print('未分类的情况1!请检查排序名称是否正确')
            print(maskname_list_withpath)

        imgname=os.path.basename(imgname_withpath)
        dataneme=os.path.basename(data_withpath)

        #检测单体mask文件夹地址是否存在:
        mask_path_ex=os.path.join(mask_path2,imgname.strip(file_format.upper()).strip(file_format.lower()))
        mask_is_exists= os.path.exists(mask_path_ex)
        #mask_path_ex = imgname.replace(file_format,mask_replace_format)#mask basename
        #mask_path_ex=os.path.join(mask_path,mask_path_ex)
        #mask_is_exists = os.path.exists(mask_path_ex)#检验蒙版是否对应
        #mask_is_exists=1 #不检测对应关系!
        data_path_ex=dataneme.replace(file_format,data_replace_format)
        data_path_ex=os.path.join(data_path,data_path_ex)
        data_is_exists=os.path.exists(data_path_ex)#检验data是否对应

        if data_is_exists:
            #     读取标签数据
            box_data=pd.read_csv(data_withpath) 
            stoneID_list=box_data["Unnamed: 0"]
            top_list=box_data["box_top"]
            left_list=box_data["box_left"]
            bottom_list=box_data["box_bottom"]
            right_list=box_data["box_right"]
            class_name_list=box_data["class_name"]
            stoneID_list=stoneID_list.tolist()
            top_list=top_list.tolist()
            left_list=left_list.tolist()
            bottom_list= bottom_list.tolist()
            right_list= right_list.tolist()
            class_name_list= class_name_list.tolist()

            #print(class_name_list)


            if mask_is_exists:

                print("已找到匹配项:%s \n:(box_data:%s,maskfile:%s)"%(imgname,dataneme,maskfilename_withpath))
                
                img=cv.imread(imgname_withpath) #read the image
                #生成形状集合
                shapes=labelme_generate_p1_2(img,maskname_list_withpath,class_name_list,
                                                        left_list,top_list)
                #将原图片拷贝到输出目录下并转为json数据,img由cv2读取
                #imgname中不能有.JPG,因此需要先去掉.JPG
                saveimgname=imgname.strip(file_format.upper()).strip(file_format.lower())+'.jpg'
                imgdata_json=img_to_json(img,save_path,saveimgname)
                #创建一个标准的labelme格式的json内建文件
                jsonfile=jsoncreator(shapes,imgname,imgdata_json,
                                                np.shape(img)[0],np.shape(img)[1],version="3.16.7")
                jsonpath=os.path.join(save_path,imgname.replace(file_format,replace_format))
                jsonpackage(jsonfile,jsonpath)
                    #plt.imshow(mask_masked)
                    #plt.show()
                print("----->%s:打包完成<-----"%imgname)
                print('----------------------------------')



这是先前写的代码,当时的labelme版本还是3.XX,注意可能会有兼容性问题(有空就改。)

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Imgaug库对labelme标注后的json格式的数据集进行扩充。Imgaug是一个强大的图像增强库,可以应用各种图像增强技术来扩充数据集。 首先,你需要安装Imgaug库。你可以使用以下命令来安装Imgaug: ``` pip install imgaug ``` 接下来,你需要加载labelme标注后的json格式的数据集。你可以使用labelme库来加载和解析json文件。下面是一个示例代码: ```python import json from labelme import utils def load_labelme_json(json_path): with open(json_path, 'r') as f: data = json.load(f) return data json_data = load_labelme_json('path/to/json/file.json') ``` 然后,你可以使用Imgaug库来定义并应用各种图像增强技术。例如,你可以使用以下代码来实现随机水平翻转和随机旋转的图像增强: ```python import imgaug.augmenters as iaa # 定义图像增强器 augmenter = iaa.Sequential([ iaa.Fliplr(0.5), # 随机水平翻转概率为50% iaa.Affine(rotate=(-45, 45)) # 随机旋转角度范围为-45到45度 ]) # 对每张图像进行增强 for image_data in json_data['images']: image = utils.img_b64_to_arr(image_data['data']) augmented_image = augmenter.augment_image(image) # 在这里可以对增强后的图像进行保存或其他操作 ``` 注意,Imgaug库还支持许多其他的图像增强技术,如缩放、裁剪、亮度调整、颜色变换等。你可以根据自己的需求选择适当的增强技术,并将其添加到图像增强器中。 希望这个回答能对你有帮助!如果你还有其他问题,请继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值