【數據增強】精細化貼圖數據增強

1.任務背景

假設我有100個蘋果的照片,我需要把這些照片粘貼到傳送帶照片上,模擬“傳送帶蘋果檢測”場景。
這種貼圖的方式更加合理一些,因為yolo之類的mosaic貼圖,會把圖像弄的非常支離破碎。
現在我需要隨機選擇幾張蘋果圖像,每張蘋果圖像至少使用x次,并且保證蘋果(新蘋果之間、新舊標注信息之間)不重疊,且蘋果大小范圍可以自由指定
效果圖如下(人工核查,xml也是正確的,我粘貼的是電力部件)。在真實使用中,如果需要確保信粘貼內容與已有標簽不重復,請在在這里插入圖片描述
):

2.具體邏輯

2.1 項目描述

這是一個用于計算機視覺任務(如目標檢測)的智能數據增強腳本。它通過將小物體圖像(Patches)以復雜且真實的方式粘貼到大型背景圖像上,來批量生成高質量的訓練數據集。腳本的核心是“場景合成”,旨在創建包含多個、尺寸合理且互不重疊物體的復雜圖像,從而有效提升模型的魯棒性和泛化能力。

2.2 整體流程

腳本的運行流程遵循一個清晰的、基于統計學控制的“事件驅動”模型:

  1. 計算任務總量: 首先,根據用戶設定的參數(小圖總數、期望重復次數、每背景粘貼數),腳本會計算出需要生成的增強圖片總數。
  2. 循環生成: 程序會循環執行所計算出的總次數。在每一次循環中,它會獨立地完成一次“場景合成”操作。
  3. 場景合成:
    • 選取素材: 隨機選擇一張背景圖和指定數量的隨機小圖。
    • 智能調整與放置: 對每一個選中的小圖,依次進行:
      • 動態縮放: 根據相對于背景圖的“最大/最小面積百分比”要求,自動縮放小圖,確保尺寸合理。
      • 碰撞檢測: 為小圖尋找一個隨機的、且不與任何已放置小圖重疊的位置。
      • 數據增強: 對小圖進行隨機的水平或垂直翻轉。
      • 粘貼與記錄: 將處理后的小圖粘貼到背景圖上,并同步更新XML標注信息。
    • 保存輸出: 將最終合成的圖片和包含所有新物體標注的XML文件,以唯一編號保存到輸出文件夾。

2.3主要功能

  • 場景化組合: 能在單一背景上粘貼多個隨機物體,模擬復雜的真實世界場景。
  • 動態尺寸調整: 摒棄了固定的像素限制,采用相對于背景的面積百分比來約束貼圖大小,使其能智能適應任意尺寸的背景圖。
  • 防重疊粘貼: 核心亮點功能。通過碰撞檢測算法確保粘貼的物體之間(包括原有的標注信息)互不重疊,顯著提升了生成數據的質量和真實感。
  • 可控的隨機性: 用戶可以通過參數精確控制最終生成數據集的總量,并使每個物體的平均使用次數在統計上趨于穩定。
  • 自動化標注: 在生成圖像的同時,會自動創建和更新對應的PASCAL VOC格式的XML標注文件,省去手動標注的繁瑣工作。

2.4 參數說明

  • FOLDER_A, FOLDER_B, OUTPUT...: 用于定義素材和輸出結果的路徑。
  • OBJECT_NAME: 指定粘貼的物體在XML文件中被稱作什么類別名。
  • NUM_PATCHES_PER_BG: **(核心)**設定每張生成的圖片上要粘貼多少個小圖/物體。
  • REPEATS_PER_PATCH: **(核心)**設定數據集中每一種小圖期望被重復使用的平均次數,用于計算總生成量。
  • MAX_AREA_PERCENTAGE: 定義貼圖相對于背景的最大允許面積(例如 0.5 代表50%)。
  • MIN_AREA_PERCENTAGE: 定義貼圖相對于背景的最小允許面積(例如 0.05 代表5%),小于此值會被自動放大。
  • MAX_PLACEMENT_TRIES: 在為小圖尋找不重疊位置時的最大嘗試次數,這是一個防止在擁擠場景下無限循環的安全設置。

3.代碼實現

