前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Python图像识别] 二十一.水书图像识别之利用数据增强扩充图像数据集

[Python图像识别] 二十一.水书图像识别之利用数据增强扩充图像数据集

作者头像
Eastmount
发布2023-12-06 19:09:53
2030
发布2023-12-06 19:09:53
举报

该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类应用。希望文章对您有所帮助,如果有不足之处,还请海涵~

这篇文章将详细讲解利用数据增强方法实现图像数据集的扩充。通常,在某些情况下我们会缺失数据集或需要自主构建数据集,此时数据增强将发挥重要作用,本文以水书图像为例,通过五大类方法扩充数据集。本文以代码和方法为主,原理知识整个系列的众多文章已经介绍过。

希望对您有所帮助!让我们开始吧,且看且珍惜。

  • 一.什么是水书
  • 二.数据集构造
  • 三.数据增强
    • 1.什么是数据增强
    • 2.几何变换增强数据
    • 3.亮度变换增强数据
    • 4.颜色通道变换增强数据
    • 5.高斯噪声和椒盐噪声
    • 6.模拟怀旧和噪声添加
  • 五.完整代码
  • 六.如何用GAN生成图像?
  • 七.总结

该系列在github所有源代码:

  • https://github.com/eastmountyxz/ ImageProcessing-Python

学Python近十年,认识了很多大佬和朋友,感恩。深知自己很菜,得拼命努力前行,编程也没有什么捷径,干就对了。希望未来能更透彻学习和撰写文章,同时非常感谢参考文献中的大佬们的文章和分享,共勉。 - https://blog.csdn.net/eastmount


一.什么是水书

水书是水族古文字及其著编典籍的汉译统称,是除纳西族东巴文以外世界上最后“活着”的象形文字,收集整理、研究解读水族文字对了解水族历史文化、研究少数民族原始宗教和文化信仰、从中窥探中国古文字奥秘有着重要意义。

由于水书是靠数量稀少的水书先生代代手抄传承,且记录水书的载体除纸张外还有大量刺绣、碑刻、木刻等其他原生载 体、金石载体,随着时代的发展,大量水书古籍文献和文字图像正在损毁和流失。另一方面,水书传承者的数量随着时间推移正在急剧减少,据统计,全国有近千名水书先生,但绝大部分已在60岁以上,大量散落民间的水书古籍无法被收集进行专业修复和妥善保存。传统水书收集整理和水族文字研究在人力、物力和技术上有一定的局限性,对大量散落民间的水书进行系统采集整理和文字提取识别难度巨大,无法满足信息化时代对濒危水族文字抢救提出的新要求。

当前,国内外学者开始高度重视对濒危水书的抢救工作,发掘、收集和整理了大批水书文献资料。这一时期,除了传统的对水书自身的研究和挖掘,学者们也开始思考水族文字抢救工作中存在的问题和困难,并不断探索解决方案,如罗春寒的《水书的抢救及存在问题浅议》、潘朝霖的《水文急剧消亡的原因探 析》、康蔼德和潘兴文的《水 语 调 查 研 究》等。随着计算机技术的发展和普及,水书研究进入信息化时代,运用计算机辅助水书输入、整理研究开始走入学术视野,如韦宗林的《水族古文字计算机输入法》、董芳的《水书文字规范标准建设与信息化的研究》、罗刚的《计 算 机 水 书 语 料库建设的探讨》、戴丹的《水书水字可视化输入中的模式 匹配》。经过各级部门和专家学者不遗余力的努力,目前国内水书的整理和研究已颇具成效。但传统的水族文字采集、整理和保护方式还存在以下几个方面的不足:

  • 由于记载水族文字的主要载体为口传、纸张手抄、刺绣、碑刻、木刻、陶瓷和古籍等,文字清晰度不足,数字化读取困难,对字体的采集和整理主要依赖于大量的人力和物力,信息化环境下的数据库建设不足,大大制约了整理和研究效率;
  • 历来对水书和水族古文字的研究主要采用人文社科的思想,侧重于对字源、字音、字义和文化内涵的破译和解读,现代化信息技术在水书研究领域的运用体现不明显,作用没有得到充分发挥;
  • 对水族文字提取和识别研究,破译成果的整理和运用不足,至今没有完成水书本体和水族古文字识别及数据库的建设。

随着计算机视觉和图像处理技术的迅速发展,图像分割与图像识别方法已广泛应用于各行各业,比如车牌识别、人脸识别、身份证识等。图像分割是将图像分成若干具有独特性质的区域并提取感兴趣目标的技术,它是图像处理和图像分析的关键步骤。图像识别是通过算法和函数提取像素中的某些特征,并对图像进行识别和分类的过程。

为了更好地运用现代计算机图像处理和图像分割等技术来辅助濒危水族文字的抢救工作,保护水族文化,修复水书文物图像,本文提出了一种基于图像增强及区域检测的水族文字提取与分割算法。该研究具有重要的理论研究意义和良好的实际应用价值,可以广泛应用于水族文字提取、水族文字识别和水族文化传承领域。


二.数据集构造

作者构造了如下图的初始数据集,共计12个水族文字,您可以猜猜它们的含义。

