imgaug Augment Polygons 对标注图片和polygons的数据增强

news2024/11/13 11:40:58

对于本地化进行图像的增强,大家都是非常好操作的。但是,对于标注信息一起增强,还是稍微有一些难度的,麻烦很多。

我是遇到一个数据集非常少的任务,只有40张图。就直接标记了去训练,发现几乎不拟合,当然这里使用的是yolo v8,而不是UNet。

于是,先本地化给增强到50倍数据集,然后再去训练,说不定是个好的方法。这里采用的就是imgaug的开源库,学习参考如下:

  1. imgaug 地址
  2. 官方文档
  3. Augment Polygons

一、单张实验下

1、首先,是采用labelme标注的一张图像,如下,是用labelme打开时候看到的内容:

在这里插入图片描述

imgaug查看原图和标记内容,如下:

import imageio
import imgaug as ia
import json
import numpy as np
from imgaug.augmentables.polys import Polygon, PolygonsOnImage

class LabelJson(object):
    def __init__(self, abs_path=None) -> None:
        super().__init__()
        self.abs_path = abs_path
        self.read()

    def read(self):
        with open(self.abs_path, 'r', encoding='utf-8') as f:
            lj = json.load(f)
        self.wh = [lj.get('imageWidth'), lj.get('imageHeight')]
        shapes = lj.get('shapes')
        self.cls = [i.get('label') for i in shapes]  # '1305' if i.get('label') == '14' else
        points = [i.get('points') for i in shapes]
        points = [np.array(i, dtype=np.int32).reshape((-1, 2)) for i in points]
        self.loc = points
        self.box = [[j[:, 0].min(), j[:, 1].min(), j[:, 0].max(), j[:, 1].max()] for j in points]
        self.img_name = lj.get('imagePath')
        self.is_pos = bool(self.cls)
        return self

img_path = r"F:\tmp\png/catDog.jpg"
json_path = r'F:\tmp\png\catDog.json'
image = imageio.imread(img_path)
json_info = LabelJson(json_path)

print(image.shape)

ia.imshow(image)

image_polys = np.copy(image)
for point in json_info.loc:
    meerkat = Polygon(point)
    image_polys = meerkat.draw_on_image(image_polys, alpha_face=0.2, size_points=7)

ia.imshow(image_polys)

显示的图片内容:

在这里插入图片描述

2、开始进行第一次数据增强,不改变形状,加入高斯噪声等等操作

#  let's convert our polygons to an PolygonsOnImage instance:
psoi = ia.PolygonsOnImage([Polygon(point) for point in json_info.loc],
                          shape=image.shape)


import imgaug.augmenters as iaa
ia.seed(1)

# add aug
aug = iaa.Sequential([
    iaa.AdditiveGaussianNoise(scale=10),
    iaa.CoarseDropout(0.1, size_px=8),
    iaa.AddToHueAndSaturation((-50, 50))
])

image_aug, psoi_aug = aug(image=image, polygons=psoi)
ia.imshow(psoi_aug.draw_on_image(image_aug, alpha_face=0.2, size_points=7))

下面就是增强后的结果:

在这里插入图片描述

3、接下来进行第二次的增强,这次加入形状和位置调整。

# add aug 2
aug = iaa.Sequential([
    iaa.Affine(translate_percent={"x": 0.2, "y": 0.1}),
    iaa.Fliplr(1.0)
])

image_aug, psoi_aug = aug(image=image, polygons=psoi)
ia.imshow(psoi_aug.draw_on_image(image_aug, alpha_face=0.2, size_points=7))

展示如下所示:

在这里插入图片描述

4、增强后的坐标,转化为labelme可以读取的json形式保存,再打开查看,这也是大多数我们需要做的目的。如下操作:

import base64, os
from PIL import Image
import io
import json
import cv2
def base64encode_img(src_image):
    # src_image = Image.open(image_path)
    src_image = Image.fromarray(cv2.cvtColor(src_image, cv2.COLOR_BGR2RGB))
    output_buffer = io.BytesIO()
    src_image.save(output_buffer, format='JPEG')
    byte_data = output_buffer.getvalue()
    base64_str = base64.b64encode(byte_data).decode('utf-8')
    return base64_str

