「图像 merge」无中生有制造数据
在进行一个新项目的时候,往往缺少一些真实数据,导致没办法进行模型训练,这时候就需要算法工程师自行制作一些数据了,比如这篇文章分享的 bag 目标检测,在检测区域没有真实的 bag数据
此时,就可以采用图像拼接的方式将凑集到的 bag图像粘贴到场景图像中【前提,目标图一般为“大头贴”】,当然场景图片并不是所有的位置都可以粘贴,一般有特定区域,比如 地面、墙壁、某设备等,因此还需要采用标注工具将这些目标区域标注出来,算法通过读取对应的目标区域,随机设定区域内的坐标点进行粘贴,将目标图粘贴到场景图当中
当然并不是任何形式的目标图都可以粘贴,为了更好的融合场景当中,还需要将目标从 大头贴当中给 扣出来,即除了目标区域,其他区域设置为透明格式,这样拼接的效果才“更”加真实一些【还是很假的!!!】
具体的操作过程如何所示,代码附最后,如有 bug 还望见谅!
1、制作底片模版
博主采用的 LabelImg标注工具,将底片待粘贴区域标注好
标注完成的 txt 内容
labelImg 的显示界面
2、将对应的大头贴目标头图处理
从 jpg 图像将目标 “扣” 出来,此处采用的像素抠图,将白色区域设置为透明,此处并不通用,不同目标的小伙伴自行修改代码,png的图像格式可以保存 alpha通道
# !/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2023.11
# @Author : 绿色羽毛
# @Email : lvseyumao@foxmail.com
# @Blog : https://blog.csdn.net/ViatorSun
# @Note : jpg2png.pyimport os
import cv2
import numpy as np
import os.path as ospfile_path = "/media/yinzhe/DataYZ/DataSet/DataSet/bag_masknew"
save_path = file_path + "_out"if not osp.exists(save_path):os.makedirs(save_path)img_lst = []
for path, dirs, files in os.walk(file_path):for file in files:if os.path.splitext(file)[1] in ['.jpg', ".png", ".JPG", ".jpeg"]: # 扫描指定格式文件img_dir = osp.join(path, file)img_save = osp.join(save_path, file)img = cv2.imread(img_dir)img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转换为RGB格式png_img = osp.join(save_path, file.split(".")[0] + ".png")white_mask = cv2.inRange(img, (200, 200, 200), (255, 255, 255)) # 提取白色部分img = cv2.cvtColor(img, cv2.COLOR_RGB2BGRA)img[:,:,3][white_mask == 255] = 0 # 将白色部分变成透明cv2.imwrite(png_img, img)
3、将底片与透明目标进行叠加融合
叠加融合的方法有很多种,此处只采用了最简单的叠加方式,也可以考虑 cv2.seamlessClone
最终成果如下图所示
除了生成合成图片,标注信息也同步生成
注意! 此处的标注信息是按照标注框尺寸保存的【此处隐藏bug后续优化】
提示:可以根据目标区域的非透明区域进行保存
# !/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2023.10
# @Author : 绿色羽毛
# @Email : lvseyumao@foxmail.com
# @Blog : https://blog.csdn.net/ViatorSun
# @Note : ps_merge_img.pyimport os
import cv2
import random
from random import sample
import numpy as np
import argparse def read_label_txt(label_dir):labels = []with open(label_dir) as fp:for f in fp.readlines():labels.append(f.strip().split(' '))return labelsdef rescale_yolo_labels(labels, img_shape):height, width, nchannel = img_shaperescale_boxes = []for box in list(labels):x_c = float(box[1]) * widthy_c = float(box[2]) * heightw = float(box[3]) * widthh = float(box[4]) * heightx_left = x_c - w * .5y_left = y_c - h * .5x_right = x_c + w * .5y_right = y_c + h * .5rescale_boxes.append([box[0], int(x_left), int(y_left), int(x_right), int(y_right)])return rescale_boxesdef xyxy2xywh(image, bboxes):height, width, _ = image.shapeboxes = []for box in bboxes:if len(box) < 4:continuecls = int(box[0])x_min = box[1]y_min = box[2]x_max = box[3]y_max = box[4]w = x_max - x_minh = y_max - y_minx_c = (x_min + x_max) / 2.0y_c = (y_min + y_max) / 2.0x_c = x_c / widthy_c = y_c / heightw = float(w) / widthh = float(h) / heightboxes.append([cls, x_c, y_c, w, h])return boxesdef cast_color(img, value):img_t = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)h,s,v = cv2.split(img_t)# 增加图像对比度v2 = np.clip(cv2.add(2*v,value),0,255)img2 = np.uint8(cv2.merge((h,s,v2)))img_cast = cv2.cvtColor(img2,cv2.COLOR_HSV2BGR) # 改变图像对比度return img_castdef brightness(img, value):img_t = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)h,s,v = cv2.split(img_t)# 增加图像亮度v1 = np.clip(cv2.add(1*v,value),0,255)img1 = np.uint8(cv2.merge((h,s,v1)))img_brightness = cv2.cvtColor(img1,cv2.COLOR_HSV2BGR) # 改变图像亮度亮度return img_brightnessdef add_alpha_channel(img):""" 为jpg图像添加alpha通道 """b_channel, g_channel, r_channel = cv2.split(img) # 拆分jpg图像通道alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # 创建Alpha通道img_new = cv2.merge((b_channel, g_channel, r_channel, alpha_channel)) # 融合通道return img_newdef merge_img(jpg_img, png_img, y1, y2, x1, x2):""" 将png透明图像与jpg图像叠加y1,y2,x1,x2为叠加位置坐标值"""# 判断jpg图像是否已经为4通道if jpg_img.shape[2] == 3:jpg_img = add_alpha_channel(jpg_img)'''当叠加图像时,可能因为叠加位置设置不当,导致png图像的边界超过背景jpg图像,而程序报错这里设定一系列叠加位置的限制,可以满足png图像超出jpg图像范围时,依然可以正常叠加'''yy1 = 0yy2 = png_img.shape[0]xx1 = 0xx2 = png_img.shape[1]if x1 < 0:xx1 = -x1x1 = 0if y1 < 0:yy1 = - y1y1 = 0if x2 > jpg_img.shape[1]:xx2 = png_img.shape[1] - (x2 - jpg_img.shape[1])x2 = jpg_img.shape[1]if y2 > jpg_img.shape[0]:yy2 = png_img.shape[0] - (y2 - jpg_img.shape[0])y2 = jpg_img.shape[0]# 获取要覆盖图像的alpha值,将像素值除以255,使值保持在0-1之间alpha_png = png_img[yy1:yy2, xx1:xx2, 3] / 255.0alpha_jpg = 1 - alpha_png# 开始叠加for c in range(0, 3):jpg_img[y1:y2, x1:x2, c] = ((alpha_jpg * jpg_img[y1:y2, x1:x2, c]) + (alpha_png * png_img[yy1:yy2, xx1:xx2, c]))return jpg_imgdef random_add_patches_on_objects(image, mask_lst, rescale_boxes, paste_number):img = image.copy()new_bboxes = []cl = 0random.shuffle(rescale_boxes)for i, rescale_bbox in enumerate(rescale_boxes[:int(len(mask_lst))]): # 待ps图像 目标框中p_img = mask_lst[i]bbox_h, bbox_w, bbox_c = p_img.shapeobj_xmin, obj_ymin, obj_xmax, obj_ymax = rescale_bbox[1:]obj_w = obj_xmax - obj_xmin + 1 # 目标框尺寸obj_h = obj_ymax - obj_ymin + 1while not (bbox_w < obj_w and bbox_h < obj_h): # 如果目标框小于 mask尺寸,对mask进行缩放以确保可以放进 bbox中new_bbox_w = int(bbox_w * random.uniform(0.5, 0.8))new_bbox_h = int(bbox_h * random.uniform(0.5, 0.8))bbox_w, bbox_h = new_bbox_w, new_bbox_hsuccess_num = 0while success_num < paste_number:center_search_space = [obj_xmin, obj_ymin, obj_xmax - new_bbox_w - 1, obj_ymax - new_bbox_h - 1] # 选取生成随机点区域if center_search_space[0] >= center_search_space[2] or center_search_space[1] >= center_search_space[3]:print('============== center_search_space error!!!! ================')success_num += 1continuenew_bbox_x_min = random.randint(center_search_space[0], center_search_space[2]) # 随机生成点坐标new_bbox_y_min = random.randint(center_search_space[1], center_search_space[3])new_bbox_x_left, new_bbox_y_top, new_bbox_x_right, new_bbox_y_bottom = new_bbox_x_min, new_bbox_y_min, new_bbox_x_min + new_bbox_w - 1, new_bbox_y_min + new_bbox_h - 1new_bbox = [cl, int(new_bbox_x_left), int(new_bbox_y_top), int(new_bbox_x_right), int(new_bbox_y_bottom)]success_num += 1new_bboxes.append(new_bbox)p_img = cv2.resize(p_img, (new_bbox_w, new_bbox_h))img = merge_img(img, p_img, new_bbox_y_top, new_bbox_y_bottom+1, new_bbox_x_left, new_bbox_x_right+1)return img, new_bboxesif __name__ == "__main__":# 用来装载参数的容器parser = argparse.ArgumentParser(description='PS')# 给这个解析对象添加命令行参数parser.add_argument('-i', '--images', default= '/media/yinzhe/DataYZ/DataSet/DataSet/bag_model',type=str, help='path of images')parser.add_argument('-t', '--mask', default= '/media/yinzhe/DataYZ/DataSet/DataSet/bag_mask',type=str, help='path of masks')parser.add_argument('-s', '--saveImage',default= '/media/yinzhe/DataYZ/DataSet/DataSet/bag_save', type=str, help='path of ')parser.add_argument('-c', '--scale', default= 0.2, type=float, help='number of img')parser.add_argument('-n', '--num', default= 5, type=int, help='number of img')args = parser.parse_args() # 获取所有参数mask_filedirs = args.maskimages_path = args.imagessave_path = args.saveImagescale, num = args.scale, args.nummask_paths = []if not os.path.exists(save_path):os.makedirs(save_path)# 读取所有的 mask 模版mask_lst = []for t_path in os.listdir(mask_filedirs):mask = cv2.imread(os.path.join(mask_filedirs, t_path), cv2.IMREAD_UNCHANGED)if (mask.shape[2] != 4): # RGB alphabreakmask_lst.append(mask)# template_paths = random.shuffle(template_paths) #打乱顺序for image_path in os.listdir(images_path) :if "txt" in image_path:continueimage = cv2.imread(os.path.join(images_path, image_path))pre_name = image_path.split('.')[0]bbox_lst = read_label_txt(os.path.join(images_path, pre_name + ".txt"))if image is None or len(bbox_lst) == 0:print("empty image !!! or empty label !!!")continue# yolo txt转化为x1y1x2y2rescale_bboxes = rescale_yolo_labels(bbox_lst, image.shape) # 转换坐标表示# maskes_path = sample(mask_paths, int(len(bbox_lst) * scale))#for i in range(num):maskes = sample(mask_lst, int(len(bbox_lst) * scale))img, bboxes = random_add_patches_on_objects(image, maskes, rescale_bboxes, 1)boxes = xyxy2xywh(img, bboxes)img_name = pre_name + '_' + str(i) + '.jpg'print('handle img:', img_name)cv2.imwrite(os.path.join(save_path, img_name), img)with open(os.path.join(save_path, img_name[:-4] + ".txt"), 'a') as f:for box in boxes:mess = str(3) + " " + str(box[1]) + " " + str(box[2]) + " " + str(box[3] * 0.6) + " " + str(box[4]* 0.6) + "\n"f.write(mess)
相关文章:

「图像 merge」无中生有制造数据
在进行一个新项目的时候,往往缺少一些真实数据,导致没办法进行模型训练,这时候就需要算法工程师自行制作一些数据了,比如这篇文章分享的 bag 目标检测,在检测区域没有真实的 bag数据 此时,就可以采用图像拼…...
RK3588之ArmSoM-W3 + MPP实现多路硬解码拉流
简介 学习完MPP的解码Demo之后,想必大家都想通过一个项目来进行RK3588-MPP的解码实战。本篇文章就基于ArmSoM-W3开发板,开发一个多路硬解码项目,实现四路MPP硬解码拉流显示实现的效果如下: RK3588四路MPP硬解码拉流 环境介绍 硬件…...
【Rust日报】2023-10-29 隆重推出 Rerun 0.10!
Lapce代码编辑器发布v0.3.0 Lapce代码编辑器新发布v0.3.0! https://lapce.dev/ 距离我们上次发布已经过去很长一段时间了。我们正忙着在自己的 UI 工具包Floem中重写 Lapce ,这将使我们以后对 UI 部分代码的开发变得更容易、更快。 另一件值得注意的事情…...
AI智能识别如何助力PDF,轻松实现文档处理?
AI智能识别如何助力PDF,轻松实现文档处理? 随着科技的不断发展,人工智能(AI)在各个领域都发挥着重要的作用。其中,文档智能( Document AI )在金融、医疗、教育、保险、能源、物流等…...
【SA8295P 源码分析】114 - 将Android GVM userdata文件系统从 EXT4 修改为 F2FS
【SA8295P 源码分析】114 - 将Android GVM userdata文件系统从 EXT4 修改为 F2FS 一、代码修改方法1. BoardConfig.mk2. 修改 fstab二、开机进入 adb 验证2.1 验证 userdata 修改 f2fs 文件系统格式成功2.2 测试 f2fs 文件系统性能:androbench.apk系列文章汇总见:《【SA8295P…...
LeetCode 387 字符串中的第一个唯一字符 简单
题目 - 点击直达 1. 387 字符串中的第一个唯一字符1. 题目详情1. 原题链接2. 题目要求3. 基础框架 2. 解题思路1. 思路分析2. 时间复杂度3. 代码实现 1. 387 字符串中的第一个唯一字符 1. 题目详情 给定一个字符串 s ,找到 它的第一个不重复的字符,并返…...