PS:我写的水书看着还不错,丑萌丑萌的 O(∩_∩)O

初始数据集如下图所示,大家猜中了吗?

很显然,紧靠人工撰写无法完成水族文字识别任务。那怎么解决呢?

  • 方法1:通过图像提取采集水族古籍中的古文字,并构造数据集
  • 方法2:通过数据增强的方法生成更多的数据集
  • 方法3:利用GAN算法生成类似的数据集,但前提仍需要学习

此外,在真实场景中,我们会遇到很多缺乏图像数据的情况,数据增强的方法非常适用且有效。因此,本文主要介绍数据增强扩充水书图像数据集的案例。


三.数据增强

1.什么是数据增强

数据增强也叫数据扩增,意思是在不实质性的增加数据的情况下,让有限的数据产生等价于更多数据的价值。

常见方法如下:

  • 空间几何变换– 镜像、翻转、旋转、缩放、平移、裁剪
  • .亮度变换 – 亮度、对比度、饱和度
  • 颜色通道变换
  • 噪声变换– 椒盐噪声、高斯噪声、白点噪声
  • 模拟雾或图像怀旧特效– 模拟传统水书碑刻、木刻等场景,针对特定场景进行模拟
  • GAN– 深度学习生成类似图像
  • 其它方法– SMOTE、 mixup(线性插值)、AutoAugment

2.几何变换增强数据

图像几何变换不改变图像的像素值,在图像平面上进行像素变换。适当的几何变换可以最大程度地消除由于成像角度、透视关系乃至镜头自身原因所造成的几何失真所产生的负面影响。几何变换常常作为图像处理应用的预处理步骤,是图像归一化的核心工作之一。比如图像旋转原理如下:

原理参考作者前文:

  • [Python从零到壹] 三十八.图像处理基础篇之图像几何变换(平移缩放旋转)
  • [Python从零到壹] 三十九.图像处理基础篇之图像几何变换(镜像仿射透视)

该部分关键代码如下:

代码语言:javascript
复制
# -*- coding: utf-8 -*-
"""
2022-12-24
By: Eastmount CSDN xiuzhang
"""
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt

#-----------------------------------------------------------------------
#几何变换-镜像、翻转、旋转、缩放
def JH_Transformation(img,img_path):
    rows, cols, channel = img.shape
    #print(rows,cols,channel)
    
    #镜像处理
    jx = cv2.flip(img, 1)

    #旋转30度 (旋转中心,旋转度数,scale)
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 30, 1)
    rotated30 = cv2.warpAffine(img, M, (cols, rows), borderValue=(255,255,255))

    #旋转45度 (旋转中心,旋转度数,scale)
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 1)
    rotated45 = cv2.warpAffine(img, M, (cols, rows), borderValue=(255,255,255))

    #旋转90度 (旋转中心,旋转度数,scale)
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 90, 1)
    rotated90 = cv2.warpAffine(img, M, (cols, rows), borderValue=(255,255,255))

    #旋转330度 (旋转中心,旋转度数,scale)
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 330, 1)
    rotated330 = cv2.warpAffine(img, M, (cols, rows), borderValue=(255,255,255))

    #旋转180度
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 180, 1)
    rotated180 = cv2.warpAffine(img, M, (cols, rows), borderValue=(255,255,255))

    #缩小
    sx = cv2.resize(img, (int(cols*0.8), int(rows*0.8)))
    
    #放大
    fd = cv2.resize(img, (int(cols*1.2), int(rows*1.2)))
    
    #显示图像
    titles = ['Source', 'JX', 'XZ30', 'XZ45', 'XZ90', 'XZ330', 'XZ180', 'SX', 'FD']
    images = [img, jx, rotated30, rotated45, rotated90, rotated330, rotated180, sx, fd]
    for i in range(9):
       plt.subplot(3,3,i+1), plt.imshow(images[i], 'gray')
       plt.title(titles[i])
       plt.xticks([]),plt.yticks([])
    plt.show()

    #保存图像
    cv2.imwrite(img_path[0:-4] + '_jx.png', jx)
    cv2.imwrite(img_path[0:-4] + '_rotated30.png', rotated30)
    cv2.imwrite(img_path[0:-4] + '_rotated45.png', rotated45)
    cv2.imwrite(img_path[0:-4] + '_rotated90.png', rotated90)
    cv2.imwrite(img_path[0:-4] + '_rotated330.png', rotated330)
    cv2.imwrite(img_path[0:-4] + '_rotated180.png', rotated180)
    cv2.imwrite(img_path[0:-4] + '_sx.png', sx)
    cv2.imwrite(img_path[0:-4] + '_fd.png', fd)
    
#-----------------------------------------------------------------------
#读取指定文件夹下的所有图像
def main():
    file_path = "data"
    for img_name in os.listdir(file_path):
        img_path = file_path + "\\" + img_name
        res_path = "data_add" + "\\" + img_name
        img = cv2.imread(img_path)
        
        #1.几何变换-镜像、翻转、旋转、缩放
        JH_Transformation(img,res_path)

if __name__ == "__main__":
    main()

输出结果如下图所示:


3.亮度变换增强数据