def savejson(points_list, clses_list, img_tmp, filename, save_dir):
    A = dict()
    listbigoption = []
    for cls, points in zip(clses_list, points_list):
        listobject = dict()

        listobject['points'] = points
        listobject['line_color'] = 'null'
        listobject['label'] = cls

        listobject['fill_color'] = 'null'
        listbigoption.append(listobject)

    A['imageData'] = base64encode_img(img_tmp)
    A['imagePath'] = filename
    A['shapes'] = listbigoption
    A['flags'] = {}
    print(A)

    saveJson_path = os.path.join(save_dir, 'json')
    os.makedirs(saveJson_path, exist_ok=True)
    suffix = os.path.splitext(filename)[-1]
    with open(saveJson_path + "/" + filename.replace(suffix, ".json"), 'w', encoding='utf-8') as f:
        json.dump(A, f, indent=2, ensure_ascii=False)
        
image_aug, psoi_aug = aug(image=image, polygons=psoi)
print(psoi_aug)

points_list = []
for pos in psoi_aug:
    print('pos:', pos)
    points = [list(xy.astype(np.float64)) for xy in pos]
    print('points:', points)
    points_list.append(points)

image_augRGB = cv2.cvtColor(image_aug, cv2.COLOR_BGR2RGB)
savejson(points_list, json_info.cls, image_augRGB, os.path.basename(img_path), r'F:\tmp\png\aug')
# ia.imshow(psoi_aug.draw_on_image(image_aug, alpha_face=0.2, size_points=7))
ia.imshow(image_aug)
cv2.imwrite(os.path.join(r'F:\tmp\png\aug', os.path.basename(img_path)), image_augRGB)

直接保存的是BGR,需要转到RGB进行保存

在这里插入图片描述
增强后,存储到本地,用labelme再次打开查看,如下(暂未做小于0的截断处理):

在这里插入图片描述

加入截断操作,如下:

image_aug, psoi_aug = aug(image=image, polygons=psoi)
print(psoi_aug)
nw, nh, _ = image_aug.shape

points_list = []
for pos in psoi_aug:
    print('pos:', pos)
    points = [list(xy.astype(np.float64)) for xy in pos]
    print('points:', points)
    for p in points:
        if p[0]<0:
            p[0] = 0
        elif p[0]>nh:
            p[0] = nh
        if p[1]<0:
            p[1] = 0
        elif p[1]>nw:
            p[1] = nw
    points_list.append(points)

展示如下:

在这里插入图片描述

数据增强,随机的产生2*4个图像,用于展示:

ia.seed(2)
aug = iaa.Sequential([
    iaa.OneOf([
        iaa.AdditiveGaussianNoise(scale=10),
        iaa.GaussianBlur(sigma=(0.0, 3.0)),
        ]),
    iaa.Affine(rotate=(-20, 20), translate_percent=(-0.2, 0.2), scale=(0.8, 1.2),
               mode=["constant", "edge"], cval=0),  # 放射变换
    iaa.OneOf([
        iaa.Fliplr(0.5),    # 水平翻转
        iaa.Flipud(0.5),    # 上下翻转
        ]),
    iaa.OneOf([
        iaa.GammaContrast((0.5, 2.0)),
        iaa.LinearContrast((0.8, 1.2), per_channel=0.5),
        ]),

    iaa.AddToHueAndSaturation((-20, 20)),   # 通过随机值增加或减少色调和饱和度。
    iaa.Sometimes(0.75, iaa.Snowflakes())
])

images_polys_aug = []
for _ in range(2*4):
    image_aug, psoi_aug = aug(image=image, polygons=psoi)

    image_polys_aug = psoi_aug.draw_on_image(image_aug, alpha_face=0.2, size_points=11)
    images_polys_aug.append(ia.imresize_single_image(image_polys_aug, 0.5))

ia.imshow(ia.draw_grid(images_polys_aug, cols=2))

展示如下:
在这里插入图片描述

二、汇总

最后,做下汇总:

目标:根据采用labelme标注的pylygons标记信息,批量对图像和标注信息同时增强变换
步骤:

  1. 读取图像和json文件信息
  2. 增强操作
  3. 保存到本地
  4. 再次采用labelme,查看生成的结果,是否正常

代码如下:

import imageio
import imgaug as ia
import numpy as np
from imgaug.augmentables.polys import Polygon, PolygonsOnImage
import imgaug.augmenters as iaa

