Python:批量以一定概率使图片像素值里的每一位二进制数进行01跳变,并以原文件名保存

初学Python,毕设要求以一定概率对数据集里图片的每一个像素值的每一位二进制数进行01跳变,查找了许多资料后写了如下程序,运行速度比较慢,希望能有所帮助吧

有错误或者改进的地方还请指出

from skimage import io
import numpy as np
import os

def binToDec(binary):       #二进制转化为十进制int
    result = 0        #定义一个初始化变量,后续用于存储最终结果
    for i in range(len(binary)):
                      #利用for循环及切片从右至左依次取出,然后再用内置方法求2的次方
        result += int(binary[-(i + 1)]) * pow(2, i)
    return result

def jiaoyan(img):     #椒盐噪声
    rows,cols,dims = img.shape
    for i in range(5000):
        x = np.random.randint(0,rows)
        y = np.random.randint(0,cols)
        img[x,y,:] = 255
              
def Read_filename(path_name,have):      #目录下只有图片的话have为false,还有其他文件的话为true
    if have:
        name_list1 = os.listdir(path_name)    #读取所有文件名
        name_list1.sort()     #对读取的文件名进行排序
        name_list2 = [0]*len(name_list1)
        j=0
        for i in range(len(name_list1)):
            if name_list1[i].split('.',1)[1] == 'png':
                name_list2[j] = name_list1[i]    #如果扩展名为png,存入name_list2
                j=j+1
        name_list = [0]*j      #创建长度为j的list
        for i in range(j):     #目的是去掉多余的项
            name_list[i] = name_list2[i]
    else:
        name_list = os.listdir(path_name)
        name_list.sort()
    return(name_list)     
        
def Process(path_name,path,have,probability):
    name_list = Read_filename(path_name,have)
    coll = io.ImageCollection(path)
    for n in range(1):        #第一张图片
    #for n in range(len(coll))       #所有图片
        #coll[n][100:480,1:639,] = 255        #区域涂色
        #jiaoyan(coll[n])
        img = coll[n]
        rows,cols,dims = img.shape      #列,,通道(480,640,3)
        for k in range(dims):
            for i in range(rows):
                for j in range(cols):    #从0通道第一列第一行开始
                    a = bin(img[i,j,k]).replace('0b','')    #存入对应像素值str类型的二进制
                    b = np.zeros(len(a), dtype = np.uint8)    #因位数可能不同,创建长度为len(a)的Array of uint8,每个元素都为0
                    for m in range(len(a)):    #遍历每个二进制位
                        d = np.random.randint(0,100)    #随机产生[0,100)的整数
                        if d < probability:    #依概率使0变成1,或者使1变成0
                            b[m] = bin((int(a[m])+1)%2).replace('0b','')
                        else:    #有概率二进制位不变
                            b[m] = a[m]
                    img[i,j,k] = binToDec(b)    #计算像素值,覆盖原来的像素值
        io.imshow(img)
        io.imsave('E:/Temp/'+str(name_list[n]),img)    #以原文件名保存图像到E:/Temp下        
#a = "E:/Ubuntu/slambench2-master/datasets/TUM/freiburg1/rgbd_dataset_freiburg1_room.dir/rgbd_dataset_freiburg1_room/rgb"
a = "E:/Ubuntu/slambench2-master/datasets/ICL_NUIM/living_room_traj2_loop.dir"
#b = 'E:/Ubuntu/slambench2-master/datasets/TUM/freiburg1/rgbd_dataset_freiburg1_room.dir/rgbd_dataset_freiburg1_room/rgb/*.png'
b = 'E:/Ubuntu/slambench2-master/datasets/ICL_NUIM/living_room_traj2_loop.dir/*.png'

Process(a,b,1,50)

Anaconda Python3.7

程序挺简单的,解释一下加深记忆吧

首先是读取目录下所有文件名称,分两种情况:

1、当目录下的所有文件都是你要处理的图片时,如下图

在这里插入图片描述

name_list = os.listdir(path_name)  
name_list.sort()

这样Read_filename的返回值就是所有排过序的文件名称,放在一个list
通过下面这个函数把对应的名称赋给对应的图片,达到以原文件名保存的效果

io.imsave('E:/Temp/'+str(name_list[n]),img)

没找到有什么函数能直接处理图片并以原文件名保存,所以只能用批量重命名的办法达到这个效果
所以下面两个代码的排序方法必须一致,ImageCollection函数会自动排序。因为我的文件名称都是数字组成的,所以两个代码的排序应该是一致的

coll = io.ImageCollection(path)     #读取所有图片
name_list.sort()

2、当目录下不都是图片时,如下图

在这里插入图片描述

name_list1 = os.listdir(path_name)    #读取所有文件名
name_list1.sort()     #对读取的文件名进行排序
name_list2 = [0]*len(name_list1)
j=0
for i in range(len(name_list1)):
    if name_list1[i].split('.',1)[1] == 'png':
        name_list2[j] = name_list1[i]    #如果扩展名为png,存入name_list2
        j=j+1
name_list = [0]*j      #创建长度为j的list,从0到j-1,也就是j个数
for i in range(j):     #目的是去掉多余的项
    name_list[i] = name_list2[i]

name_list1放的是所有文件名,name_list2放的是扩展名为png的文件名,name_list是去掉多余项的name_list2,这里去不去都一样,多余的最后也不会用到
这里不清楚的是为什么这个程序读不出情况1时候的文件名?

果然写出来是有好处的,发现这个Read_filename完全是多余的……所以删掉

要想以原文件名保存,只需要把

io.imsave('E:/Temp/'+str(name_list[n]),img)

改为

io.imsave(coll.files[n],img)    #例:coll.files[0]=E:/Temp\cyberpunk2077_cdn_wallpaper.png

coll=ImageCollection(path)会把对应图像的完整路径存储在coll.files下,类型为list,所以直接赋给io.imsave的第一个参数就行了,处理完后会直接覆盖原图像
如果不想覆盖原图像,如下

io.imsave(coll.files[i].replace('Temp','Temp1'),img)    #会存到E:/Temp1\cyberpunk2077_cdn_wallpaper.png

然后是处理部分

知道rows,cols,dims = img.shape是什么意思后想法就很简单了,示例图片是640*480*3个像素值,存在包含3个二维Array of uint8的数组里(三维数组?),依次把每个像素值转化为二进制形式,处理完后直接覆盖原像素值

a = bin(img[i,j,k]).replace('0b','')   
b = np.zeros(len(a), dtype = np.uint8)

bin()可以把一个整数变为字符串类型的二进制数,如果不加replace('0b',''),输出是0bXXXXXX,b是长度和a一样的Array of uint8,b相当于一个介质,因为字符串类型不可以直接赋值
接下来一个for循环遍历b中的每一位二进制数,然后

d = np.random.randint(0,100)    #随机产生[0,100)的整数,不包含100
    if d < probability:

简单的几何概型,probability是多少,概率就是多少,放在最后一个for循环里,保证每一个二进制数跳变的几率是相互独立的

(int(a[m])+1)%2

简单的跳变方法,+1取余

END

放几个运行结果,分别是用10%,50%,100%概率的结果
此处用的是ICL-NUIM数据集
10%的概率
50%的概率
100%的概率
参考资料:
https://me.csdn.net/denny2015
https://www.cnblogs.com/ddpeng/p/11302368.html
https://blog.csdn.net/T1243_3/article/details/80170006?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task


版权声明:本文为CishYish原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。