图像亮度变换类似于图像加法或减法运算。第一种是调用Numpy库实现,目标图像像素为两张图像的像素之和;第二种是通过OpenCV调用add()函数实现。第二种方法的函数原型如下:

  • dst = add(src1, src2[, dst[, mask[, dtype]]])– src1表示第一张图像的像素矩阵 – src2表示第二张图像的像素矩阵 – dst表示输出的图像,必须和输入图像具有相同的大小和通道数 – mask表示可选操作掩码(8位单通道数组),用于指定要更改的输出数组的元素。 – dtype表示输出数组的可选深度

注意,当两幅图像的像素值相加结果小于等于255时,则输出图像直接赋值该结果,如120+48赋值为168;如果相加值大于255,则输出图像的像素结果设置为255,如(255+64) 赋值为255。原理参考作者前文:

  • [Python从零到壹] 三十六.图像处理基础篇之图像算术与逻辑运算详解

该部分关键代码如下:

代码语言:javascript
复制
#-----------------------------------------------------------------------
#亮度变换-增强、减弱
def Brighter_Transformation(img, percetage):
    img_copy = img.copy()
    w = img.shape[1]
    h = img.shape[0]
    for xi in range(0, w):
        for xj in range(0, h):
            img_copy[xj, xi, 0] = np.clip(int(img[xj, xi, 0] * percetage), a_max=255, a_min=0)
            img_copy[xj, xi, 1] = np.clip(int(img[xj, xi, 1] * percetage), a_max=255, a_min=0)
            img_copy[xj, xi, 2] = np.clip(int(img[xj, xi, 2] * percetage), a_max=255, a_min=0)
    return img_copy

def Darker_Transformation(img, percetage):
    img_copy = img.copy()
    w = img.shape[1]
    h = img.shape[0]
    for xi in range(0, w):
        for xj in range(0, h):
            img_copy[xj, xi, 0] = int(img[xj, xi, 0] * percetage)
            img_copy[xj, xi, 1] = int(img[xj, xi, 1] * percetage)
            img_copy[xj, xi, 2] = int(img[xj, xi, 2] * percetage)
    return img_copy

def LD_Transformation(img,img_path):
    rows, cols, channel = img.shape
    
    #增强1.1、1.5、2.0、2.5、3.0
    zq_11 = Brighter_Transformation(img,1.1)
    zq_15 = Brighter_Transformation(img,1.5)
    zq_20 = Brighter_Transformation(img,2.0)
    zq_25 = Brighter_Transformation(img,2.5)
    zq_30 = Brighter_Transformation(img,3.0)

    #减弱0.9、0.8、0.5
    jr_09 = Darker_Transformation(img,0.9)
    jr_08 = Darker_Transformation(img,0.8)
    jr_07 = Darker_Transformation(img,0.7)

    #显示图像
    titles = ['Source', 'ZQ1.1', 'ZQ1.5', 'ZQ2.0', 'ZQ2.5', 'ZQ3.0', 'JR0.9', 'JR0.8', 'JR0.7']
    images = [img, zq_11, zq_15, zq_20, zq_25, zq_30, jr_09, jr_08, jr_07]
    for i in range(9):
       plt.subplot(3,3,i+1), plt.imshow(images[i], 'gray')
       plt.title(titles[i])
       plt.xticks([]),plt.yticks([])
    plt.show()

    #保存图像
    cv2.imwrite(img_path[0:-4] + '_zq_11.png', zq_11)
    cv2.imwrite(img_path[0:-4] + '_zq_15.png', zq_15)
    cv2.imwrite(img_path[0:-4] + '_zq_20.png', zq_20)
    cv2.imwrite(img_path[0:-4] + '_zq_25.png', zq_25)
    cv2.imwrite(img_path[0:-4] + '_zq_30.png', zq_30)
    cv2.imwrite(img_path[0:-4] + '_jr_09.png', jr_09)
    cv2.imwrite(img_path[0:-4] + '_jr_08.png', jr_08)
    cv2.imwrite(img_path[0:-4] + '_jr_07.png', jr_07)

输出结果如下图所示:


4.颜色通道变换增强数据

该部分关键代码如下:

