目标检测-从大尺寸图片截取包含目标的训练图片

"""
此程序用于把原始的图片和标签转换为截图后的图片和标签

设定固定的窗口大小

去截取物体图片

可以把一张图多截取几张图片,以增加数据量
已实现


"""

import os.path
import shutil

import cv2
import random
from  multiprocessing import Process,Pool

class Crop_Img:
    # 0 初始化
    def __init__(self,txt_path="",img_path="",window_w=640,window_h=640):

        self.txt_path=txt_path #待处理文本路径
        self.img_path=img_path #待处理图片路径
        self.window_w=window_w #滑窗宽
        self.window_h=window_h #滑窗高
        self.temp_list=[] #目标在原图中的位置列表[xmin,ymin,xmax,ymax,class]
        self.slide_list=[] #滑窗在原图中的位置列表[xmin,ymin,xmax,ymax]
        self.xyxy_list=[] #异物在滑窗中的位置列表[xmin,ymin,xmax,ymax]
        self.xxyywwhh_list=[] #异物在滑窗中归一化后的位置列表[class,x,y,w,h]

    # 1 判断保存文件是否存在
    def path_isexist(self):
        self.save_dir = os.path.dirname(self.img_path)
        self.save_dir=os.path.dirname(self.save_dir)
        self.save_img_dir = os.path.join(self.save_dir, "save_imgs")  # 裁剪后保存图片的路径
        self.save_txt_dir = os.path.join(self.save_dir, "save_labels")  # 裁剪后保存图片的标签

        if not os.path.exists(self.save_img_dir):
            os.mkdir(self.save_img_dir)

        if not os.path.exists(self.save_txt_dir):
            os.mkdir(self.save_txt_dir)

    # 2 把读取的xywh转换为xyxy然后返回
    def get_xyhw2xyxy_from_txt(self):
        """
        根据txt读取坐标信息,把归一化的xyhw坐标转换为xyxy坐标
        """

        image = cv2.imread(self.img_path)
        file = open(self.txt_path)
        content = file.readlines()
        for x in content:
            x = x.replace("\n", "")
            temp_coor = x.split(" ")
            xx = float(temp_coor[1])
            yy = float(temp_coor[2])
            ww = float(temp_coor[3])
            hh = float(temp_coor[4])
            wt = int(image.shape[1])
            ht = int(image.shape[0])
            xmin = int(wt * xx - 0.5 * ww * wt)
            xmax = int(wt * xx + 0.5 * ww * wt)
            ymin = int(ht * yy - 0.5 * hh * ht)
            ymax = int(ht * yy + 0.5 * hh * ht)
            self.temp_list.append(xmin)
            self.temp_list.append(ymin)
            self.temp_list.append(xmax)
            self.temp_list.append(ymax)
            self.temp_list.append(temp_coor[0])
        print("temp",self.temp_list)
        return self.temp_list

    # 3 随机生成截取区域,
    def slide_window(self):
        """
        根据目标在原始图片中的位置随机生成滑动窗口

        可以多生成几个滑动窗口以增强数据集
        """
        window_num=1 #想要生成多少个滑窗

        image = cv2.imread(self.img_path)
        img_w = int(image.shape[1])
        img_h = int(image.shape[0])

        for i in range(window_num):
            while (True):
                slide_list = []  # 临时存放滑窗坐标
                while (True):
                    ys = random.randint(0, int(self.temp_list[1]))
                    if ys + self.window_h < img_h:
                        break
                while (True):
                    xs = random.randint(0, int(self.temp_list[0]))
                    if xs + self.window_w < img_w:
                        break

                if xs < self.temp_list[0] and xs + self.window_w > self.temp_list[2] and ys < self.temp_list[1] and ys + self.window_h > self.temp_list[3]:
                        slide_list.append(xs)
                        slide_list.append(ys)
                        slide_list.append(xs + self.window_w)
                        slide_list.append(ys + self.window_h)
                        self.slide_list.append(slide_list)
                        break
                else:
                    continue

    # 4 裁剪图片部分区域
    def crop_img_from_originalimg(self,save_img_dir):
        """

        把在原图中截取的图片保存在指定文件夹save_img_dir中

        """
        i=1
        for slide_list in self.slide_list:

            image = cv2.imread(self.img_path)
            a = int(slide_list[0])
            b = int(slide_list[2])
            c = int(slide_list[1])
            d = int(slide_list[3])

            cropImg = image[c:d, a:b]  # 裁剪图像  注意image[ymin:ymax,xmin:xmax]
            name = self.img_path.split("\\")[-1]
            name=name.split(".")[0]
            name=name + "_{}.jpg".format(i)
            i += 1
            dest = os.path.join(save_img_dir, name)
            cv2.imwrite(dest, cropImg)  # 写入图像路径

    # 5 获取异物在滑窗内的xyxy和xywh
    def get_realative_xyxy_xywh_in_slidewindow(self):

        """
        返回物体在滑动窗口的左上右下坐标,和相对于截取后物体在滑窗中的相对坐标classesname,xx,yy,ww,hh
        """


        for slide_list in self.slide_list:
            xxyywwhh_list=[]
            xyxy_list=[]

            xmin = int(self.temp_list[0]) - int(slide_list[0])
            ymin = int(self.temp_list[1]) - int(slide_list[1])
            xmax = int(self.temp_list[2]) - int(slide_list[0])
            ymax = int(self.temp_list[3]) - int(slide_list[1])
            class_name = self.temp_list[4]

            xx = float(float(xmin + xmax) / 2.0) / float(self.window_w)
            yy = float(float(ymin + ymax) / 2.0) / float(self.window_h)
            ww = float(xmax - xmin) / float(self.window_w)
            hh = float(ymax - ymin) / float(self.window_h)

            xxyywwhh_list.append(class_name)
            xxyywwhh_list.append(xx)
            xxyywwhh_list.append(yy)
            xxyywwhh_list.append(ww)
            xxyywwhh_list.append(hh)
            self.xxyywwhh_list.append(xxyywwhh_list)

            xyxy_list.append(xmin)
            xyxy_list.append(ymin)
            xyxy_list.append(xmax)
            xyxy_list.append(ymax)
            self.xyxy_list.append(xyxy_list)

            print("xyxy_list",self.xyxy_list)
            print("xxyywwhh_list",self.xxyywwhh_list)

    # 6 把get_realative_xyxy_xywh_in_slidewindow这个函数获取的wywh坐标写入txt文件
    def write_realative_txt(self,save_txt_dir):
        """
        把目标在滑动窗口中的[class,x,y,w,h]写入txt文件中
        """
        i=1
        for xxyywwhh_list in self.xxyywwhh_list:
            txt_name = self.txt_path.split("\\")[-1]
            txt_name=txt_name.split(".")[0]
            txt_name=txt_name+"_{}.txt".format(i)
            i+=1
            save_txt_path = os.path.join(save_txt_dir, txt_name)
            with open(save_txt_path, "a", encoding="gbk") as f:
                f.write(str(xxyywwhh_list[0]))
                f.write(" ")
                f.write(str(xxyywwhh_list[1]))
                f.write(" ")
                f.write(str(xxyywwhh_list[2]))
                f.write(" ")
                f.write(str(xxyywwhh_list[3]))
                f.write(" ")
                f.write(str(xxyywwhh_list[4]))

    # 7 运行该函数即可
    def main_get_crop_img_txt(self):
        """
        获得最终结果运行此方法即可
        :param save_img_dir:
        :param save_txt_dir:
        :return:
        """
        self.path_isexist()
        self.get_xyhw2xyxy_from_txt()
        self.slide_window()
        self.get_realative_xyxy_xywh_in_slidewindow()

        self.crop_img_from_originalimg(self.save_img_dir)
        self.write_realative_txt(self.save_txt_dir)

    # 8 根据cxywh格式在原图中画框
    def draw_rec(self, cor_list,save_flag=True):
        """
        save_flag:是否把画的框保存在原图中
                True:保存
                False:仅显示
        根据坐标在图片中画框
        cor_list[xmin,ymin,xmax,ymax]
        """
        image = cv2.imread(self.img_path)
        draw_0 = cv2.rectangle(image, (int(cor_list[0]), int(cor_list[1])), (int(cor_list[2]), int(cor_list[3])),
                               (0, 0, 255), 2)

        if save_flag:
            cv2.imwrite(self.img_path, draw_0)
        else:
            cv2.imshow('deaw_0', draw_0)
            cv2.waitKey(0)  # 等待按键

    #其他功能————————————————————————————————————————————————————————————————————

    # 9 从文本里读路径并找出来然后放在指定文件夹
    def get_contents_without_huiche_from_txt(self):
        """
        传入一个文本
        输出没有回车符的队列

        forexample:

        输入:
        print(read_txt(r"D:\desk\A_3.txt"))
        文本内容读进来是这样的
        ["asdasda\n",asdasdasd\n]

        输出:
        ["asdasda",asdasdasd]

        """
        file = open(self.txt_path)
        content = file.readlines()
        temp_list = []
        for x in content:
            x = x.replace("\n", "")
            temp_list.append(x)
        return temp_list

    # 10 批量重命名
    def batch_rename(self,path):
        """
        :param path:
        输入
        ——imgs
        —————A
        ———————a.jpg
        ———————at.jpg
        ———————ad.jpg
        ———————aw.jpg
        ———————aq.jpg
        ———————ar.jpg
        ...
        —————B
        ......

        输出
        ——imgs
        —————A
        ———————A_1.jpg
        ———————A_2.jpg
        ———————A_3.jpg
        ———————A_4.jpg
        ———————A_5.jpg
        ———————A_6.jpg
        ...
        :return:
        """
        for dir_name in os.listdir(path):
            path_dir = os.path.join(path, dir_name)
            if os.path.isdir(path_dir):
                i = 0
                for img_name in os.listdir(path_dir):
                    img_path = os.path.join(path_dir, img_name)
                    i += 1
                    name_suffix=img_name.split(".")[-1]
                    rename_path = os.path.join(path_dir, "{}_{}.{}".format(dir_name, i,name_suffix))
                    print(rename_path)
                    os.rename(img_path, rename_path)
        print("Successflly Changed")
        return

    # 11 从txt列出的路径里找到对应的图片并加入到文件夹中去
    def from_txt_get_images(self,save_img_dir, txt_path):
        with open(txt_path, "r", encoding="gbk") as f:
            content = f.readlines()
            image_path_list = content[0].split("\\n")
            image_path_list.remove("")

            for x in image_path_list:
                x = x.split("/")
                a = x[0][:-6]
                b = x[1]
                img_path = a + "JEPGimages\\" + b
                img_name = img_path.split("\\")[-1]
                new_img_path = save_img_dir + "\\" + img_name
                shutil.copy(img_path, new_img_path)
                print(new_img_path)

    # 12 统计图片的大中小目标个数
    def get_num_big_mediun_small(self):
        self.get_xyhw2xyxy_from_txt()
        self.obj_num = {"small_num": 0, "medium_num": 0, "big_num": 0} #用来保存目标数量


        w_object=self.temp_list[2]-self.temp_list[0]
        h_object=self.temp_list[3]-self.temp_list[1]
        piex_object=w_object*h_object

        if piex_object <= 32 * 32 and piex_object >= 0:
            self.obj_num["small_num"] += 1
        if piex_object > 32 * 32 and piex_object <= 96 * 96:
            self.obj_num["medium_num"] += 1
        if piex_object > 96 * 96:
            self.obj_num["big_num"] += 1
        print(self.obj_num)

    # 13 找出最合适切块儿的行与列,结合下面的cut_img(14)一起使用
    def judge_best_column_row(self,img_size_list):
        """
        :param img_size_list: 你想要的图像块儿的尺寸
        :return:
        """
        # 找出最合适的分割行和列

        img = cv2.imread(self.img_path)
        h, w = img.shape[:2]
        best_row = 1
        best_colu = 1

        patch_h = h
        patch_w = w

        close_value_h = img_size_list[0]
        close_value_w = img_size_list[1]
        for row in range(2, 20):
            temp_h = h / row
            if abs(temp_h - close_value_h) < abs(patch_h - close_value_h):
                patch_h = temp_h
                best_row = row

        for colu in range(2, 20):
            temp_w = w / colu
            if abs(temp_w - close_value_w) < abs(patch_w - close_value_w):
                patch_w = temp_w
                best_colu = colu
        return best_row, best_colu

    # 14 把图片切块儿
    def cut_imgs(self):

        row,column=self.judge_best_column_row([640,640])

        # 需要分割的图片
        org_img = cv2.imread(self.img_path)

        # 判断文件夹是否为空?
        path_save_dir = os.path.dirname(self.img_path)
        path_save=os.path.join(path_save_dir,"cut_dir")

        if not os.path.exists(path_save):
            os.mkdir(path_save)

        if len(os.listdir(path_save)) != 0:
            shutil.rmtree(path_save)
            os.mkdir(path_save)

        height, width = org_img.shape[:2]
        print('height %d widht %d' % (height, width))

        row_step = (int)(height / row)
        column_step = (int)(width / column)

        print('row step %d col step %d' % (row_step, column_step))

        print('height %d widht %d' % (row_step * row, column_step * column))

        img = org_img[0:row_step * row, 0:column_step * column]

        # 把图片写入文件夹
        for i in range(row):
            for j in range(column):
                pic_name = path_save + '\\' + str(i) + "_" + str(j) + ".jpg"
                tmp_img = img[(i * row_step):(i * row_step + row_step),
                          (j * column_step):(j * column_step) + column_step]
                cv2.imwrite(pic_name, tmp_img)