import os
import random
import xml.etree.ElementTree as ET
from PIL import Image
from tqdm import tqdm
import copy
import math
import cv2# --- 配置區 ---# 輸入文件夾
FOLDER_A = r'E:\data\baidu_pic\aaa'  # 存放小圖像的文件夾
FOLDER_B = r'E:\data\baidu_pic\background'  # 存放帶XML的大圖像的文件夾# 輸出文件夾 (如果不存在,腳本會自動創建)
OUTPUT_IMAGES_FOLDER = r'E:\data\baidu_pic\hecheng\iamges'
OUTPUT_ANNOTATIONS_FOLDER = r'E:\data\baidu_pic\hecheng\xlms'# 要在XML中添加的Object名稱
OBJECT_NAME = 'rdg'# --- 關鍵參數 ---
# 1. 為每張大圖粘貼多少個小圖
NUM_PATCHES_PER_BG = 3# 2. 數據集中每張小圖期望重復使用的次數
# 這將決定“小圖池”的大小
REPEATS_PER_PATCH = 2# 3.新增:相對面積限制 
# 使用基于背景圖面積的百分比來控制貼圖的最終尺寸
MAX_AREA_PERCENTAGE = 0.01  # 貼圖面積不得超過背景的1%
MIN_AREA_PERCENTAGE = 0.005 # 貼圖面積不得小于背景的0.5%# 4.支持的圖像文件擴展名
SUPPORTED_IMAGE_FORMATS = ['.jpg', '.jpeg', '.png', '.bmp']# 5.為防止因空間不足而無限循環,設定為每個貼圖尋找不重疊位置的最大嘗試次數
MAX_PLACEMENT_TRIES = 100# --- 輔助函數 ---def is_overlapping(box1, box2):"""檢查兩個邊界框是否重疊。 box = (xmin, ymin, xmax, ymax)"""if box1[2] < box2[0] or box2[2] < box1[0]:return Falseif box1[3] < box2[1] or box2[3] < box1[1]:return Falsereturn Truedef get_b_image_basenames(folder_path):filenames = []for f in os.listdir(folder_path):basename, ext = os.path.splitext(f)if ext.lower() in SUPPORTED_IMAGE_FORMATS and os.path.exists(os.path.join(folder_path, basename + '.xml')):filenames.append(basename)return list(set(filenames))def update_xml_annotation(xml_root, object_name, xmin, ymin, xmax, ymax):obj = ET.SubElement(xml_root, 'object')ET.SubElement(obj, 'name').text = object_nameET.SubElement(obj, 'pose').text = 'Unspecified'ET.SubElement(obj, 'truncated').text = '0'ET.SubElement(obj, 'difficult').text = '0'bndbox = ET.SubElement(obj, 'bndbox')ET.SubElement(bndbox, 'xmin').text = str(int(xmin))ET.SubElement(bndbox, 'ymin').text = str(int(ymin))ET.SubElement(bndbox, 'xmax').text = str(int(xmax))ET.SubElement(bndbox, 'ymax').text = str(int(ymax))def find_image_ext(folder, basename):for ext in SUPPORTED_IMAGE_FORMATS:if os.path.exists(os.path.join(folder, basename + ext)):return extreturn None# --- 主邏輯區 ---def main():print("--- 開始執行數據增強任務 (帶完全防重疊邏輯) ---")os.makedirs(OUTPUT_IMAGES_FOLDER, exist_ok=True)os.makedirs(OUTPUT_ANNOTATIONS_FOLDER, exist_ok=True)all_small_images = [f for f in os.listdir(FOLDER_A) if os.path.splitext(f)[1].lower() in SUPPORTED_IMAGE_FORMATS]if not all_small_images:print(f"錯誤: 文件夾 '{FOLDER_A}' 中沒有找到任何圖像文件。")returnbackground_basenames = get_b_image_basenames(FOLDER_B)if not background_basenames:print(f"錯誤: 文件夾 '{FOLDER_B}' 中沒有找到任何帶有XML配對的圖像文件。")returnnum_total_patches = len(all_small_images)if NUM_PATCHES_PER_BG <= 0:print("錯誤: NUM_PATCHES_PER_BG 必須大于0。")returntotal_operations = int((num_total_patches * REPEATS_PER_PATCH) / NUM_PATCHES_PER_BG)print(f"將生成 {total_operations} 張增強圖片。")for i in tqdm(range(total_operations), desc="生成增強圖片中"):try:bg_basename = random.choice(background_basenames)bg_ext = find_image_ext(FOLDER_B, bg_basename)if not bg_ext: continuebg_image_path = os.path.join(FOLDER_B, bg_basename + bg_ext)xml_path = os.path.join(FOLDER_B, bg_basename + '.xml')background_image_pil = Image.open(bg_image_path).convert("RGBA")tree = ET.parse(xml_path)xml_root = tree.getroot()bg_width, bg_height = background_image_pil.sizebackground_area = bg_width * bg_height# --- 核心改動:預加載原始XML中的所有物體邊界框 ---placed_boxes = []for obj in xml_root.findall('object'):try:bndbox = obj.find('bndbox')# 將XML中的坐標文本轉換為整數xmin = int(float(bndbox.find('xmin').text))ymin = int(float(bndbox.find('ymin').text))xmax = int(float(bndbox.find('xmax').text))ymax = int(float(bndbox.find('ymax').text))placed_boxes.append((xmin, ymin, xmax, ymax))except (AttributeError, ValueError) as e:print(f"\n警告: 解析背景'{bg_basename}'的XML時,有對象格式不正確,已跳過。錯誤: {e}")continue# ----------------------------------------------------patches_to_paste = random.choices(all_small_images, k=NUM_PATCHES_PER_BG)for small_img_filename in patches_to_paste:small_image_path = os.path.join(FOLDER_A, small_img_filename)patch_cv_image = cv2.imread(small_image_path, cv2.IMREAD_UNCHANGED)if patch_cv_image is None: continueh, w = patch_cv_image.shape[:2]patch_area = w * hmax_allowed_area = background_area * MAX_AREA_PERCENTAGEif patch_area > max_allowed_area:scale_factor = math.sqrt(max_allowed_area / patch_area)new_w, new_h = int(w * scale_factor), int(h * scale_factor)patch_cv_image = cv2.resize(patch_cv_image, (new_w, new_h), interpolation=cv2.INTER_AREA)h, w, patch_area = new_h, new_w, new_w * new_hmin_required_area = background_area * MIN_AREA_PERCENTAGEif patch_area < min_required_area:scale_factor = math.sqrt(min_required_area / patch_area)new_w, new_h = int(w * scale_factor), int(h * scale_factor)if new_w >= bg_width or new_h >= bg_height: continuepatch_cv_image = cv2.resize(patch_cv_image, (new_w, new_h), interpolation=cv2.INTER_CUBIC)if len(patch_cv_image.shape) == 3 and patch_cv_image.shape[2] == 4:patch_cv_image = cv2.cvtColor(patch_cv_image, cv2.COLOR_BGRA2RGBA)else:patch_cv_image = cv2.cvtColor(patch_cv_image, cv2.COLOR_BGR2RGB)patch_image = Image.fromarray(patch_cv_image)if random.choice([True, False]): patch_image = patch_image.transpose(Image.FLIP_LEFT_RIGHT)if random.choice([True, False]): patch_image = patch_image.transpose(Image.FLIP_TOP_BOTTOM)patch_width, patch_height = patch_image.sizefor _ in range(MAX_PLACEMENT_TRIES):paste_x = random.randint(0, bg_width - patch_width)paste_y = random.randint(0, bg_height - patch_height)candidate_box = (paste_x, paste_y, paste_x + patch_width, paste_y + patch_height)is_valid_placement = Truefor existing_box in placed_boxes:if is_overlapping(candidate_box, existing_box):is_valid_placement = Falsebreakif is_valid_placement:background_image_pil.paste(patch_image, (paste_x, paste_y), patch_image)update_xml_annotation(xml_root, OBJECT_NAME, paste_x, paste_y, candidate_box[2], candidate_box[3])placed_boxes.append(candidate_box)breakelse:print(f"\n警告: 在嘗試 {MAX_PLACEMENT_TRIES} 次后,未能為小圖 '{small_img_filename}' 找到不重疊的位置。跳過此小圖。")new_basename = f"augmented_output_{i+1}"output_image_path = os.path.join(OUTPUT_IMAGES_FOLDER, new_basename + bg_ext)output_xml_path = os.path.join(OUTPUT_ANNOTATIONS_FOLDER, new_basename + ".xml")background_image_pil.convert("RGB").save(output_image_path)tree.write(output_xml_path, encoding='utf-8')except Exception as e:print(f"\n在生成第 {i+1} 張圖片時發生未知錯誤: {e}")continueprint(f"\n--- 所有任務已完成!---")if __name__ == '__main__':main()

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/87509.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/87509.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/87509.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HTML響應式Web設計