代码语言:javascript
复制
#-----------------------------------------------------------------------
#颜色通道变换
def Channel_Transformation(img,img_path):
    rows, cols, channel = img.shape
    img = Brighter_Transformation(img,1.5)  #边缘增强
    color_map = [
        cv2.COLORMAP_AUTUMN,
        cv2.COLORMAP_BONE,
        cv2.COLORMAP_JET,
        cv2.COLORMAP_WINTER,
        cv2.COLORMAP_PARULA,
        cv2.COLORMAP_OCEAN,
        cv2.COLORMAP_SUMMER,
        cv2.COLORMAP_SPRING,
        cv2.COLORMAP_COOL,
        cv2.COLORMAP_PINK,
        cv2.COLORMAP_HOT,
        cv2.COLORMAP_PARULA,
        cv2.COLORMAP_MAGMA,
        cv2.COLORMAP_INFERNO,
        cv2.COLORMAP_PLASMA,
        cv2.COLORMAP_TWILIGHT,
        cv2.COLORMAP_TWILIGHT_SHIFTED
    ]

    rgb_img_01 = cv2.applyColorMap(img, color_map[0])
    rgb_img_02 = cv2.applyColorMap(img, color_map[1])
    rgb_img_03 = cv2.applyColorMap(img, color_map[9])
    rgb_img_04 = cv2.applyColorMap(img, color_map[3])
    rgb_img_05 = cv2.applyColorMap(img, color_map[13])
    rgb_img_06 = cv2.applyColorMap(img, color_map[5])
    rgb_img_07 = cv2.applyColorMap(img, color_map[12])
    rgb_img_08 = cv2.applyColorMap(img, color_map[10])

    # 通道分离
    b = cv2.split(img)[0]
    g = np.zeros((rows,cols), dtype=img.dtype)
    r = np.zeros((rows,cols), dtype=img.dtype)
    mb = cv2.merge([b, g, r])

    g = cv2.split(img)[1]
    b = np.zeros((rows,cols), dtype=img.dtype)
    r = np.zeros((rows,cols), dtype=img.dtype)
    mg = cv2.merge([b, g, r])

    r = cv2.split(img)[2]
    b = np.zeros((rows,cols), dtype=img.dtype)
    g = np.zeros((rows,cols), dtype=img.dtype)
    mr = cv2.merge([b, g, r])
    
    #显示图像
    titles = ['Source', 'RGB-1', 'RGB-2', 'RGB-3', 'RGB-4',
              'RGB-5', 'RGB-6', 'RGB-7', 'RGB-8', 'B', 'G', 'R']
    images = [img, rgb_img_01, rgb_img_02, rgb_img_03, rgb_img_04,
              rgb_img_05, rgb_img_06, rgb_img_07, rgb_img_08, mb, mg, mr]
    for i in range(12):
       plt.subplot(4,3,i+1), plt.imshow(images[i], 'gray')
       plt.title(titles[i])
       plt.xticks([]),plt.yticks([])
    plt.show()

    #保存图像
    cv2.imwrite(img_path[0:-4] + '_rgb_img_01.png', rgb_img_01)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_02.png', rgb_img_02)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_03.png', rgb_img_03)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_04.png', rgb_img_04)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_05.png', rgb_img_05)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_06.png', rgb_img_06)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_07.png', rgb_img_07)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_08.png', rgb_img_08)
    cv2.imwrite(img_path[0:-4] + '_mb.png', mb)
    cv2.imwrite(img_path[0:-4] + '_mg.png', mg)
    cv2.imwrite(img_path[0:-4] + '_mr.png', mr)

输出结果如下图所示:


5.高斯噪声和椒盐噪声

该部分关键代码如下:

代码语言:javascript
复制
#-----------------------------------------------------------------------
#添加高斯噪声和椒盐噪声
def GaussianNoise(img, percetage):
    gn = img.copy()
    w = img.shape[1]
    h = img.shape[0]
    G_NoiseNum = int(percetage * img.shape[0] * img.shape[1])
    for i in range(G_NoiseNum):
        lx = np.random.randint(0, h)
        ly = np.random.randint(0, w)
        gn[lx][ly][np.random.randint(3)] = np.random.randn(1)[0]
    return gn

def SaltNoise(img, percetage):
    sn = img.copy()
    SP_NoiseNum = int(percetage * img.shape[0] * img.shape[1])
    for i in range(SP_NoiseNum):
        randR = np.random.randint(0, img.shape[0] - 1)
        randG = np.random.randint(0, img.shape[1] - 1)
        randB = np.random.randint(0, 3)
        if np.random.randint(0, 1) == 0:
            sn[randR, randG, randB] = 0
        else:
            sn[randR, randG, randB] = 255
    return sn

def Gaussian_Salt_Noise(img,res_path):
    rows, cols, channel = img.shape
    img = Brighter_Transformation(img,1.5)  #边缘增强

    #高斯噪声
    gn_005 = GaussianNoise(img, 0.05)
    gn_010 = GaussianNoise(img, 0.10)
    gn_015 = GaussianNoise(img, 0.15)
    gn_020 = GaussianNoise(img, 0.20)

    #椒盐噪声
    sn_005 = SaltNoise(img, 0.05)
    sn_010 = SaltNoise(img, 0.10)
    sn_015 = SaltNoise(img, 0.15)
    sn_020 = SaltNoise(img, 0.20)
    
    #显示图像
    titles = ['Source', 'Gaussian-0.05', 'Gaussian-0.10', 'Gaussian-0.15', 'Gaussian-0.20',
              'Salt-0.05', 'Salt-0.10', 'Salt-0.15', 'Salt-0.20']
    images = [img, gn_005, gn_010, gn_015, gn_020, sn_005, sn_010, sn_015, sn_020]
    for i in range(9):
       plt.subplot(3,3,i+1), plt.imshow(images[i], 'gray')
       plt.title(titles[i])
       plt.xticks([]),plt.yticks([])
    plt.show()
    
    #保存图像
    cv2.imwrite(img_path[0:-4] + '_gn_005.png', gn_005)
    cv2.imwrite(img_path[0:-4] + '_gn_010.png', gn_010)
    cv2.imwrite(img_path[0:-4] + '_gn_015.png', gn_015)
    cv2.imwrite(img_path[0:-4] + '_gn_020.png', gn_020)
    cv2.imwrite(img_path[0:-4] + '_sn_005.png', sn_005)
    cv2.imwrite(img_path[0:-4] + '_sn_010.png', sn_010)
    cv2.imwrite(img_path[0:-4] + '_sn_015.png', sn_015)
    cv2.imwrite(img_path[0:-4] + '_sn_020.png', sn_020)

