用python实现根据yolov5边框标签文件黑化边框外背景

原图

标签

处理后

代码

# -*- coding: utf-8 -*-
import os
import cv2
import numpy as np

# 配置路径(请根据实际情况修改)
input_img_dir = r'***'
input_label_dir = r'***'
output_dir = r'***'

# 创建输出目录
os.makedirs(output_dir, exist_ok=True)

def process_images():
    # 遍历图片目录
    for img_file in os.listdir(input_img_dir):
        # 构建完整文件路径
        img_path = os.path.join(input_img_dir, img_file)
        
        # 只处理图片文件
        if not img_file.lower().endswith(('.png', '.jpg', '.jpeg')):
            continue

        # 读取对应标签文件
        label_file = os.path.splitext(img_file)[0] + '.txt'
        label_path = os.path.join(input_label_dir, label_file)

        if not os.path.exists(label_path):
            print(f"警告:找不到 {img_file} 对应的标签文件,已跳过")
            continue

        # 读取图片
        # img = cv2.imread(img_path)
        # if img is None:
        #     print(f"错误:无法读取图片 {img_file},已跳过")
        #     continue
        
        # 读取图片
        try:
            # 使用二进制模式打开图片文件
            with open(img_path, 'rb') as f:
                # 将图片数据读入numpy数组
                chunk = f.read()
                img_array = np.frombuffer(chunk, dtype=np.uint8)
                # 解码图片
                img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
            if img is None:
                raise ValueError(f"无法解码图片 {img_file}")
        except Exception as e:
            print(f"错误:{e} | 文件:{img_file}")
            continue

        # 创建全黑背景
        height, width = img.shape[:2] # 获取图像的高度(height)和宽度(width)两个维度信息
        masked = np.zeros_like(img) # 创建黑色画布,如果要白色画布可以masked = np.full_like(img, 255)

        # 读取并解析YOLO标签文件
        with open(label_path, 'r') as f:  # 使用with语句确保文件安全关闭
            for line in f:  # 逐行迭代(内存友好)
                # 预处理行内容
                cleaned_line = line.strip()
                
                # 跳过空行和注释
                if not cleaned_line or cleaned_line.startswith('#'):
                    continue
                
                # 数据分割与验证
                parts = cleaned_line.split()
                if len(parts) < 5:
                    print(f"警告:无效数据行(字段不足),已跳过 - {cleaned_line}")
                    continue
                
                # 数据类型转换(带异常捕获)
                try:
                    data = [float(x) for x in parts]
                except ValueError as e:
                    print(f"数值转换失败:{cleaned_line} | 错误:{str(e)}")
                    continue
                
                # 坐标参数校验(YOLO格式应为归一化0-1)
                if not all(0 <= x <= 1 for x in data[1:5]):
                    print(f"异常坐标值(超出0-1范围),已跳过 - {data[1:]}")
                    continue
                
                # 解析坐标参数
                _, x_norm, y_norm, w_norm, h_norm = data[:5]
                
                # 转换为像素坐标(保持浮点精度计算)
                x_center = x_norm * width
                y_center = y_norm * height
                box_width = w_norm * width
                box_height = h_norm * height
                
                # 计算边界框坐标(四舍五入更精确)
                x1 = int(round(x_center - box_width / 2))
                y1 = int(round(y_center - box_height / 2))
                x2 = int(round(x_center + box_width / 2))
                x2 = min(x2, width)  # 优先约束右边界
                y2 = int(round(y_center + box_height / 2))
                y2 = min(y2, height)  # 优先约束下边界
                
                # 二次校验区域有效性
                if x2 <= x1 or y2 <= y1:
                    print(f"无效区域:x=[{x1}-{x2}], y=[{y1}-{y2}],已跳过")
                    continue
                
                # 最终安全裁剪(防御性编程)
                safe_x1 = max(0, x1)
                safe_y1 = max(0, y1)
                safe_x2 = min(width, x2)
                safe_y2 = min(height, y2)
                
                # 复制有效区域
                try:
                    masked[safe_y1:safe_y2, safe_x1:safe_x2] = img[safe_y1:safe_y2, safe_x1:safe_x2]
                except ValueError as e:
                    print(f"区域复制失败:{e} | 坐标:x={safe_x1}-{safe_x2}, y={safe_y1}-{safe_y2}")

        # 保存结果
        # output_path = os.path.join(output_dir, img_file)
        # cv2.imwrite(output_path, masked)
        # print(f"已处理:{img_file}")
        
        # 保存结果
        try:
            # 分解文件名和扩展名
            file_name, ext = os.path.splitext(img_file)
            ext = ext.lower()  # 统一转换为小写

            # 设置编码参数
            if ext in ('.jpg', '.jpeg'):
                encode_params = [int(cv2.IMWRITE_JPEG_QUALITY), 95]
            elif ext == '.png':
                encode_params = [int(cv2.IMWRITE_PNG_COMPRESSION), 4]
            else:
                encode_params = []
            
            # 编码并保存
            success, encoded_image = cv2.imencode(ext, masked, encode_params)
            if success:
                output_path = os.path.join(output_dir, img_file)
                with open(output_path, 'wb') as f:
                    encoded_image.tofile(f)
                print(f"已处理:{img_file}")
            else:
                raise ValueError("图像编码失败")
        except Exception as e:
            print(f"错误:保存文件失败 {e} | 文件:{img_file}")

if __name__ == '__main__':
    process_images()
    print("处理完成!所有结果已保存到:", output_dir)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值