MaskRcnn(二)实例分割的图像与标签同时进行增强

本文详细介绍了实例分割数据增强的原因和方法,包括防止过拟合、增强模型鲁棒性和泛化能力。通过平移、缩放、旋转等手段,提高识别精度。具体实现中,针对labelme标记的数据,进行了旋转处理,并对标签进行相应的旋转,最终保存处理后的图片和json文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、增强原因

1、防止过拟合

1.1、过拟合的定义

为了得到一致假设而使假设变得过度严格。
也就是说模型在训练集上的表现很好,但在测试集和新数据上的表现很差。
欠拟合,过拟合,适度拟合的区别。

训练集表现测试集表现结论
欠拟合
过拟合
适度拟合

1.2、过拟合出现的原因

①、模型复杂度过高,参数过多。
②、训练数据少。
③、训练集和测试集分布不一致。
④、样本里面的噪声数据干扰过大,导致模型过分记住了噪声特征,反而忽略了真实的输入输出特征。
⑤、训练集和测试集特征分布不一样。

1.3、解决方法

①、降低模型复杂度
②、扩大数据集或者进行数据增强
③、正则化
④、早停
⑤、清洗异常数据

2、增强结果模型的鲁棒性和泛化能力。

以下为我的理解,鲁棒性我理解为训练数据集中可能会出现一些错误,对这些错误的容忍能力越好,鲁棒性就越强,反之亦反,而泛化能力就是面对位置数据的一种预测能力,比如说我在A数据集上训练的,但在B数据集上仍然有比较好的表现,说明该模型或算法泛化能力比较好。

2.1、鲁棒性

模型对异常数据的容忍能力。

2.2、泛化性

模型对未知数据的预测能力。

3、提高识别精度

精度可以理解为模型好坏,把A预测为A,把B预测为B,预测的越准,精度越高。

二、常用数据增强方法

1、平移

对图像进行各个方向上的移动。

2、缩放

对图像进行缩小放大处理。

3、旋转

对图像进行一定角度的旋转。

4、随机裁切

对图像进行随机的裁剪。

5、颜色抖动

对图像的曝光度(exposure)、饱和度(saturation)和色调(hue)进行随机变化形成不同光照及颜色下的图片,达到数据增强的目的,尽可能使得模型能够使用不同光照条件小的情形,提高模型泛化能力。

6、随机遮挡

对图像进行小区域的遮挡。

7、噪声扰动:

对图像的每个像素RGB进行随机扰动, 常用的噪声模式是椒盐噪声和高斯噪声。

三、实例分割数据增强实现

因为实例分割数据集实在太难标记了,数据增强必不可少,使用手动标记的数据加上随机水平翻转进行训练后效果一般,决定把数据再一次进行增强,因为采用的是labelme标记的数据,必须对原图加上标签同时进行转变,决定尝试尝试。

1、旋转

对图像进行一定角度的旋转。
因为之前对原始数据加上水平翻转后的数据进行训练后,发现效果不是特别理想,看了看效果图后,发现原始数据大多数都是很规整的,而测试的数据如果有的物体不正,就会导致识别不出来,如下图。
在这里插入图片描述
如果比较规整,还蛮好识别的。
在这里插入图片描述
于是决定首先对图像进行旋转处理。