线程池--简单版本和复杂版本
目录 一、引言 二、线程池头文件介绍 三、简单版本线程池 1.创建线程池 2.添加任务到线程池 3.子线程执行回调函数 4.摧毁线程池 5.简单版线程池流程分析 四、复杂版本线程池 1.结构体介绍 2.主线程 3.子线程 4.管理线程 一、引言 多线程版服务器一个客户端就需要…...

docker进阶
文章目录 docker 进阶Part1 常用命令总结docker version 查看docker客户端和服务端信息docker info 查看更加详细信息docker images 列出所有镜像基本用法常用选项 docker search 搜索镜像基本用法示例用法 docker pull 拉取镜像基本用法示例用法 docker rmi 删除镜像基本用法示…...

Unity HoloLens 2 应用程序发布
设置3D 启动器画面,glb格式的模型 VS中可以直接生成所有大小的图标...

3D RPG Course | Core 学习日记三:Navigation智能导航地图烘焙
前言 前面我们已经绘制好了一个简单的地图场景,现在我们需要使用Navigation给地图做智能导航,以实现AI自动寻路,以及设置地图的可行走区域以及不可行走区域,Navigation的基础知识、原理、用法在Unity的官方文档,以及网…...
Linux 启用本地ISO作为软件源
环境:sle12sp5 (open SUSE) 1、禁用现有的源 查看源:sle12sp5 zypper lr -u ➜ sle12sp5 zypper lr -u Repository priorities are without effect. All enabled repositories share the same prior…...