输出结果如下图所示:


6.模拟怀旧和噪声添加

该部分关键代码如下:

代码语言:javascript
复制
#-----------------------------------------------------------------------
#模拟怀旧和噪声添加
def Salt(img, num):
    wn = img.copy()
    rows, cols, chn = wn.shape
    for i in range(num):
        x = np.random.randint(0, rows)
        y = np.random.randint(0, cols)    
        wn[x,y,:] = 210
    return wn

def Fog_Noise(img, percetage):
    mask_img = img.copy()
    mask_img[:, :] = (166, 178, 180)  #雾的颜色 (146,182,213)
    
    #调整雾的浓度 round(random.uniform(0.03, 0.28), 2)
    res = cv2.addWeighted(img, percetage, mask_img, 1-percetage, 0) 
    return res

def Fog_Salt_Noise(img,img_path):
    rows, cols, channel = img.shape
    img = Brighter_Transformation(img,1.5)  #边缘增强

    #白点噪声
    wn_100 = Salt(img, 100)
    wn_150 = Salt(img, 150)
    wn_200 = Salt(img, 200)
    wn_250 = Salt(img, 250)

    #模拟怀旧
    fog_06 = Fog_Noise(img, 0.6)
    fog_07 = Fog_Noise(img, 0.7)
    fog_08 = Fog_Noise(img, 0.8)
    fog_09 = Fog_Noise(img, 0.9)

    #显示图像
    titles = ['Source', 'wn-100', 'wn-150', 'wn-200', 'wn-250',
              'fog_06', 'fog_07', 'fog_08', 'fog_09']
    images = [img, wn_100, wn_150, wn_200, wn_250,
              fog_06, fog_07, fog_08, fog_09]
    for i in range(9):
       plt.subplot(3,3 ,i+1), plt.imshow(images[i], 'gray')
       plt.title(titles[i])
       plt.xticks([]),plt.yticks([])
    plt.show()

    #保存图像
    cv2.imwrite(img_path[0:-4] + '_wn_100.png', wn_100)
    cv2.imwrite(img_path[0:-4] + '_wn_150.png', wn_150)
    cv2.imwrite(img_path[0:-4] + '_wn_200.png', wn_200)
    cv2.imwrite(img_path[0:-4] + '_wn_250.png', wn_250)
    cv2.imwrite(img_path[0:-4] + '_fog_06.png', fog_06)
    cv2.imwrite(img_path[0:-4] + '_fog_07.png', fog_07)
    cv2.imwrite(img_path[0:-4] + '_fog_08.png', fog_08)
    cv2.imwrite(img_path[0:-4] + '_fog_09.png', fog_09)

输出结果如下图所示:


五.完整代码

本文的最终代码如下所示,通过定义函数实现了五大类别的数据增强。希望对您有所帮助。

代码语言:javascript
复制
# -*- coding: utf-8 -*-
"""
2022-12-24
By: Eastmount CSDN xiuzhang
"""
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
import random

#-----------------------------------------------------------------------
#几何变换-镜像、翻转、旋转、缩放
def JH_Transformation(img,img_path):
    rows, cols, channel = img.shape
    #print(rows,cols,channel)
    
    #镜像处理
    jx = cv2.flip(img, 1)

    #旋转30度 (旋转中心,旋转度数,scale)
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 30, 1)
    rotated30 = cv2.warpAffine(img, M, (cols, rows), borderValue=(255,255,255))

    #旋转45度 (旋转中心,旋转度数,scale)
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 1)
    rotated45 = cv2.warpAffine(img, M, (cols, rows), borderValue=(255,255,255))

    #旋转90度 (旋转中心,旋转度数,scale)
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 90, 1)
    rotated90 = cv2.warpAffine(img, M, (cols, rows), borderValue=(255,255,255))

    #旋转330度 (旋转中心,旋转度数,scale)
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 330, 1)
    rotated330 = cv2.warpAffine(img, M, (cols, rows), borderValue=(255,255,255))

    #旋转180度
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 180, 1)
    rotated180 = cv2.warpAffine(img, M, (cols, rows), borderValue=(255,255,255))

    #缩小
    sx = cv2.resize(img, (int(cols*0.8), int(rows*0.8)))
    
    #放大
    fd = cv2.resize(img, (int(cols*1.2), int(rows*1.2)))

    """
    #显示图像
    titles = ['Source', 'JX', 'XZ30', 'XZ45', 'XZ90', 'XZ330', 'XZ180', 'SX', 'FD']
    images = [img, jx, rotated30, rotated45, rotated90, rotated330, rotated180, sx, fd]
    for i in range(9):
       plt.subplot(3,3,i+1), plt.imshow(images[i], 'gray')
       plt.title(titles[i])
       plt.xticks([]),plt.yticks([])
    plt.show()
    """

    #保存图像
    cv2.imwrite(img_path[0:-4] + '_jx.png', jx)
    cv2.imwrite(img_path[0:-4] + '_rotated30.png', rotated30)
    cv2.imwrite(img_path[0:-4] + '_rotated45.png', rotated45)
    cv2.imwrite(img_path[0:-4] + '_rotated90.png', rotated90)
    cv2.imwrite(img_path[0:-4] + '_rotated330.png', rotated330)
    cv2.imwrite(img_path[0:-4] + '_rotated180.png', rotated180)
    cv2.imwrite(img_path[0:-4] + '_sx.png', sx)
    cv2.imwrite(img_path[0:-4] + '_fd.png', fd)

