先前做了一个类似的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,注意可能会有兼容性问题(有空就改。)