SpringCloud-Alibaba-Nacos2.0.4
SpringCloud-Alibaba-Nacos2.0.4 SpringCloud Alibaba版本选择(截止到2023年3月12日) Spring Cloud Alibaba VersionSpring Cloud VersionSpring Boot Version2021.0.4.0*Spring Cloud 2021.0.42.6.11 SpringCloud Alibaba-2021.0.4.0组件版本关系 S…...
docker运行镜像相关配置文件
Dockerfile 文件配置 FROM anapsix/alpine-java:8_server-jre_unlimitedMAINTAINER Lion LiRUN mkdir -p /data/sydatasource/logs \/data/sydatasource/temp \/data/skywalking/agentWORKDIR /data/sydatasourceENV SERVER_PORT8220EXPOSE ${SERVER_PORT}ENV TZAsia/Shanghai …...
引擎系统设计思路 - 用户态与系统态隔离
用户态与系统态隔离: a. 外部用户侧的对象或者逻辑,在外部创建使用。内部系统侧的对象或者逻辑,在内部创建使用。 b. 用户状态下对内部系统的操作要立即响应,但是具体如何实际执行系统内部的机制,则是异步并行的。因为…...

致远OA wpsAssistServlet任意文件读取漏洞复现 [附POC]
文章目录 致远OA wpsAssistServlet任意文件读取漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 致远OA wpsAssistServlet任意文件读取漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用…...

轻量应用服务器有什么优势?如何评价亚马逊云科技轻量应用服务器?
什么是轻量应用服务器? 随着如今各行各业对云计算的需求越来越多,云服务器也被越来越多的企业所广泛采用。其中,轻量应用服务器是一种简单、高效、可靠的云计算服务,能够为开发人员、企业和个人提供轻量级的虚拟专用服务器&#…...
python的日志模块学习记录
logging模块是Python的内置日志模块满足日常需要 使用方法 *** 1.导入*** import logging from logging import config*** 2.配置日志配置项(基本配置一般不能满足需要,一般使用字典配置如下)*** # 日志基本配置方法,一般不能满足需要 logging.basic…...
【java】redisTemplate mock时报空指针
原方法: Boolean locked redisTemplate.opsForValue().setIfAbsent(redisKey, "", 400, TimeUnit.SECONDS);mock方法 mock方法: 需要每个函数都mock。 Mock RedisTemplate redisTemplate;... ValueOperations<String, String> value…...

Hadoop PseudoDistributed Mode 伪分布式
Hadoop PseudoDistributed Mode 伪分布式加粗样式 hadoop101hadoop102hadoop103192.168.171.101192.168.171.102192.168.171.103namenodesecondary namenoderecource managerdatanodedatanodedatanodenodemanagernodemanagernodemanagerjob historyjob logjob logjob log 1. …...
个人职业规划
职业规划 软件体系结构 内容 组件 关系 视图 技术 抽象 封装 信息隐藏 模块化 事务分离 耦合和内聚 充分性、完整性和原始性 策略和实现的分离 接口和实现的分离 单一引用点 分而治之 结构 层 管道和过滤器 黑板 系统 分布式系统 代理者 交互式系统 …...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...