什么是響應式Web設計&#xff1f; RWD指的是響應式Web設計&#xff08;Responsive Web Design)RWD能夠以可變尺寸傳遞網頁RWD對于平板和移動設備是必需的 創建一個響應式設計&#xff1a; <!DOCTYPE html> <html lang"en-US"> <head> <styl…

【讀代碼】百度開源大模型:ERNIE項目解析

一、項目基本介紹 1.1 項目概述 ERNIE(Enhanced Representation through kNowledge IntEgration)是百度基于PaddlePaddle深度學習框架開發的多模態預訓練模型體系。最新發布的ERNIE 4.5系列包含10個不同變體,涵蓋從300B參數的巨型MoE模型到0.3B的輕量級模型,形成完整的多…

2025年6月:技術探索與生活平衡的協奏曲

> 當代碼與晨跑軌跡在初夏的陽光下交織,我找到了程序員生活的黃金分割點 --- ### 一、技術突破:AI驅動的智能工作流優化系統 這個月我成功部署了第三代自動化工作流系統,核心創新在于**動態決策樹+實時反饋機制**。系統可自主優化處理路徑,錯誤率下降62%! ```pyth…

如何查看服務器運行了哪些服務?

&#x1f7e2; 一、Linux服務器Linux下&#xff0c;常用以下幾種方法&#xff1a;? 1. 查看所有正在監聽端口的服務netstat -tulnp 含義&#xff1a;-t TCP-u UDP-l 監聽狀態-n 顯示端口號-p 顯示進程號和程序名示例輸出&#xff1a;pgsql復制編輯Proto Recv-Q Send-Q Local A…