class LabelJson(object):
    def __init__(self, abs_path=None) -> None:
        super().__init__()
        self.abs_path = abs_path
        self.read()

    def read(self):
        with open(self.abs_path, 'r', encoding='utf-8') as f:
            lj = json.load(f)
        self.wh = [lj.get('imageWidth'), lj.get('imageHeight')]
        shapes = lj.get('shapes')
        self.cls = [i.get('label') for i in shapes]  # '1305' if i.get('label') == '14' else
        points = [i.get('points') for i in shapes]
        points = [np.array(i, dtype=np.int32).reshape((-1, 2)) for i in points]
        self.loc = points
        self.box = [[j[:, 0].min(), j[:, 1].min(), j[:, 0].max(), j[:, 1].max()] for j in points]
        self.img_name = lj.get('imagePath')
        self.is_pos = bool(self.cls)
        return self

import base64, os
from PIL import Image
import io
import json
import cv2
def base64encode_img(src_image):
    # src_image = Image.open(image_path)
    src_image = Image.fromarray(cv2.cvtColor(src_image, cv2.COLOR_BGR2RGB))
    output_buffer = io.BytesIO()
    src_image.save(output_buffer, format='JPEG')
    byte_data = output_buffer.getvalue()
    base64_str = base64.b64encode(byte_data).decode('utf-8')
    return base64_str

def savejson(points_list, clses_list, img_tmp, filename, save_dir):
    A = dict()
    listbigoption = []
    for cls, points in zip(clses_list, points_list):
        listobject = dict()

        listobject['points'] = points
        listobject['line_color'] = 'null'
        listobject['label'] = cls

        listobject['fill_color'] = 'null'
        listbigoption.append(listobject)

    A['imageData'] = base64encode_img(img_tmp)
    A['imagePath'] = filename
    A['shapes'] = listbigoption
    A['flags'] = {}

    suffix = os.path.splitext(filename)[-1]
    with open(save_dir + "/" + filename.replace(suffix, ".json"), 'w', encoding='utf-8') as f:
        json.dump(A, f, indent=2, ensure_ascii=False)


def saveJsonImg_main(image_aug, psoi_aug, cls_list, img_path, num, save_dir):
    nw, nh, _ = image_aug.shape

    points_list = []
    for pos in psoi_aug:
        points = [list(xy.astype(np.float64)) for xy in pos]
        for p in points:
            if p[0] < 0:
                p[0] = 0
            elif p[0] > nh:
                p[0] = nh
            if p[1] < 0:
                p[1] = 0
            elif p[1] > nw:
                p[1] = nw
        points_list.append(points)

    image_augRGB = cv2.cvtColor(image_aug, cv2.COLOR_BGR2RGB)
    savejson(points_list, cls_list, image_augRGB, str(num)+'_'+os.path.basename(img_path), save_dir)
    # ia.imshow(psoi_aug.draw_on_image(image_aug, alpha_face=0.2, size_points=7))
    cv2.imwrite(os.path.join(save_dir, str(num)+'_'+os.path.basename(img_path)), image_augRGB)


ia.seed(2)
aug = iaa.Sequential([
    iaa.OneOf([
        iaa.SaltAndPepper(0.01),
        iaa.AdditiveGaussianNoise(scale=5),
        iaa.GaussianBlur(sigma=(0.0, 3.0)),
        ]),
    iaa.OneOf([
        iaa.Affine(rotate=(-20, 20), translate_percent=(-0.2, 0.2), scale=(0.8, 1.2),
                   mode=["constant", "edge"], cval=0),  # 放射变换
        iaa.Affine(scale={"x": (0.5, 1.5), "y": (0.5, 1.5)}),
        iaa.Affine(translate_px={"x": (-20, 20), "y": (-20, 20)}),
        iaa.TranslateX(px=(-20, 20)),
        iaa.Rotate((-45, 45))
        ]),
    iaa.OneOf([
        iaa.Fliplr(0.7),    # 水平翻转
        iaa.Flipud(0.7),    # 上下翻转
        ]),
    iaa.OneOf([
        iaa.GammaContrast((0.5, 2.0)),
        iaa.LinearContrast((0.8, 1.2), per_channel=0.5),
        iaa.WithBrightnessChannels(iaa.Add((-50, 50))),     # Augmenter to apply child augmenters to brightness-related image channels.
        iaa.AddToHueAndSaturation((-20, 20)),   # 通过随机值增加或减少色调和饱和度。
        ]),

    iaa.Sometimes(0.75, iaa.Snowflakes())
])