#-----------------------------------------------------------------------
#亮度变换-增强、减弱
def Brighter_Transformation(img, percetage):
    img_copy = img.copy()
    w = img.shape[1]
    h = img.shape[0]
    for xi in range(0, w):
        for xj in range(0, h):
            img_copy[xj, xi, 0] = np.clip(int(img[xj, xi, 0] * percetage), a_max=255, a_min=0)
            img_copy[xj, xi, 1] = np.clip(int(img[xj, xi, 1] * percetage), a_max=255, a_min=0)
            img_copy[xj, xi, 2] = np.clip(int(img[xj, xi, 2] * percetage), a_max=255, a_min=0)
    return img_copy

def Darker_Transformation(img, percetage):
    img_copy = img.copy()
    w = img.shape[1]
    h = img.shape[0]
    for xi in range(0, w):
        for xj in range(0, h):
            img_copy[xj, xi, 0] = int(img[xj, xi, 0] * percetage)
            img_copy[xj, xi, 1] = int(img[xj, xi, 1] * percetage)
            img_copy[xj, xi, 2] = int(img[xj, xi, 2] * percetage)
    return img_copy

def LD_Transformation(img,img_path):
    rows, cols, channel = img.shape
    
    #增强1.1、1.5、2.0、2.5、3.0
    zq_11 = Brighter_Transformation(img,1.1)
    zq_15 = Brighter_Transformation(img,1.5)
    zq_18 = Brighter_Transformation(img,1.8)
    zq_20 = Brighter_Transformation(img,2.0)
    zq_25 = Brighter_Transformation(img,2.5)

    #减弱0.9、0.8、0.5
    jr_09 = Darker_Transformation(img,0.9)
    jr_08 = Darker_Transformation(img,0.8)
    jr_07 = Darker_Transformation(img,0.7)

    """
    #显示图像
    titles = ['Source', 'ZQ1.1', 'ZQ1.5', 'ZQ1.8', 'ZQ2.0', 'ZQ2.5', 'JR0.9', 'JR0.8', 'JR0.7']
    images = [img, zq_11, zq_15, zq_18, zq_20, zq_25, jr_09, jr_08, jr_07]
    for i in range(9):
       plt.subplot(3,3,i+1), plt.imshow(images[i], 'gray')
       plt.title(titles[i])
       plt.xticks([]),plt.yticks([])
    plt.show()
    """
    
    #保存图像
    cv2.imwrite(img_path[0:-4] + '_zq_11.png', zq_11)
    cv2.imwrite(img_path[0:-4] + '_zq_15.png', zq_15)
    cv2.imwrite(img_path[0:-4] + '_zq_18.png', zq_18)
    cv2.imwrite(img_path[0:-4] + '_zq_20.png', zq_20)
    cv2.imwrite(img_path[0:-4] + '_zq_25.png', zq_25)
    cv2.imwrite(img_path[0:-4] + '_jr_09.png', jr_09)
    cv2.imwrite(img_path[0:-4] + '_jr_08.png', jr_08)
    cv2.imwrite(img_path[0:-4] + '_jr_07.png', jr_07)
    