【Linux基礎知識系列】第三十八篇 - 打印系統與 PDF 工具

在Linux系統中&#xff0c;打印和PDF處理是日常辦公和文檔管理中不可或缺的功能。CUPS&#xff08;Common Unix Printing System&#xff09;是Linux中常用的打印服務&#xff0c;它提供了打印任務的管理和打印設備的配置功能。同時&#xff0c;Linux也提供了多種PDF處理工具&a…

STM32CUBEMX 使用教程6 — TIM 定時器配置、定時中斷

往期文章推薦&#xff1a; STM32CUBEMX 使用教程5 — DMA配置 & 串口結合DMA實現數據搬運 STM32CUBEMX 使用教程4 — 串口 (USART) 配置、重定向 printf 輸出 STM32CUBEMX 使用教程3 — 外部中斷&#xff08;EXTI&#xff09;的使用 STM32CUBEMX 使用教程2 — GPIO的使…

微信小程序實現table表格

微信小程序沒有table標簽&#xff0c;運用display:table和display:flex實現一個內容字數不固定表格…… wxml&#xff1a; <view class"ContentShow"> <view class"conht">煙臺市新聞發布會登記審批表</view> <view class"tabl…

MySQL 基本面試題

目錄 一、SQL的基本操作 1、SQL查詢的執行順序 2、count(*)、count(1) 、count(列名) 的區別 3、char 和 varchar 的區別 4、MySQL 中常用的基礎函數 5、MySQL的執行流程 6、MyISAM和InnoDB的區別 二、事務 1、事務的基本概念 2、事務的四大特性&#xff08;ACID) 3…

WPF學習筆記(12)下拉框控件ComboBox與數據模板

下拉框控件ComboBox與數據模板 一、ComboBox1. ComboBox概述2. ItemsControl類3. Selector類4. ComboBox類 二、ComboBox數據模板總結 一、ComboBox 1. ComboBox概述 ComboBox類代表一個有下拉列表的選擇控件&#xff0c;供用戶選擇。 官方文檔&#xff1a;https://learn.mic…

Docker for Windows 設置國內鏡像源教程

在使用 Docker 時&#xff0c;由于默認的 Docker Hub 鏡像源位于國外&#xff0c;國內用戶在拉取鏡像時可能會遇到速度慢或連接不穩定的問題。為了加速鏡像拉取&#xff0c;可以將 Docker 配置為使用國內鏡像源。以下是適用于 Windows 系統的詳細配置方法&#xff1a; 方法一&…

