目标检测数据预处理——非宫格与宫格混合拼图(大宽高比图片)

之前一直用的是宫格的正方形拼图,但比如对“人”框的截图是这种高宽高比的长方形图片,按照最大边resize最小边等比例缩放后放入宫格中对造成最小边resize太多,整体图片缩小很多。所以本片专门针对高宽高比的图片拼图进行编辑。

本篇的拼图方式有2种:分别是长方形拼图和正方形拼图(即宫格拼图)。其中正方形拼图有4种,从1×1到4×4;长方形拼图有4种,分别是1×2、2×1、2×3、3×2,根据宽高比在哪个范围内以及横向或者纵向来判断按照对应的方式进行拼图。判断流程如下:

Created with Raphaël 2.3.0 输入图片 max_len = max(img_h, img_w) max_len == img_w ? rate = img_w / img_h, state = "水平" rate = img_h / img_w, state = "垂直" yes no
state为水平
state为垂直
state为水平
state为垂直
state为水平
state为垂直
state为水平
state为垂直
rate和state
rate<1.2
从1*1到4*4
1.2 <= rate <= 1.3
1*1
3*2
2*3
1.3 < rate < 1.7
3*2
2*3
1.7 <= rate <= 1.8
3*2和2*1
2*3和1*2
rate > 1.8
2*1
1*2

n×n的这里不再贴图演示,这里演示非宫格的拼图效果:
1×2:
在这里插入图片描述
2×1:
在这里插入图片描述
2×3:
在这里插入图片描述
3×2:
在这里插入图片描述
若是上面的流程图判断不是很清晰的话,可以看下面的数轴更加直观简单:
在这里插入图片描述
因为1.2到1.3与1.7到1.8是两边的中间区域,所以让这区间的图片同时resize成两个size的图片。