#批量在原图中截目标
def get_crop_img_and_txt(img_dir,txt_dir):
    for img_name in os.listdir(img_dir):
        if img_name.endswith("jpg"):
            img_path=os.path.join(img_dir,img_name)
            txt_name=img_name.split(".")[0]+".txt"
            txt_path=os.path.join(txt_dir,txt_name)
            crop_img = Crop_Img(txt_path,img_path,2000,2000)
            crop_img.main_get_crop_img_txt()

#批量在图片中画框
def draw_rec_in_img(save_img_dir,save_txt_dir):
    for img_name in os.listdir(save_img_dir):
        if img_name.endswith("jpg"):
            img_path=os.path.join(save_img_dir,img_name)
            txt_name=img_name.split(".")[0]+".txt"
            txt_path=os.path.join(save_txt_dir,txt_name)

            c=Crop_Img(txt_path,img_path)
            temp=c.get_xyhw2xyxy_from_txt()
            c.draw_rec(temp,True)


if __name__ == '__main__':

    weichuli = ["A","B","B-","C","C-","D","D-","D--","E","E-","F","F-","G","G-","H","H-","I","J","K","K-", "L", "L-"]
    print(len(weichuli))

    for x in weichuli:
        img_dir = r"F:\xuedi\New_img\images\{}".format(x)  # 未裁剪的图片
        txt_dir = r"F:\xuedi\New_img\labels-hebing\{}".format(x)  # 未裁剪的标签

        get_crop_img_and_txt(img_dir, txt_dir)

    # draw_rec_in_img(save_img_dir,save_txt_dir)

    # c=Crop_Img(img_path=img_path)
    # c.cut_imgs()




当时处理机场异物数据集时写的代码

把分辨率为3000*4000的图片

截图为1000*1000的图片

以及生成对应的标签文件


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值