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

posted @ 2021-11-12 19:29  shines87  阅读(1213)  评论(0)    收藏  举报