def main():
    img_dir = r"./images"
    json_dir = r'./label'
    save_dir = r'./aug'

    for file in os.listdir(img_dir):
        img_path = os.path.join(img_dir, file)
        json_path = os.path.join(json_dir, file.replace('.jpg', '.json'))

        # read image and get json info
        image = imageio.imread(img_path)
        json_info = LabelJson(json_path)

        #  let's convert our polygons to an PolygonsOnImage instance:
        psoi = ia.PolygonsOnImage([Polygon(point) for point in json_info.loc],
                                  shape=image.shape)

        # one labelme image aug to 50 image
        for num in range(50):
            # aug
            image_aug, psoi_aug = aug(image=image, polygons=psoi)

            # save json and image
            saveJsonImg_main(image_aug, psoi_aug, json_info.cls, img_path, num, save_dir)


if __name__ == '__main__':
    main()

至此结束,感兴趣的可以赶紧去学习下。如果恰好对你也有帮助,点个赞👍,再走啦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/453793.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

这一篇搞定Spring

文章目录 一、引言1.1 原生web开发中存在哪些问题&#xff1f; 二、Spring框架2.1 概念2.2 访问与下载 三、Spring架构组成四、山寨版的Spring容器4.1准备工作4.2 山寨IOC容器4.3 配置文件告诉容器 管理哪些bean4.4 相关类4.5 测试 容器 五、构建Maven项目5.1 新建项目5.2 选择…

深度强化学习——AlphaGo实例讲解(5)

现在我们来分析AlphaGo这个实例&#xff0c;看看深度强化学习是怎么样用来玩围棋游戏的 AlphaGo的主要设计思路&#xff1a; 首先是训练&#xff0c;要分3步来做&#xff1a; 1、behavior cloning&#xff1a;这是一种模仿学习&#xff0c;alphaGo模仿人类玩家&#xff0c;从…

STM32平衡小车 pid简单学习

自动控制系统 自动控制系统可分为开环控制系统和闭环控制系统。 1、开环控制系统开环控制系统(open-loop control system)指被控对象的输出(被控制量)对控制器(controller)的输出没有影响。在这种控制系统中&#xff0c;不依赖将被控量反送回来以形成任何闭环回路。 2、闭环控…

c++入门(下)

C入门&#xff08;下&#xff09; 对于C的基础语法的讲解&#xff0c;由想要实现多次重复的函数&#xff0c;引出宏函数和inline的内联函数的对比&#xff0c;对于inline的讲解和运用&#xff0c;在后&#xff0c;C语言中的NULL和C中独特的nullptr的相比两者的比较&#xff0c…

kong(4):限流配置

Kong 提供了 Rate Limiting 插件&#xff0c;实现对请求的限流功能&#xff0c;避免过大的请求量过大&#xff0c;将后端服务打挂。 Rate Limiting 支持秒/分/小时/日/月/年多种时间维度的限流&#xff0c;并且可以组合使用。例如说&#xff1a;限制每秒最 多 100 次请求&…

Windows Server 2012R2 安装mysql 丢失VCRUNTIME140_1.dll------亲测

无去启动此程序,因为计算机中丢失VCRUNTIME140_1.dll。尝试重新安装该程序以解决此问题。 1.解决思路 说到底还是缺少底层的依赖&#xff0c;先下载依赖然后安装&#xff0c;最后安装vc。要不然vc是安装不成功。 下载安装--一下的插件 安装过程中需要重启一次电脑。 注意:必…

Android LoaderManager AsyncTaskLoader加载全部图片RecyclerView BigImageView呈现,Java(1)

Android LoaderManager AsyncTaskLoader加载全部图片RecyclerView BigImageView呈现&#xff0c;Java&#xff08;1&#xff09; 权限&#xff1a; <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:n…

VUE3子组件-业务代码优化

Vue3子组件 1.简介 Vue 3组件的主要优势之一就是它们可以帮助你将你的应用程序分解成可维护和可重用的部分。当你在应用程序中多次使用相同的代码时&#xff0c;你可以将它们抽象成一个组件&#xff0c;然后在应用程序中的多个地方使用该组件&#xff0c;而不必每次都编写相同…

5年了,终于入职阿里测试岗位,直接涨薪30K...

前言 本科毕业后就一直从事软件测试的工作&#xff0c;和多数人一样&#xff0c;最开始从事功能测试的工作&#xff0c;看着自己的同学一步一步往上走&#xff0c;自己还是在原地踏步&#xff0c;说实话这不是自己想要的状态。 一年半后开始沪漂生活&#xff0c;又摸爬滚打了…

