记录几段常用的图像处理python代码
非原创,基本都是把网上代码修修改改,增加了批处理等输入输出

图像处理相关

图像叠加

将某目录下两张命名一致的jpg和png图像按照一定权重叠加,叠加后图片输出在当前目录下

import cv2
import numpy as np
import os

# 需要输入图像的路径
path = "../eval"
for _image in os.listdir(path):
    if _image.split('.')[1] == "jpg":

        # 将同名的jpg和png文件进行叠加
        image_jpg = os.path.join(path, _image)
        _image_png = _image.split('.')[0] + ".png"
        image_png = os.path.join(path, _image_png)

        img_a = cv2.imread(image_jpg)
        img_b = cv2.imread(image_png)
        # 图像叠加权重
        weight = 0.4
        img_a = cv2.resize(img_a, (img_b.shape[1], img_b.shape[0]))

        img_c = weight * img_b + (1 - weight) * img_a
        img_c = img_c.astype(np.uint8)
        img_c = np.clip(img_c, 0, 255)
        # 文件名前加result,输出在本目录下
        cv2.imwrite("result" + _image_png, img_c)

求路径下所有图像的平均图

import cv2
import numpy as np
import os

# 需要输入图像的路径,需保证路径下所有图像尺度一致
path = "./1/"
count = 1
img_b = None
for _image in os.listdir(path):
    print(_image)
    image_jpg = os.path.join(path, _image)

    img_a = cv2.imread(image_jpg)
    img_a = img_a.astype(np.float32)
    if img_b is None:
        img_b = img_a
        continue

    img_b = img_b + img_a
    count = count + 1

img_b = img_b / count
img_b = img_b.astype(np.uint8)
img_b = np.clip(img_b, 0, 255)
# 输出在本目录下
cv2.imwrite("result.png", img_b)

批量颜色替换

将路径下的图片的某几种指定颜色替换为另外几种指定颜色并输出

from PIL import Image
import os
import numpy as np
import cv2


def replace_color(img, src_clr, dst_clr):
    ''' 通过矩阵操作颜色替换程序
    @param	img:	图像矩阵
    @param	src_clr:	需要替换的颜色(r,g,b)
    @param	dst_clr:	目标颜色		(r,g,b)
    @return				替换后的图像矩阵
    '''


    img_arr = np.asarray(img, dtype=np.double)

    # 分离通道
    r_img = img_arr[:, :, 0].copy()
    g_img = img_arr[:, :, 1].copy()
    b_img = img_arr[:, :, 2].copy()

    # 编码
    img = r_img * 256 * 256 + g_img * 256 + b_img
    src_color = src_clr[0] * 256 * 256 + src_clr[1] * 256 + src_clr[2]

    # 索引并替换颜色
    r_img[img == src_color] = dst_clr[0]
    g_img[img == src_color] = dst_clr[1]
    b_img[img == src_color] = dst_clr[2]

    # 合并通道
    dst_img = np.array([r_img, g_img, b_img], dtype=np.uint8)
    # 将数据转换为图像数据(h,w,c)
    dst_img = dst_img.transpose(1, 2, 0)

    return dst_img

base_path = './gtROI_trainvaltest/gtFine/test/raw/'
image_dir = os.listdir(base_path)
for img in image_dir:
    print(base_path+img)
    img_path = base_path+img
    img = Image.open(img_path).convert('RGB')
    #res_img = img.copy()

    # change color(1,1,1) to (128,0,0)
    # change color(2,2,2) to (0,128,0)
    res_img = replace_color(img, (1, 1, 1), (0, 0, 0))
    #res_img = replace_color(res_img, (2, 2, 2), (0, 128, 0))

    #是否转为灰度图
    res_img = cv2.cvtColor(res_img, cv2.COLOR_BGR2GRAY)

    res_img = Image.fromarray(res_img)
    res_img.save(img_path)

获取目录下所有图片像素值

from PIL import Image

import os


def checkColor(dir, file, recursion):
    files = os.listdir(dir)
    for name in files:
        fullname = os.path.join(dir, name)
        if (os.path.isdir(fullname) & recursion):
            checkColor(fullname, file, recursion)
        else:
            image = Image.open(fullname)
            file.write(name)
            file.write(str(image.getcolors()))
            file.write("\n")