python">'''
5 size
1*1 1*2 2*1 2*3 3*2
'''
import codecs
from genericpath import exists
import random
import PIL.Image as Image
import os
import cv2
import json2txt
import sys
sys.path.append("/data/cch/拼图代码/format_transform")
import modeTxt
import shutil
import cut_bbox

# 图像拼接
def image_compose(idx, ori_tmp, num, save_path, gt_resized_path, bg_resized_path, imgsize, yr, xr, xs, ys):
    to_image = Image.new('RGB', (imgsize, imgsize)) #创建一个新图
    
    for y in range(yr):
        for x in range(xr):
            index = y*xr + x
            if index >= len(ori_tmp):
                break
            open_path = [gt_resized_path, bg_resized_path]
            for op in open_path:
                if os.path.exists(os.path.join(op, ori_tmp[index])):
                    to_image.paste(Image.open(os.path.join(op, ori_tmp[index])), (
                        int(x * xs), int(y * ys)))
                    break
                else:
                    continue
    new_name = os.path.join(save_path, "2022workcloth_pedestrain_" + str(idx) + "_" + str(num) + ".jpg")
    if xr == yr:
        new_name = os.path.join(save_path, "2022workcloth_square_" + str(idx) + "_" + str(num) + ".jpg")
    to_image.save(new_name) # 保存新图
    # print(new_name)
    return new_name

# 标签拼接
def labels_merge(ori_tmp, new_name, txt_resized_path, txt_pintu_path, yr, xr, xs, ys):
    data = ""
    for y in range(yr):
        for x in range(xr):
            index = y*xr + x
            if index >= len(ori_tmp):
                break
            txt_path = os.path.join(txt_resized_path, ori_tmp[index].split(".")[0] + ".txt")
            try:
                os.path.exists(txt_path)
            except:
                print(txt_path, "file not exists!")
            if os.path.exists(txt_path):
                with codecs.open(txt_path, 'r', encoding='utf-8',errors='ignore') as f1:
                    for line in f1.readlines():
                        line = line.strip('\n')
                        a = line.split(' ')
                        a[2] = str(float(a[2]) + (x * xs))
                        a[3] = str(float(a[3]) + (y * ys))
                        a[4] = str(float(a[4]) + (x * xs))
                        a[5] = str(float(a[5]) + (y * ys))
                        b =a[0] + ' ' + a[1] + ' ' + a[2] + ' ' + a[3] + ' ' + a[4] + ' ' + a[5]
                        data += b + "\n"

    write_path = os.path.join(txt_pintu_path, os.path.splitext(new_name)[0].split("/")[-1] + ".txt")
    with open(write_path, 'w', encoding='utf-8') as f2:    
        f2.writelines(data)
 
 # 涂黑处理
def pintu2black(txt_pintu_path, save_path, label_black, label_del, to_black_num, to_black_min_num):
    files = os.listdir(txt_pintu_path)
    for file in files:
        img_path = os.path.join(save_path, os.path.splitext(file)[0] + ".jpg")
        img_origal = cv2.imread(img_path)
        data = ""
        with codecs.open(txt_pintu_path+"/"+file, encoding="utf-8", errors="ignore") as f1:
            for line in f1.readlines():
                line = line.strip("\n")
                a = line.split(" ")
                xmin = int(eval(a[2]))
                ymin = int(eval(a[3]))
                xmax = int(eval(a[4]))
                ymax = int(eval(a[5]))
                if ((xmax - xmin < to_black_num) and (ymax - ymin < to_black_num)) or \
                    ((xmax - xmin < to_black_min_num) or (ymax - ymin < to_black_min_num)) \
                    or a[1] in label_black:
                    img_origal[ymin:ymax, xmin:xmax, :] = (0, 0, 0)
                    cv2.imwrite(img_path, img_origal)
                    line = ""
                if a[1] in label_del:
                    line = ""
                if line:
                    data += line + "\n"
        with open(txt_pintu_path+"/"+file, 'w', encoding='utf-8') as f2:    
            f2.writelines(data)
        # print(data)

def gt_distribute(imgSave_path, ori, ori_spec, gt_resized_path, txt_path, gt_range):
    image_names = os.listdir(imgSave_path)
    for image_name in image_names:
        imgPath = os.path.join(imgSave_path, image_name)
        img = cv2.imread(imgPath)
        [img_h, img_w, _] = img.shape
        max_len = max(img_h, img_w)
        print(image_name, max_len)
        state = ""
        rate = 0
        if max_len == img_w:
            state = "horizontal"
            rate = img_w / img_h
        else:
            state = "vertical"
            rate = img_h / img_w

        if rate < 1.2:
            for index in range(len(gt_range)):
                if gt_range[index][0] <= max_len < gt_range[index][1]:
                    gt_resized_name = gt_resize(gt_resized_path, txt_path, image_name, img, gt_range[index][0], index+1, state, True)
                    ori_spec[index].append(gt_resized_name)
            continue
        
        # gt_resize函数的参数True为最长边resize,False为最短边resize,意在resize后的最短、最长边都不会超出格子的最短、最长边
        if 1.2 <= rate <= 1.3:
            gt_resized_name = gt_resize(gt_resized_path, txt_path, image_name, img, imgsize, 1, state, True)
            ori_spec[0].append(gt_resized_name)   # 1:1
            gt_resized_name = gt_resize(gt_resized_path, txt_path, image_name, img, int(imgsize/3), 2, state, False)
            if state == "horizontal": 
                ori[2].append(gt_resized_name)   # 2:3
            else:
                ori[3].append(gt_resized_name)   # 3:2

        if 1.3 < rate < 1.7:
            if rate <= 1.5:
                gt_resized_name = gt_resize(gt_resized_path, txt_path, image_name, img, int(imgsize/3), 1, state, False)
            else:
                gt_resized_name = gt_resize(gt_resized_path, txt_path, image_name, img, int(imgsize/2), 1, state, True)
            if state == "horizontal":
                ori[2].append(gt_resized_name)    # 2:3
            else:
                ori[3].append(gt_resized_name)    # 3:2

        if 1.7 <= rate <= 1.8:
            gt_resized_name_1 = gt_resize(gt_resized_path, txt_path, image_name, img, int(imgsize/2), 1, state, True)
            gt_resized_name_2 = gt_resize(gt_resized_path, txt_path, image_name, img, int(imgsize/2), 2, state, False)
            if state == "horizontal":
                ori[2].append(gt_resized_name_1)    # 2:3
                ori[0].append(gt_resized_name_2)    # 1:2
            else:
                ori[3].append(gt_resized_name_1)    # 3:2 
                ori[1].append(gt_resized_name_2)    # 2:1

        # if 1.8 < rate <= 2.2:
        if 1.8 < rate:
            if rate <= 2:
                gt_resized_name = gt_resize(gt_resized_path, txt_path, image_name, img, int(imgsize/2), 1, state, False)
            else:
                gt_resized_name = gt_resize(gt_resized_path, txt_path, image_name, img, imgsize, 1, state, True)
            if state == "horizontal":
                ori[0].append(gt_resized_name)    # 1:2
            else:
                ori[1].append(gt_resized_name)    # 2:1

def gt_resize(gt_resized_path, txt_path, image_name, img, img_size, x, state, flag):
    if not os.path.exists(gt_resized_path):
        os.mkdir(gt_resized_path)
    [img_h, img_w, _] = img.shape
    img_read = [0, 0, 0]
    if state == "horizontal":
        if flag:
            precent = img_size / img_w
            img_read = cv2.resize(img, (img_size, int(img_h * precent)), interpolation=cv2.INTER_CUBIC)
        else:
            precent = img_size / img_h
            img_read = cv2.resize(img, (int(img_w * precent), img_size), interpolation=cv2.INTER_CUBIC)
    else:
        if flag:
            precent = img_size / img_h
            img_read = cv2.resize(img, (int(img_w * precent), img_size), interpolation=cv2.INTER_CUBIC)
        else:
            precent = img_size / img_w
            img_read = cv2.resize(img, (img_size, int(img_h * precent)), interpolation=cv2.INTER_CUBIC)
    img_resized = gt_resized_path + "/" + image_name.split(".")[0] + "_" + str(x) + ".jpg"
    cv2.imwrite(img_resized, img_read)

    txt_name = txt_path + "/" + image_name.split(".")[0] + ".txt"
    txt_resized_name = gt_resized_path + "/" + image_name.split(".")[0] + "_" + str(x) + ".txt"
    if os.path.exists(txt_name):
        data = ""
        with codecs.open(txt_name, 'r', encoding='utf-8',errors='ignore') as f1:
            for line in f1.readlines():
                line = line.strip('\n')
                a = line.split(' ')
                a[2] = str(float(a[2]) * precent)
                a[3] = str(float(a[3]) * precent)
                a[4] = str(float(a[4]) * precent)
                a[5] = str(float(a[5]) * precent)
                b =a[0] + ' ' + a[1] + ' ' + a[2] + ' ' + a[3] + ' ' + a[4] + ' ' + a[5]
                data += b + "\n"
        with open(txt_resized_name, 'w', encoding='utf-8') as f2:    
            f2.writelines(data)
    return img_resized.split("/")[-1]

if __name__ == "__main__":
    images_path = '/data/cch/000test/images'  # 图片集地址  
    json_path = "/data/cch/000test/json"

    save_path = '/data/cch/pintu_data/test/workcloth/save1'
    tmp = "/data/cch/000test/tmp"

    #----------------------------------------------------------------
    # imgSave_path = "/data/cch/pintu_data/test/workcloth/images"
    # jsonSava_path = "/data/cch/pintu_data/test/workcloth/json"

    # if not os.path.exists(imgSave_path):
    #     os.mkdir(imgSave_path)
    # else:
    #     shutil.rmtree(imgSave_path)
    #     os.mkdir(imgSave_path)

    # if not os.path.exists(jsonSava_path):
    #     os.mkdir(jsonSava_path)
    # else:
    #     shutil.rmtree(jsonSava_path)
    #     os.mkdir(jsonSava_path)

    # cut_bbox.main(images_path, json_path, imgSave_path, ["person"], 0)   # person切图
    # cuts = os.listdir(imgSave_path)
    # for cut in cuts:
    #     if not os.path.splitext(cut)[-1] == ".json":
    #         continue
    #     json_f = os.path.join(imgSave_path, cut)
    #     shutil.move(json_f, jsonSava_path)
    #----------------------------------------------------------------

    if not os.path.exists(save_path):
        os.mkdir(save_path)
    else:
        shutil.rmtree(save_path)
        os.mkdir(save_path)

    if not os.path.exists(tmp):
        os.mkdir(tmp)
    else:
        shutil.rmtree(tmp)
        os.mkdir(tmp)
    bg_resized_path = os.path.join(tmp, "bg_resized")
    gt_resized_path = os.path.join(tmp, "gt_resized")
    txt_path = os.path.join(tmp, "txt")        # 原数据txt
    txt_pintu_path = os.path.join(tmp, "txt_pintu")

    os.mkdir(txt_path)
    os.mkdir(txt_pintu_path)

    label_black = ["other"]
    label_del = ["del"]
    imgsize = 416
    to_black_num = 15        
    to_black_min_num = 5 
    
    img_threshold = [1 / 2 * 1.2, 1 / 2 * 1.4, 1 / 6 * 1.3, 1 / 6 * 1.5]   # 每个size的图拼阈值
    img_threshold_spec = [0.3, 1 / 4 * 1.8, 1 / 9 * 1.7, 1 / 16 * 1.6]

    gt_range = [[imgsize, 10000], [int(imgsize/2), 10000], [int(imgsize/3), imgsize], [int(imgsize/4), int(imgsize/2)]]

    json2txt.main_import(jsonSava_path, txt_path)

    ori = []
    for i in range(4):
        ori.append([])    # 存放顺序 1:2 2:1 2:3 3:2

    ori_spec = []
    for i in range(4):
        ori_spec.append([])     # 存正方形小图
    
    gt_distribute(imgSave_path, ori, ori_spec, gt_resized_path, txt_path, gt_range)    # 不同size的小图放入对应容器中

    idx = 1

    for ori_m in ori_spec:       # n×n拼图
        if len(ori_m) == 0:
            idx += 1
            continue
        img_threshold_spec[idx-1] *= len(ori_m)
        if idx == 1 and img_threshold_spec[idx-1] > 80:
            img_threshold_spec[idx-1] = 80
        num = 0
        random.shuffle(ori_m)
        picknum = idx * idx
        if len(ori_m) < picknum:
            img_threshold_spec[idx-1] = 1
        index = 0
        while num < int(img_threshold_spec[idx-1]):
            ori_tmp = []
            if idx == 1:
                new_name = image_compose(idx, [ori_m[num]], num, save_path, gt_resized_path,\
                    bg_resized_path, imgsize, idx, idx, imgsize/idx, imgsize/idx)
                labels_merge([ori_m[num]], new_name, gt_resized_path, txt_pintu_path, idx,\
                    idx, imgsize/idx, imgsize/idx)

            else:
                if len(ori_m) > picknum:
                    if index >= len(ori_m):
                        random.shuffle(ori_m)
                        index = 0
                    ori_tmp = ori_m[index:index+picknum]
                    index = index + picknum
                else:
                    ori_tmp = ori_m.copy() 
                new_name = image_compose(idx, ori_tmp, num, save_path, gt_resized_path, \
                    bg_resized_path, imgsize, idx, idx, imgsize/idx, imgsize/idx) #调用函数
                labels_merge(ori_tmp, new_name, gt_resized_path, txt_pintu_path, idx,\
                    idx, imgsize/idx, imgsize/idx)

                ori_tmp.clear()
            num += 1

        print(idx, num, len(ori_m))
        idx += 1

    idx = 1
    for ori_n in ori:                  # 长方形拼图
        if len(ori_n) == 0:
            idx += 1
            continue
        # ori_path = os.path.join(save_path, "ori_" + str(idx) + ".txt")
        img_threshold[idx-1] *= len(ori_n)
        # if idx == 1 and img_threshold[idx-1] > 80:
        #     img_threshold[idx-1] = 80
        num = 0
        random.shuffle(ori_n)
        picknum = 0                      
        if idx == 1 or idx == 2:         # 1×2或2×1 拼2张
            picknum = 2
        elif idx == 3 or idx == 4:       # 2×3或3×2 拼6张
            picknum = 6
        if len(ori_n) < picknum:
            img_threshold[idx-1] = 1
        index = 0
        while num < int(img_threshold[idx-1]):
            ori_tmp = []
            [yr, xr, xs, ys] = 1, 1, 0, 0       # x,y的图片张数 小图粘贴到大图的左上角起始坐标
            # if idx == 1:
            #     new_name = image_compose(idx, [ori_n[num]], num, save_path, gt_resized_path, bg_resized_path, imgsize, yr, xr, xs, ys)
            #     labels_merge([ori_n[num]], new_name, gt_resized_path, txt_pintu_path, yr, xr, xs, ys)

            # else:
            if len(ori_n) > picknum:
                # random.sample(ori_n, picknum)
                if index >= len(ori_n):
                    random.shuffle(ori_n)
                    index = 0
                ori_tmp = ori_n[index:index+picknum]
                index = index + picknum
            else:
                ori_tmp = ori_n.copy()
            
            if idx == 1:
                [yr, xr, xs, ys] = 2, 1, imgsize, imgsize/2
            elif idx == 2:
                [yr, xr, xs, ys] = 1, 2, imgsize/2, imgsize
            elif idx == 3:
                [yr, xr, xs, ys] = 3, 2, imgsize/2, imgsize/3
            elif idx == 4:
                [yr, xr, xs, ys] = 2, 3, imgsize/3, imgsize/2
            new_name = image_compose(idx, ori_tmp, num, save_path, gt_resized_path, bg_resized_path, imgsize, yr, xr, xs, ys) #调用函数
            labels_merge(ori_tmp, new_name, gt_resized_path, txt_pintu_path, yr, xr, xs, ys)

            ori_tmp.clear()
            num += 1

        print(idx, num, len(ori_n))
        idx += 1

    pintu2black(txt_pintu_path, save_path, label_black, label_del, to_black_num, to_black_min_num)

    modeTxt.txt2darknet(txt_pintu_path, save_path, save_path)
    shutil.rmtree(tmp)
  1. 这里的拼图同样也是带文件的拼图,相应的label也会随之改变。
  2. resize的函数相较于以前版本的加了个布尔类型的flag参数,用来判断是用最大边resize还是用最小边resize,意在不会使得最大边或者最小边都不超出格子。
    比如:1.3 < rate < 1.7的图片是拼2×3的,还要再判断是否<=1.5。如果<=1.5,flag要为False即用最短边resize,因为假设格子的最长边为3最短边为2,如果此时用图片的最长边resize成3的话,最短边等比例缩放不管rate为1.3或无限接近1.5都会大于2。

http://www.niftyadmin.cn/n/351634.html

相关文章

基于QEMU的RISC-V架构linux系统开发(三)——基于buildroot的最小根文件系统配置与编译

1.buildroot官网下载最新版本的buildroot。 https://buildroot.org/download.html 图1 下载最新版本的buildroot压缩包 2.拷贝buildroot软件包到工作目录&#xff0c;并解压buildroot。 图2 解压buildroot软件包 3.新建编译脚本build_risc-v.sh&#xff0c;使用buildroot自带的…

29岁测试被辞,面试2个月还找不到工作....

最近一个29岁老同学联系我&#xff0c;因为被公司辞退&#xff0c;找我倾诉&#xff0c;于是写下此文。 他是14年二本毕业&#xff0c;在我的印象里人特别懒&#xff0c;不爱学习&#xff0c;专业不好&#xff0c;毕业前因为都没找到合适工作&#xff0c;直接去创业了&#xf…

WIN提权 令牌窃取进程注入

令牌窃取&#xff08;鸡肋玩意 2008包括2008以下&#xff09; 令牌&#xff0c;又叫token&#xff0c;是系统临时产生的秘钥&#xff0c;相当于账号密码&#xff0c;用来决定是否允许此次请求和判断此次请求是属于哪一个用户。 win7一下的版本可以尝试 这里使用msf上自带的令…

5 个章节、25 条规范,全方位 Get 数据集选择与创建的「百科全书」

By 超神经 内容一览&#xff1a;如果你正在学习如何创建或选择一个合适的数据集&#xff0c;那么这篇文章会给你一些实用的建议&#xff0c;帮助你在选择和创建数据集时做出明智的决策。 关键词&#xff1a;机器学习 数据集 本文首发自 HyperAI 超神经微信公众平台~ 作者 |…

耗时162天,从华为外包5k转岗正式员工15k,经历的心酸只有自己知道····

一提及外包测试&#xff0c;大部分人的第一印象就是&#xff1a;工作强度大&#xff0c;技术含量低&#xff0c;没有归属感&#xff01; 本人毕业于某普通二本院校非计算机专业&#xff0c;跨专业入行测试&#xff0c;至今有近 5年工作经验。 第一份测试工作是在华为做了两年外…

基于ROS2的costmap中Obstacle Layer中对障碍物信息的增加与删除机制的方案调研。

文章目录 1.背景2.目标3. 障碍物信息添加方式发送数据的数据结构与接收数据的数据结构 4. 障碍物清理机制4.1 可调参数4.2 优化光追算法4.3 障碍物跟踪 1.背景 基于costmap地图&#xff0c;使用navigation导航时&#xff0c;会出现由于激光雷达/图像测距的局限性&#xff0c; …

苦卷一个月,P9大佬给我的Alibaba面试手册,终于成功踹开字节大门

怎么说呢&#xff0c;今年真的是寒气逼人啊&#xff01;在这个大环境下&#xff0c;裁员已经不算是特别的事情&#xff0c;粗暴裁员也许是未来一种趋势…在职的卷的起飞&#xff0c;离职的找不到好工作。 做点能做的&#xff1a;跑跑步骑骑车多锻炼&#xff1b;当当上面正版书…

第十五届“中国电机工程学会杯”数学建模竞赛

第十五届电工杯5月26号就要开始啦&#xff0c;今天给大家回顾第十四届全国大学生电工数学建模竞赛A题&#xff0c;主要从赛题重述和问题分析与代码实战展开。第十五届全国大学生电工数学建模竞赛已经开始报名了哦&#xff0c;后续我也会分享对应的建模思路哦&#xff0c;大家记…