DOTA_devkit_YOLO-master工具使用
参见 https://zhuanlan.zhihu.com/p/356416158
1.1、ImgSpliy.py 切图工具。
当然也切割了标签文件,这才是主要功能,子标签文件有可能为空文件 即没有目标;子图文件名记录了在原图中的位置信息和resize_rate.
example
|----images #一共1780*0.9张图片,大小不一,如某图片size=3477*3466 38.01MB
|----{1000_20161003.tif、……}
|----labelTxt #一共1780*0.9个.xml标签
|----{1000_20161003.txt、……}
examplesplit
|----images #一共39458张子图size=1024*1024,gap=400
|----{1000_20161003__1__0___0.png、1000_20161003__1__0___624.png、……}
|---- labelTxt
|----{1000_20161003__1__0___0.txt、1000_20161003__1__0___624.txt、……}
class splitbase(): def __init__(self, basepath, outpath, code='utf-8', gap=400, subsize=1024, thresh=0.7, choosebestpoint=True, ext='.png'): …… if __name__ == '__main__': # example usage of ImgSplit split = splitbase(basepath=r'example', output=r'examplesplit') split.splitdata(rate=1)
输入:example{images, labelTxt}是已有的数据集,两个子文件夹命名可以在.py文件第54行修改。其中labelTxt中的.txt文件内容是dota/poly四点标注法
参数:gap是相邻两子图的gap区,thresh是被截断的目标框是否保留的阈值,rate是子图cv2.resize的比例。
1.2、仅仅切图
def crop(image_file, crop_size, overlap): img = cv2.imread(image_file) print('input image size = {}'.format(img.shape)) height, width = img.shape[:2] offset = crop_size - overlap batch = [] location = [] for i in range(0, height, offset): for j in range(0, width, offset): if i + crop_size > height: i = height - crop_size if j + crop_size > width: j = width - crop_size cropped_img = img[i:i + crop_size, j:j + crop_size] batch.append(cropped_img) location.append([i, j]) return np.array(batch), np.array(location)
补充知识:目标框的标注方法
①外接矩形框标注<x0, y0, w, h>
②poly四点标注法(这4个角由左上角顺时针开始记录) 以下为dota数据集

③opencv表示法(x0, y0, w, h, angle)
(x0,y0)为矩形框中心点;width为辅助线顺时针第一次碰到的边;angle范围是[-90,0)
④长边表示法(x0, y0, l, s, angle)
(x0,y0)是中心点;l是长边 s是短边;angle是辅助线到长边的角度,范围是[-180,0)
2、YOLO_Transform.py
def dota2Darknet(imgpath, txtpath, dstpath, extractclassname)
功能:读取txtpath中②poly格式标注的.txt文件,转为①外接矩形框标注的.txt文件,存入dstpath中。format is "id x y w h"
imgpath:需要读取每一张图片的img_size, 最后return x/img_w, y/img_h, w/img_w, h/img_h.
extractclassname:只转换某些class的目标框(文件记录).
dota_util.parse_dota_poly(fullname) :将一个文件解析成dict list,每一个dict是一行记录 一个目标框(如下)
{'name': 'ship','difficult': '1', 'poly': [(1054.0, 1028.0), (1063.0, 1011.0), (1111.0, 1040.0), (1112.0, 1062.0)]
dota_util.dots4ToRecC(poly, img_w, img_h): 转换为①外接矩形框标注法
def longsideformat2cvminAreaRect(x_c, y_c, longside, shortside, theta_longside)
return ((x_c, y_c), (width, height), theta)
转换:只改动了角度。当width为最长边时(即theta_longside落在[-90,0)中)角度不变,否则theta = theta_longside + 90即可
theta_longside范围[-180, 0),theta范围[-90, 0)
def cvminAreaRect2longsideformat(x_c, y_c, width, height, theta)
return x_c, y_c, longside, shortside, theta_longside
转换原理如上,需特别处理theta=0的情况
def dota2LongSideFormat(imgpath, txtpath, dstpath, extractclassname)
原理:dota_poly -> opencv -> longside标注法。先读取txtpath中的每一个文件,用dota_util.parse_dota_poly解析出poly;用cv函数转换为opencv标注法,
cvminAreaRect2longsideformat函数转换为长边标注法,最后保存。关键部分:
poly = obj['poly'] # poly=[(x1,y1),(x2,y2),(x3,y3),(x4,y4)] poly = np.float32(np.array(poly)) # 四点坐标归一化 poly[:, 0] = poly[:, 0] / img_w poly[:, 1] = poly[:, 1] / img_h rect = cv2.minAreaRect(poly) # 得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度) trans_data = cvminAreaRect2longsideformat(c_x, c_y, w, h, theta) c_x, c_y, longside, shortside, theta_longside = trans_data theta_label = int(theta_longside + 180.5)
额外添加的角度转换[-180,0) -> [0,180)。循环objects时统计有效gt_num,如果为0则os.remove(img_fullname),os.remove(fullname)。

总结:以上4个函数,中间两个是opencv和longside之间的角度转换;首尾两个是poly转其它并保存为文件!
def longsideformat2poly(x_c, y_c, longside, shortside, theta_longside):
rect = longsideformat2cvminAreaRect(x_c, y_c, longside, shortside, (theta_longside - 179.9)) # poly = [(x1,y1),(x2,y2),(x3,y3),(x4,y4)] poly = np.double(cv2.boxPoints(rect)) # 返回rect对应的四个点的值 normalized poly.shape = 8 return poly
def drawLongsideFormatimg(imgpath, txtpath, dstpath, extractclassname, thickness=2):
for i, obj in enumerate(objects): # obj = [classid, x_c_normalized, y_c_normalized, longside_normalized, shortside_normalized, float:0-179] rect = longsideformat2cvminAreaRect(obj[1], obj[2], obj[3], obj[4], (obj[5] - 179.9)) # rect=[(x_c,y_c),(w,h),Θ] Θ:flaot[0-179] -> (-180,0) poly = np.float32(cv2.boxPoints(rect)) # poly = [(x1,y1),(x2,y2),(x3,y3),(x4,y4)] # 四点坐标反归一化 取整 poly[:, 0] = poly[:, 0] * img_w poly[:, 1] = poly[:, 1] * img_h poly = np.int0(poly) # 画出来 cv2.drawContours(image=img, contours=[poly],contourIdx=-1, color=colors[int(obj[0])],thickness=2) cv2.imwrite(img_savename, img)
在.txt中取出长边格式的objects遍历每一个标注框,转换 -> opencv -> poly格式, draw绘制方框到img上再保存。
2021-11-12 19:26:05

浙公网安备 33010602011771号