def Test():
    dir = "./train"
    # txt文件名
    outfile = "train.txt"
    file = open(outfile, "w")
    checkColor(dir, file, 1)
    file.close()


Test()

利用mask提取感兴趣区域

import cv2
import numpy as np
import os
from PIL import Image


# 需要输入图像的路径
img_path = "./gtFine_trainvaltest/gtFine/val/raw/"
mask_path = "./mask_trainvaltest/mask/val/"
imgROI_path = "./gtROI_trainvaltest/gtFine/val/raw/"
for _image in os.listdir(img_path):
    if _image.split('.')[1] == "png":
        print(_image)
        # 将同名的图片和mask进行按位与
        img_path_ = os.path.join(img_path, _image)
        mask_path_ = os.path.join(mask_path, _image)

        img = cv2.imread(img_path_)
        mask = cv2.imread(mask_path_, cv2.IMREAD_GRAYSCALE)
        imageROI = cv2.bitwise_and(img, img, mask=mask)
        # 是否转为灰度图
        # imageROI = cv2.cvtColor(imageROI, cv2.COLOR_BGR2GRAY)
        imageROI = cv2.cvtColor(imageROI, cv2.COLOR_BGR2RGB)
        imageROI = Image.fromarray(imageROI)
        if not os.path.exists(imgROI_path):
            os.makedirs(imgROI_path)
        imageROI.save(imgROI_path+_image)


计算图像数据集的均值和方差(mean, std)用于transforms.Normalize()标准化

from torchvision.datasets import ImageFolder
import torch
from torchvision import transforms

def getStat(train_data):
    '''
    Compute mean and variance for training data
    :param train_data: 自定义类Dataset(或ImageFolder即可)
    :return: (mean, std)
    '''
    print('Compute mean and variance for training data.')
    print(len(train_data))
    train_loader = torch.utils.data.DataLoader(
        train_data, batch_size=1, shuffle=False, num_workers=0,
        pin_memory=True)
    mean = torch.zeros(3)
    std = torch.zeros(3)
    for X, _ in train_loader:
        for d in range(3):
            mean[d] += X[:, d, :, :].mean()
            std[d] += X[:, d, :, :].std()
    mean.div_(len(train_data))
    std.div_(len(train_data))
    return list(mean.numpy()), list(std.numpy())
 
if __name__ == '__main__':
	# root路径应为图片文件夹的上一层目录
    train_dataset = ImageFolder(root='../data/', transform=transforms.ToTensor())
    print(getStat(train_dataset))


孔洞填充及膨胀腐蚀操作

from PIL import Image
import os
import numpy as np
import cv2

img_path = './mask/train/'
result_path = './mask_result/train/'

# 先采用开运算去除小的噪点 然后膨胀 最后使用孔洞填充

# 孔洞填充
def im_fill(imgray):
    # 原图取补得到MASK图像
    mask = 255 - imgray

    # 构造Marker图像
    marker = np.zeros_like(imgray)
    marker[0, :] = 255
    marker[-1, :] = 255
    marker[:, 0] = 255
    marker[:, -1] = 255
    marker_0 = marker.copy()

    # 形态学重建
    SE = cv2.getStructuringElement(shape=cv2.MORPH_CROSS, ksize=(3, 3))
    while True:
        marker_pre = marker
        dilation = cv2.dilate(marker, kernel=SE)
        marker = np.min((dilation, mask), axis=0)
        if (marker_pre == marker).all():
            break
    dst = 255 - marker
    return dst


if not os.path.exists(result_path):
    os.makedirs(result_path)

for _image in os.listdir(img_path):
    print(_image)
    img_path_ = os.path.join(img_path, _image)
    img = cv2.imread(img_path_)

    # Use closing operate
    # closing_kernel = np.ones((20, 20), np.uint8)
    # img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, closing_kernel, iterations=2)
    # img = np.hstack((img, closing))

    # Use opening operate
    opening_kernel = np.ones((10, 10), np.uint8)
    img = cv2.morphologyEx(img, cv2.MORPH_OPEN, opening_kernel, iterations=1)
    # img = np.hstack((img, opening))

    # Use dilate operate
    dilate_kernel = np.ones((60, 60), np.uint8)
    img = cv2.dilate(img, dilate_kernel, iterations=1)

    img = im_fill(img)

    res_img = Image.fromarray(img)
    res_img.save(result_path + _image)