阿里巴巴软件测试面试过了,起薪20k

普通二本计算机专业毕业&#xff0c;从毕业后&#xff0c;第一份接触测试的工作是在一家通讯小公司&#xff0c;大部分接触的工作是以功能测试为主&#xff0c;一直都是几千块钱工资&#xff0c;还一度被派出差&#xff0c;以及兼职各种产品、运维、运营的活&#xff0c;感觉自…

Cleer ARC II 音弧

戴上Cleer ARC II 音弧解放双耳&#xff0c;享受更自由的音符 用惯了各种入耳式耳机&#xff0c;换上开放式耳机&#xff0c;戴着确实更加舒服&#xff0c;特别是我现在用的这款Cleer ARC II 音弧&#xff0c;戴上还不容易掉&#xff0c;很适合运动使用。这款耳机采用一种耳挂佩…

JavaEE1(4/23)

目录 1.计算机CPU 2.CPU和GPU的区别 3.线程 4.内存是如何分配的 5.进程的调度 6.线程和进程的区别和联系&#xff1f; 1.计算机CPU 主频 &#xff1a;运算速度 3.73Ghz 表示每秒计算37.3亿次 基准速度&#xff1a;最小计算速度 睿频&#xff1a;最大运行速度 超频&…

【头歌C语言程序设计】结构体解答

写在前面 这道题总体来说还是偏难的&#xff0c;如果只看代码比较难以理解&#xff0c;当结构体的文章发出后&#xff0c;就有许多小伙伴问我这个问题&#xff0c;我开始意识到&#xff0c;可能我对这道题所作的解答还不够&#xff08;不装了&#x1f601;&#xff0c;根本没有…

Python进阶篇(三)-- TCP套接字与UDP套接字编程

1 Python3 网络编程 1.1 介绍 本文将首先利用 Python 实现面向TCP连接的套接字编程基础知识&#xff1a;如何创建套接字&#xff0c;将其绑定到特定的地址和端口&#xff0c;以及发送和接收数据包。其次还将学习 HTTP 协议格式的相关知识。在此基础上&#xff0c;本篇将用 Pyt…

Spring boot项目编译后未能加载静态资源文件

起因: 因甲方爸爸加了一个紧急的需求: 需要搞一个文件上传和下载功能. 我心中想:这不简单,搞个资源服务器,将上传文件放上去,然后访问资源链接就行了. 但接下来甲方爸爸说 不需要这莫麻烦,直接将文件放服务器里,用的时候下载到资源文件夹下就行. 我心里想: 我擦嘞 还能这样!! 然…

【C++】—— STL简介(了解)

前言&#xff1a; 在上节&#xff0c;我们简单的认识了模板的基本概念。今天我简单的给大家介绍一下关于 STL 。 目录 &#xff08;一&#xff09; 什么是STL &#xff08;二&#xff09; STL的版本 &#xff08;三&#xff09; STL的六大组件 &#xff08;四&#xff09;…

Tomcat概述以及部署与优化

一、Tomcat概述 1、Tomcat的概念 Tomcat是Java语言开发的&#xff0c;服务器是一个免费的开放源代码的Web应用服务器&#xff0c;属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发和调试JSP程序的首选。一般来说&am…

Python入门基础小练习

通过前面的两个篇章Python-入门基础篇和Python-入门基础语句篇大家应该已经认识了python基础的语句和函数了&#xff0c;并且可以使用pycharm编译器创建.py文件进行运行了&#xff0c;今天适当的来一些小练习&#xff0c;给枯燥的学习增添一些趣味性。 判断一个数是否为偶数 …

linux服务器实现百万并发遇到的问题以及解决思路

目录 前言服务器与客户端的配置介绍server 代码client 代码遇到的问题error too many open files为什么会出现这个问题解决这个问题的思路 killed&#xff08;已杀死&#xff09;为什么会出现这个问题解决这个问题的思路 最终结果学到的经验教训 前言 在完成百万并发服务器的时…

搭建家庭影音媒体中心 - 公网远程连接Jellyfin流媒体服务器

文章目录 前言1. 安装Home Assistant2. 配置Home Assistant3. 安装cpolar内网穿透3.1 windows系统3.2 Linux系统3.3 macOS系统 4. 映射Home Assistant端口5. 公网访问Home Assistant6. 固定公网地址6.1 保留一个固定二级子域名6.2 配置固定二级子域名 转载自远程穿透的文章&…