一鍵部署AI工具!用AIStarter快速安裝ComfyUI與Stable Diffusion

AIStarter部署AI工具&#xff0c;讓AI開發更簡單&#xff01;無需研究復雜環境配置&#xff0c;AIStarter平臺提供一鍵安裝ComfyUI和Stable Diffusion&#xff0c;支持多版本選擇&#xff0c;快速上手。以下是詳細步驟&#xff1a; 一、訪問AIStarter市場 下載AIStarter&#x…

Python基礎(吃洋蔥小游戲)

下面我將為你設計一個"吃洋蔥小游戲"的Python實現方案&#xff0c;使用Pygame庫開發。這個游戲模擬吃洋蔥的過程&#xff0c;玩家需要收集不同種類的洋蔥以獲得高分&#xff0c;同時避免吃到辣椒。 &#x1f9c5; 吃洋蔥小游戲 - Python實現方案 &#x1f3ae; 1. …

Objective-C 路由表原理詳解

在 Objective-C 中實現路由表是組件化架構的核心&#xff0c;它通過 URL 映射機制實現模塊間解耦通信。以下是完整實現原理&#xff1a; 一、核心架構設計 #mermaid-svg-5jMinPiZe8mivAbi {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fil…

通過交互式網頁探索傳輸現象-AI云計算數值分析和代碼驗證

傳輸過程涉及質量、動量和能量等物理量在各種系統中的基本運動和轉移&#xff0c;主要分為動量傳輸、熱量傳輸和質量傳輸&#xff0c;在工程、環境科學、生物學和物流等領域至關重要。 傳輸過程是指物理量&#xff08;如質量、動量和能量&#xff09;在物理、化學、生物或工程系…

使用Rust原生實現小波卡爾曼濾波算法

一、算法原理概述小波變換&#xff08;Wavelet Transform&#xff09;通過多尺度分解將信號分為高頻&#xff08;細節&#xff09;和低頻&#xff08;近似&#xff09;部分&#xff0c;高頻通常包含噪聲&#xff0c;低頻保留主體信息。使用Haar小波&#xff08;計算高效&#x…

leetcode 3304. 找出第 K 個字符 I 簡單

Alice 和 Bob 正在玩一個游戲。最初&#xff0c;Alice 有一個字符串 word "a"。 給定一個正整數 k。 現在 Bob 會要求 Alice 執行以下操作 無限次 : 將 word 中的每個字符 更改 為英文字母表中的 下一個 字符來生成一個新字符串&#xff0c;并將其 追加 到原始的…

數字人分身+矩陣系統聚合+碰一碰發視頻: 源碼搭建-支持OEM

以下是關于數字人分身、矩陣系統聚合及碰一碰發視頻功能的源碼搭建與OEM支持的方案整理&#xff1a;核心技術模塊數字人分身技術 使用深度學習框架&#xff08;如PyTorch或TensorFlow&#xff09;訓練生成對抗網絡&#xff08;GAN&#xff09;或變分自編碼器&#xff08;VAE&am…

【LeetCode 熱題 100】189. 輪轉數組——(解法一)額外數組

Problem: 189. 輪轉數組 題目&#xff1a;給定一個整數數組 nums&#xff0c;將數組中的元素向右輪轉 k 個位置&#xff0c;其中 k 是非負數。 文章目錄 整體思路完整代碼時空復雜度時間復雜度&#xff1a;O(N)空間復雜度&#xff1a;O(N) 整體思路 這段代碼旨在解決一個經典的…

【PyCharm 2025.1.2配置debug】

大家先看下我的配置 1.調試配置 選擇 FastAPI 框架名稱-》 自定義應用程序文件&#xff1a;必須選擇當前項目的main.pyUvicorn 選項&#xff1a;這是啟動命令&#xff0c;有第三步的選擇 main.py 所以只需要–reload即可&#xff0c;如果想自定義啟動端口補充–port xxxxPytho…

Python數據庫軟件:查詢與預測功能集成系統

Python數據庫軟件:查詢與預測功能集成系統 概述 本文將詳細介紹一個具備查詢和模型預測功能的Python數據庫軟件的設計與實現。該系統基于Python開發,使用Excel作為數據存儲格式,包含約15個功能頁面,支持數據管理、查詢分析、模型預測等核心功能。 系統架構 技術棧 核心…