二值图求差并计算比例

import cv2
import numpy as np
import os
from PIL import Image

# 需要输入图像的路径
img_path = "./gtFine/train/raw/"
mask_path = "./mask/train/"
imgROI_path = "./diff/train/"

if not os.path.exists(imgROI_path):
    os.makedirs(imgROI_path)

sum = 0
count = 0
for _image in os.listdir(img_path):
    if _image.split('.')[1] == "png":
        print(_image)
        # 将同名的图片和mask相减
        img_path_ = os.path.join(img_path, _image)
        portion = os.path.splitext(_image)
        #mask_name = portion[0] + "_color" + portion[1]
        mask_name = portion[0] + portion[1]
        mask_path_ = os.path.join(mask_path, mask_name)

        img = cv2.imread(img_path_)
        mask = cv2.imread(mask_path_)

        result1 = cv2.subtract(img, mask)
        result2 = cv2.subtract(mask, img)
        result = cv2.add(result1, result2)
        result = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)

        color = np.where(result == 255)[0].shape[0]
        pixel_sum = result.shape[0] * result.shape[1]

        sum += color / pixel_sum
        count += 1

        result = Image.fromarray(result)
        result.save(imgROI_path + _image)

print(1-sum/count)

图像文件名相关

从文件夹中随机选取一定数量的文件

import os
import random
import shutil


def moveFile(fileDir, trainDir):
    pathDir = os.listdir(fileDir)  # 取图片的原始路径
    filenumber = len(pathDir)
    rate1 = 0.1  # 自定义抽取文件的比例,比方说100张抽80张,那就是0.8
    picknumber1 = int(filenumber * rate1)  # 按照rate比例从文件夹中取一定数量的文件
    sample1 = random.sample(pathDir, picknumber1)  # 随机选取picknumber数量的样本
    print(sample1)
    for name in sample1:
        shutil.copy(fileDir + "/" + name, trainDir + "/" + name)
    return


if __name__ == '__main__':
    fileDir = "./raw"
    trainDir = './chose'
    moveFile(fileDir, trainDir)


文件名批量修改

import os

def changeName(dir):
    files = os.listdir(dir)
    for name in files:
        portion = os.path.splitext(name)
        newname = portion[0] + "_gtFine_color" + portion[1]
        print(newname)
        fullname = os.path.join(dir, name)
        fullnewname = os.path.join(dir, newname)
        os.rename(fullname, fullnewname)

def Test():
    dir = "./datasets/cityscapes/gtFine/test/raw/"
    changeName(dir)

Test()

批量复制

根据txt文档内的文件名将某一路径中的图片复制到另一指定路径

import shutil
import os

# 文件旧路径
oldpath = './oldpath/'
# txt路径
file = open('./file.txt', 'r')
# 文件新路径
newpath = './newpath/'
num1 = 0
for line in file.readlines():
    num1 += 1
    message = line.split('\n')
    num = message[0]
    oldpath_pic = oldpath + num
    os.makedirs(os.path.dirname(newpath), exist_ok=True)
    shutil.copy(oldpath_pic, newpath)
file.close()
print(num1)

路径下文件生成名称txt

遍历指定路径下文件,将其文件名生成txt

import os


def ListFilesToTxt(dir, file, wildcard, recursion):
    exts = wildcard.split(".")
    files = os.listdir(dir)
    for name in files:
        fullname = os.path.join(dir, name)
        if (os.path.isdir(fullname) & recursion):
            ListFilesToTxt(fullname, file, wildcard, recursion)
        else:
            for ext in exts:
                if (name.endswith(ext)):
                    file.write(name.split(".")[0] + "\n")
                    break


def Test():
    dir = "."
    # txt文件名
    outfile = "val.txt"
    wildcard = "jpg"
    file = open(outfile, "w")
    if not file:
        print("cannot open the file %s for writing" % outfile)
    ListFilesToTxt(dir, file, wildcard, 1)
    file.close()


Test()