#-----------------------------------------------------------------------
#颜色通道变换
def Channel_Transformation(img,img_path):
    rows, cols, channel = img.shape
    img = Brighter_Transformation(img,1.5)  #边缘增强
    color_map = [
        cv2.COLORMAP_AUTUMN,
        cv2.COLORMAP_BONE,
        cv2.COLORMAP_JET,
        cv2.COLORMAP_WINTER,
        cv2.COLORMAP_PARULA,
        cv2.COLORMAP_OCEAN,
        cv2.COLORMAP_SUMMER,
        cv2.COLORMAP_SPRING,
        cv2.COLORMAP_COOL,
        cv2.COLORMAP_PINK,
        cv2.COLORMAP_HOT,
        cv2.COLORMAP_PARULA,
        cv2.COLORMAP_MAGMA,
        cv2.COLORMAP_INFERNO,
        cv2.COLORMAP_PLASMA,
        cv2.COLORMAP_TWILIGHT,
        cv2.COLORMAP_TWILIGHT_SHIFTED
    ]

    rgb_img_01 = cv2.applyColorMap(img, color_map[0])
    rgb_img_02 = cv2.applyColorMap(img, color_map[1])
    rgb_img_03 = cv2.applyColorMap(img, color_map[9])
    rgb_img_04 = cv2.applyColorMap(img, color_map[3])
    rgb_img_05 = cv2.applyColorMap(img, color_map[13])
    rgb_img_06 = cv2.applyColorMap(img, color_map[5])
    rgb_img_07 = cv2.applyColorMap(img, color_map[12])
    rgb_img_08 = cv2.applyColorMap(img, color_map[10])

    # 通道分离
    b = cv2.split(img)[0]
    g = np.zeros((rows,cols), dtype=img.dtype)
    r = np.zeros((rows,cols), dtype=img.dtype)
    mb = cv2.merge([b, g, r])

    g = cv2.split(img)[1]
    b = np.zeros((rows,cols), dtype=img.dtype)
    r = np.zeros((rows,cols), dtype=img.dtype)
    mg = cv2.merge([b, g, r])

    r = cv2.split(img)[2]
    b = np.zeros((rows,cols), dtype=img.dtype)
    g = np.zeros((rows,cols), dtype=img.dtype)
    mr = cv2.merge([b, g, r])
    
    """
    #显示图像
    titles = ['Source', 'RGB-1', 'RGB-2', 'RGB-3', 'RGB-4',
              'RGB-5', 'RGB-6', 'RGB-7', 'RGB-8', 'B', 'G', 'R']
    images = [img, rgb_img_01, rgb_img_02, rgb_img_03, rgb_img_04,
              rgb_img_05, rgb_img_06, rgb_img_07, rgb_img_08, mb, mg, mr]
    for i in range(12):
       plt.subplot(4,3,i+1), plt.imshow(images[i], 'gray')
       plt.title(titles[i])
       plt.xticks([]),plt.yticks([])
    plt.show()
    """

    #保存图像
    cv2.imwrite(img_path[0:-4] + '_rgb_img_01.png', rgb_img_01)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_02.png', rgb_img_02)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_03.png', rgb_img_03)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_04.png', rgb_img_04)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_05.png', rgb_img_05)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_06.png', rgb_img_06)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_07.png', rgb_img_07)
    cv2.imwrite(img_path[0:-4] + '_rgb_img_08.png', rgb_img_08)
    cv2.imwrite(img_path[0:-4] + '_mb.png', mb)
    cv2.imwrite(img_path[0:-4] + '_mg.png', mg)
    cv2.imwrite(img_path[0:-4] + '_mr.png', mr)

#-----------------------------------------------------------------------
#添加高斯噪声和椒盐噪声
def GaussianNoise(img, percetage):
    gn = img.copy()
    w = img.shape[1]
    h = img.shape[0]
    G_NoiseNum = int(percetage * img.shape[0] * img.shape[1])
    for i in range(G_NoiseNum):
        lx = np.random.randint(0, h)
        ly = np.random.randint(0, w)
        gn[lx][ly][np.random.randint(3)] = np.random.randn(1)[0]
    return gn

def SaltNoise(img, percetage):
    sn = img.copy()
    SP_NoiseNum = int(percetage * img.shape[0] * img.shape[1])
    for i in range(SP_NoiseNum):
        randR = np.random.randint(0, img.shape[0] - 1)
        randG = np.random.randint(0, img.shape[1] - 1)
        randB = np.random.randint(0, 3)
        if np.random.randint(0, 1) == 0:
            sn[randR, randG, randB] = 0
        else:
            sn[randR, randG, randB] = 255
    return sn

def Gaussian_Salt_Noise(img,img_path):
    rows, cols, channel = img.shape
    img = Brighter_Transformation(img,1.5)  #边缘增强

    #高斯噪声
    gn_005 = GaussianNoise(img, 0.05)
    gn_010 = GaussianNoise(img, 0.10)
    gn_015 = GaussianNoise(img, 0.15)
    gn_020 = GaussianNoise(img, 0.20)

    #椒盐噪声
    sn_005 = SaltNoise(img, 0.05)
    sn_010 = SaltNoise(img, 0.10)
    sn_015 = SaltNoise(img, 0.15)
    sn_020 = SaltNoise(img, 0.20)

    """
    #显示图像
    titles = ['Source', 'Gaussian-0.05', 'Gaussian-0.10', 'Gaussian-0.15', 'Gaussian-0.20',
              'Salt-0.05', 'Salt-0.10', 'Salt-0.15', 'Salt-0.20']
    images = [img, gn_005, gn_010, gn_015, gn_020, sn_005, sn_010, sn_015, sn_020]
    for i in range(9):
       plt.subplot(3,3,i+1), plt.imshow(images[i], 'gray')
       plt.title(titles[i])
       plt.xticks([]),plt.yticks([])
    plt.show()
    """
    
    #保存图像
    cv2.imwrite(img_path[0:-4] + '_gn_005.png', gn_005)
    cv2.imwrite(img_path[0:-4] + '_gn_010.png', gn_010)
    cv2.imwrite(img_path[0:-4] + '_gn_015.png', gn_015)
    cv2.imwrite(img_path[0:-4] + '_gn_020.png', gn_020)
    cv2.imwrite(img_path[0:-4] + '_sn_005.png', sn_005)
    cv2.imwrite(img_path[0:-4] + '_sn_010.png', sn_010)
    cv2.imwrite(img_path[0:-4] + '_sn_015.png', sn_015)
    cv2.imwrite(img_path[0:-4] + '_sn_020.png', sn_020)