1.1先观察一下json文件
{
    "version": "4.5.9",               //labelme的版本号
    "flags": {},                      //flag标记
    "shapes": [                       //边由点构成的多边形
      {
        "line_color": null,           //线的颜色
        "fill_color": null,           //填充颜色
        "label": "2",                 //标签
        "points": [                   //一个个点,这里只列出一个点。
          [
            1365.8296754954001,
            1075.6984533100115
          ]
        ],
        "group_id": 1,                //实体的id号,同一类的第几个
        "shape_type": "polygon",      //图形类型
        "flags": {}                   //flag标记
      }
    ],
    "imagePath": "1.jpg"              //图片的位置

后面就是一长串一长串的东西,可以不用管它。根据这个json文件的特征进行修改标签。

1.2、导入必要的库
import cv2        #计算机视觉库
import json       #用来解析json文件
import numpy as np  #科学计算包
import sys #处理Python运行时配置以及资源
import os  #负责程序与操作系统的交互,提供了访问操作系统底层的接口。
import random  #实现了各种分布的伪随机数生成
import time #处理时间的标准库
import base64 #编解码库
from math import cos ,sin ,pi,fabs,radians #内置数学类函数库
1.3、导入图片

图片数量很多,不可能一张张图片进行,直接对一个文件里所有图片进行相同处理。

import cv2 as cv
import os
images_path = 'C:/Users/Administrator/Desktop/PersonCode/data/'  #图片的根目录
save_path = "C:/Users/Administrator/Desktop/PersonCode/sava_data/" #保存图片文件夹
file_list = os.listdir(images_path)
for img_name in file_list:
    print(img_name)
1.4、读取json文件

同样得对json进行批量读取,不过要注意每一张图片和json对应起来,这样处理的时候才能正确,下面给出读取json文件的代码,完整代码会放在最后面。
#读取json文件

def ReadJson(jsonfile):
    with open(jsonfile,encoding='utf-8') as f:
        jsonData = json.load(f)
    return jsonData
1.5、对图片进行旋转

图像旋转函数如下

def RotateImage(img, degree):
    height, width = img.shape[:2]    #获得图片的高和宽
    heightNew = int(width * fabs(sin(radians(degree))) + height * fabs(cos(radians(degree))))
    widthNew = int(height * fabs(sin(radians(degree))) + width * fabs(cos(radians(degree))))
    matRotation = cv2.getRotationMatrix2D((width // 2, height // 2), degree, 1)
    matRotation[0, 2] += (widthNew - width) // 2
    matRotation[1, 2] += (heightNew - height) // 2
    print(width // 2,height // 2)
    imgRotation = cv2.warpAffine(img, matRotation, (widthNew, heightNew), borderValue=(255, 255, 255))
    return imgRotation,matRotation

在这里插入图片描述
背景可以改cv2的参数进行替换,image_rotate = cv2.warpAffine(image, M, (nW, nH),borderValue=(255,255,255))中的borderValue删了,改成用边缘颜色填充即可,加上参数borderMode=1,也就是改成imgRotation = cv2.warpAffine(img, matRotation, (widthNew, heightNew),borderMode=1)。
虽然看着有些别扭,但是能训练就行。
在这里插入图片描述

1.6、对图片进行裁剪

发现旋转后的图片有些高,因为很多都是补充出来的,而我使用的数据集大多数在中间,其实可以四周裁剪一下。
采用以下方法

imgRotation=imgRotation[imgRotation.shape[0]//9:(imgRotation.shape[0]//9)*8,imgRotation.shape[1]//9:(imgRotation.shape[1]//9)*8]

其实就是从长和宽的九分之一处到九分之八处裁剪一下。imgRotation[0]处理的是y方向(纵),imgRotation[1]处理x方向(横),裁剪后得改标签,慢慢探索。

1.7、对标签进行旋转
#坐标旋转
def rotatePoint(Srcimg_rotate,jsonTemp,M,imagePath):
    json_dict = {}
    for key, value in jsonTemp.items():
        if key=='imageHeight':
            json_dict[key]=Srcimg_rotate.shape[0]
            print('gao',json_dict[key])
        elif key=='imageWidth':
            json_dict[key] = Srcimg_rotate.shape[1]
            print('kuai',json_dict[key])
        elif key=='imageData':
            json_dict[key] = image_to_base64(Srcimg_rotate)
        elif key=='imagePath':
            json_dict[key] = imagePath
        else:
            json_dict[key] = value
    for item in json_dict['shapes']:
        for key, value in item.items():
            if key == 'points':
                for item2 in range(len(value)):
                    pt1=np.dot(M,np.array([[value[item2][0]],[value[item2][1]],[1]]))
                    value[item2][0], value[item2][1] = pt1[0][0], pt1[1][0]
    return json_dict
1.7、保存图片
cv2.imwrite("./result/"+img_name[:-4]+"_30"+'.jpg',img_rotate)
WriteJson('./result/'+img_name[:-4]+"_30"+'.json', json_rotate)
1.8、完整代码
import cv2        #计算机视觉库
import json       #用来解析json文件
import numpy as np  #科学计算包
import sys #处理Python运行时配置以及资源
import os  #负责程序与操作系统的交互,提供了访问操作系统底层的接口。
import random  #实现了各种分布的伪随机数生成
import time #处理时间的标准库
import base64 #编解码库
from math import cos ,sin ,pi,fabs,radians #内置数学类函数库
images_path = 'C:/Users/Administrator/Desktop/PersonCode/data/'  #图片的根目录
json_path='C:/Users/Administrator/Desktop/PersonCode/json/'  #json文件的根目录
save_path = "C:/Users/Administrator/Desktop/PersonCode/sava_data/" #保存图片文件夹
#读取json文件
def ReadJson(jsonfile):
    with open(jsonfile,encoding='utf-8') as f:
        jsonData = json.load(f)
    return jsonData
#保存json
def WriteJson(filePath,data):
    write_json = open(filePath,'w')
    write_json.write(json.dumps(data,indent=2)) 
    write_json.close()
def rotate_bound(image, angle):
    h, w,_ = image.shape
    (cX, cY) = (w // 2, h // 2)
    M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY
    image_rotate = cv2.warpAffine(image, M, (nW, nH),borderMode=1)
    return image_rotate,cX,cY,angle
def RotateImage(img, degree):
    height, width = img.shape[:2]    #获得图片的高和宽
    heightNew = int(width * fabs(sin(radians(degree))) + height * fabs(cos(radians(degree))))
    widthNew = int(height * fabs(sin(radians(degree))) + width * fabs(cos(radians(degree))))
    matRotation = cv2.getRotationMatrix2D((width // 2, height // 2), degree, 1)
    matRotation[0, 2] += (widthNew - width) // 2
    matRotation[1, 2] += (heightNew - height) // 2
    print(width // 2,height // 2)
    imgRotation = cv2.warpAffine(img, matRotation, (widthNew, heightNew),borderMode=1)
    
    return imgRotation,matRotation
def rotate_xy(x, y, angle, cx, cy):
    # print(cx,cy)
    angle = angle * pi / 180
    x_new = (x - cx) * cos(angle) - (y - cy) * sin(angle) + cx
    y_new = (x - cx) * sin(angle) + (y - cy) * cos(angle) + cy
    return x_new, y_new
#转base64
def image_to_base64(image_np):
    image = cv2.imencode('.jpg', image_np)[1]
    image_code = str(base64.b64encode(image))[2:-1]
    return image_code
#坐标旋转
def rotatePoint(Srcimg_rotate,jsonTemp,M,imagePath):
    json_dict = {}
    for key, value in jsonTemp.items():
        if key=='imageHeight':
            json_dict[key]=Srcimg_rotate.shape[0]
            print('gao',json_dict[key])
        elif key=='imageWidth':
            json_dict[key] = Srcimg_rotate.shape[1]
            print('kuai',json_dict[key])
        elif key=='imageData':
            json_dict[key] = image_to_base64(Srcimg_rotate)
        elif key=='imagePath':
            json_dict[key] = imagePath
        else:
            json_dict[key] = value
    for item in json_dict['shapes']:
        for key, value in item.items():
            if key == 'points':
                for item2 in range(len(value)):
                    pt1=np.dot(M,np.array([[value[item2][0]],[value[item2][1]],[1]]))
                    value[item2][0], value[item2][1] = pt1[0][0], pt1[1][0]
    return json_dict

if __name__=='__main__':
    file_list = os.listdir(images_path)
    i=0
    for img_name in file_list:
        i=i+1
        if i==211:
            break
        SrcImg=cv2.imread(images_path+img_name)            #读取图片
        JsonData=ReadJson(json_path+img_name[:-3]+'json')    #读取对应的json文件
        img_rotate,mat_rotate=RotateImage(SrcImg, 30)    #旋转图片
        json_rotate=rotatePoint(img_rotate,JsonData,mat_rotate,img_name)
        cv2.imwrite("./result/"+img_name[:-4]+"_30"+'.jpg',img_rotate)
        WriteJson('./result/'+img_name[:-4]+"_30"+'.json', json_rotate)
        print(img_name,"is ok!")

后面的处理方式和代码后续会补上。

Mosaic实例分割数据增强是一种用于深度学习图像分析任务(如实例分割或目标检测)的数据增强技术。它结合了多个输入图像的局部区域(mosaics),生成新的训练样本,目的是提高模型对图像中不同对象的识别和定位能力,尤其是在小样本或类别不平衡的情况下。这种技术主要通过以下步骤进行: 1. **选择图像**: 从训练集随机选取多个图像。 2. **裁剪区域**: 从每个图像中随机裁剪出多个不重叠的小块。 3. **拼接**: 将这些小块按照一定的布局(如网格状)重新组合到一个新的大图中,保持每个小块的边界信息。 4. **实例分割处理**: 对于每个小块,保留其原有的实例分割标签,确保在新图中的每个部分都能对应到原始的类别信息。 5. **添加噪声**: 可能会对拼接后的图像添加一些随机噪声,如颜色抖动或轻微模糊,增加模型对光照、纹理变化的适应性。 使用mosaic数据增强的好处包括: - **提升模型泛化能力**: 让模型在训练时看到更多样化的场景组合,防止过拟合。 - **增强小物体识别**: 小物体在mosaic中可能占据更大的比例,有助于模型更好地学习。 - **类别均衡**: 特别适合处理类别分布不均的情况,使得每个类别的样本都能得到足够的处理。 如果你对如何在实践中应用这种数据增强或者具体代码实现有疑问,我可以提供更详细的指导。相关的技术细节还有哪些你想了解的?
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

血狼傲骨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值