#-----------------------------------------------------------------------
#模拟怀旧和噪声添加
def Salt(img, num):
    wn = img.copy()
    rows, cols, chn = wn.shape
    for i in range(num):
        x = np.random.randint(0, rows)
        y = np.random.randint(0, cols)    
        wn[x,y,:] = 210
    return wn

def Fog_Noise(img, percetage):
    mask_img = img.copy()
    mask_img[:, :] = (166, 178, 180)  #雾的颜色 (146,182,213)
    
    #调整雾的浓度 round(random.uniform(0.03, 0.28), 2)
    res = cv2.addWeighted(img, percetage, mask_img, 1-percetage, 0) 
    return res

def Fog_Salt_Noise(img,img_path):
    rows, cols, channel = img.shape
    img = Brighter_Transformation(img,1.5)  #边缘增强

    #白点噪声
    wn_100 = Salt(img, 100)
    wn_150 = Salt(img, 150)
    wn_200 = Salt(img, 200)
    wn_250 = Salt(img, 250)

    #模拟怀旧
    fog_06 = Fog_Noise(img, 0.6)
    fog_07 = Fog_Noise(img, 0.7)
    fog_08 = Fog_Noise(img, 0.8)
    fog_09 = Fog_Noise(img, 0.9)

    """
    #显示图像
    titles = ['Source', 'wn-100', 'wn-150', 'wn-200', 'wn-250',
              'fog_06', 'fog_07', 'fog_08', 'fog_09']
    images = [img, wn_100, wn_150, wn_200, wn_250,
              fog_06, fog_07, fog_08, fog_09]
    for i in range(9):
       plt.subplot(3,3 ,i+1), plt.imshow(images[i], 'gray')
       plt.title(titles[i])
       plt.xticks([]),plt.yticks([])
    plt.show()
    """

    #保存图像
    cv2.imwrite(img_path[0:-4] + '_wn_100.png', wn_100)
    cv2.imwrite(img_path[0:-4] + '_wn_150.png', wn_150)
    cv2.imwrite(img_path[0:-4] + '_wn_200.png', wn_200)
    cv2.imwrite(img_path[0:-4] + '_wn_250.png', wn_250)
    cv2.imwrite(img_path[0:-4] + '_fog_06.png', fog_06)
    cv2.imwrite(img_path[0:-4] + '_fog_07.png', fog_07)
    cv2.imwrite(img_path[0:-4] + '_fog_08.png', fog_08)
    cv2.imwrite(img_path[0:-4] + '_fog_09.png', fog_09)

#-----------------------------------------------------------------------
#读取指定文件夹下的所有图像
def main():
    file_path = "data"
    for img_name in os.listdir(file_path):
        img_path = file_path + "\\" + img_name
        res_path = "data_add" + "\\" + img_name
        img = cv2.imread(img_path)

        #1.几何变换-镜像、翻转、旋转、缩放
        JH_Transformation(img,res_path)

        #2.亮度变换-增强、减弱
        LD_Transformation(img,res_path)

        #3.颜色通道变换
        Channel_Transformation(img,res_path)

        #4.添加高斯噪声和椒盐噪声
        Gaussian_Salt_Noise(img,res_path)

        #5.模拟怀旧和噪声添加
        Fog_Salt_Noise(img,res_path)
        
if __name__ == "__main__":
    main()

最终结果如下图所示,加原图共5280张图像。

后续可以按照同水族文字进行划分,并生成对应的训练集、测试集和验证集。


六.如何用GAN生成图像?

建议读者先自行尝试,结合作者前文GAN的博客,后面有时间我也会详细撰写一篇文章。

  • [Python图像识别] 四十九.图像生成之什么是生成对抗网络GAN?基础原理和代码普及

七.总结

写到这里,这篇文章就介绍结束了,希望对您有所帮助,也希望大家多多关注非物质文化遗产,包括水族文字,作者多年致力于利用AI技术保护和抢救濒危少数民族文字和语音,典型的是水书、侗族大歌、清水江文献古籍等。后续也会陆续开源相关代码和文章,靠一两个人真心挺难的,但贵在喜欢,贵在有趣,尽管每年只能前进一点点,但趴着也要前行,希望能为家乡贡献一丝丝力量,加油!感恩同行,感兴趣的也希望能一起交流。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-12-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 娜璋AI安全之家 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.什么是水书
  • 二.数据集构造
  • 三.数据增强
    • 1.什么是数据增强
      • 2.几何变换增强数据
        • 3.亮度变换增强数据
          • 4.颜色通道变换增强数据
            • 5.高斯噪声和椒盐噪声
              • 6.模拟怀旧和噪声添加
              • 五.完整代码
              • 六.如何用GAN生成图像?
              • 七.总结
              相关产品与服务
              图像识别
              腾讯云图像识别基于深度学习等人工智能技术,提供车辆,物体及场景等检测和识别服务, 已上线产品子功能包含车辆识别,商品识别,宠物识别,文件封识别等,更多功能接口敬请期待。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档