水下图像评价指标MSE,PSNR.SSIM,UCIQE,UIQM代码分享

水下图像评价指标MSE、PSNR、SSIM、UCIQE、UIQM,可分为全参考评价指标和无参考评价指标。全参考评价指标需要原始图像作为基准,无参考评价指标无需先验知识,适用于无法获取参考图像的情况。

  • 全参考评价指标

MSE(均方误差)

衡量原始图像与处理后图像之间的均方误差。计算公式为:

其中,I 和 K 分别表示原始图像和处理后的图像,m 和 n 是图像的行数和列数。MSE 值越低,说明图像质量越好。

MSE代码如下:

import cv2
import numpy as np
import os


def calculate_mse(img1, img2):
    img1, img2 = img1.astype(np.float64), img2.astype(np.float64)
    mse = np.mean((img1 - img2) ** 2)
    return mse


# 定义图像文件夹路径
folder1 = 'GT'
folder2 = 'input'

# 获取两个文件夹中的所有图像文件
files1 = [f for f in os.listdir(folder1) if os.path.isfile(os.path.join(folder1, f))]
files2 = [f for f in os.listdir(folder2) if os.path.isfile(os.path.join(folder2, f))]

# 确保两个文件夹中的图像数量相同
assert len(files1) == len(files2), "两个文件夹中的图像数量必须相同"

# 初始化MSE总和
total_mse = 0

# 遍历两个文件夹中的图像
for f1, f2 in zip(files1, files2):
    # 读取图像
    img1 = cv2.imread(os.path.join(folder1, f1))
    img2 = cv2.imread(os.path.join(folder2, f2))

    # 确保图像具有相同的形状
    if img1.shape != img2.shape:
        img1 = cv2.resize(img1, (img2.shape[1], img2.shape[0]))

    # 计算MSE值
    mse_value = calculate_mse(img1, img2)

    # 累加MSE值
    total_mse += mse_value

    # 打印每对图像的MSE值
    print(f"图片 {f1} 和 {f2} 的MSE值为: {mse_value}")

# 计算并打印MSE平均值
avg_mse = total_mse / len(files1)
print("所有图片的MSE平均值为:", avg_mse)

PSNR(峰值信噪比)

基于 MSE 计算,反映图像压缩或传输中的质量损失。计算公式为:

其中,MAXI​ 是图像的最大像素值。PSNR 值越高,说明图像质量越好。

PSNR代码如下:

import cv2
import numpy as np
import os


def compare_psnr(img1, img2, maxvalue):
    img1, img2 = img1.astype(np.float64), img2.astype(np.float64)
    mse = np.mean((img1 - img2) ** 2)
    return 10 * np.log10((maxvalue ** 2) / mse)


# 定义图像文件夹路径
folder1 = 'GT'
folder2 = 'input'

# 获取两个文件夹中的所有图像文件
files1 = [f for f in os.listdir(folder1) if os.path.isfile(os.path.join(folder1, f))]
files2 = [f for f in os.listdir(folder2) if os.path.isfile(os.path.join(folder2, f))]

# 确保两个文件夹中的图像数量相同
assert len(files1) == len(files2), "两个文件夹中的图像数量必须相同"

# 初始化PSNR总和
total_psnr = 0

# 遍历两个文件夹中的图像
for f1, f2 in zip(files1, files2):
    # 读取图像
    img1 = cv2.imread(os.path.join(folder1, f1))
    img2 = cv2.imread(os.path.join(folder2, f2))

    # 确保图像具有相同的形状
    img1 = cv2.resize(img1, (img2.shape[1], img2.shape[0]))

    # 计算PSNR值
    psnr_value = compare_psnr(img1, img2, 255)

    # 累加PSNR值
    total_psnr += psnr_value

    # 打印每对图像的PSNR值
    print(f"图片 {f1} 和 {f2} 的PSNR值为: {psnr_value}")

# 计算并打印PSNR平均值
avg_psnr = total_psnr / len(files1)
print("所有图片的PSNR平均值为:", avg_psnr)

SSIM(结构相似性指标)

衡量两幅图像的结构相似度,考虑图像的亮度、对比度和结构信息。计算公式为:

其中,x 和 y 是两幅图像,μx​ 和 μy​ 是均值,σx​ 和 σy​ 是标准差,σxy​ 是协方差,C1​ 和 C2​ 是常数。SSIM 值越接近 1,说明图像质量越好。

SSIM代码如下:

from skimage.measure import compare_ssim
import cv2
import os
#import numpy as np

# 定义图像文件夹路径
folder1 = 'GT'
folder2 = 'input'

# 获取两个文件夹中的所有图像文件
files1 = {f: os.path.join(folder1, f) for f in os.listdir(folder1) if f.lower().endswith(('.png', '.jpg', '.jpeg'))}
files2 = {f: os.path.join(folder2, f) for f in os.listdir(folder2) if f.lower().endswith(('.png', '.jpg', '.jpeg'))}

# 确保两个文件夹中的图像数量相同,并且文件是成对的
assert len(files1) == len(files2), "两个文件夹中的图像数量必须相同"
assert set(files1.keys()) == set(files2.keys()), "两个文件夹中的图像文件必须一一对应"

# 初始化SSIM总和
total_ssim = 0.0
num_images = len(files1)

# 遍历两个文件夹中的图像
for filename in files1:
    # 读取图像
    img1 = cv2.imread(files1[filename])
    img2 = cv2.imread(files2[filename])

    # 确保图像是三通道的
    if len(img1.shape) == 2:  # 灰度图
        img1 = cv2.cvtColor(img1, cv2.COLOR_GRAY2BGR)
    if len(img2.shape) == 2:
        img2 = cv2.cvtColor(img2, cv2.COLOR_GRAY2BGR)

    # 计算SSIM值
    ssim_value = compare_ssim(img1, img2, win_size=11, data_range=255, multichannel=True)

    # 累加SSIM值
    total_ssim += ssim_value

    # 打印每对图像的SSIM值
    print(f"图片 {filename} 的SSIM值为: {ssim_value}")

# 计算并打印SSIM平均值
avg_ssim = total_ssim / num_images
print("所有图片的SSIM平均值为:", avg_ssim)
  • 无参考评价指标

UCIQE(水下图像质量评价指数)

通过色度、饱和度和对比度的线性组合来量化水下图像的质量。计算公式为

其中,σc​ 是色度的标准差,conl​ 是亮度对比,μc​ 是饱和度的平均值,c1​=0.4680,c2​=0.2745,c3​=0.2576。UCIQE 值越高,表明图像在色彩、饱和度和对比度之间具有更好的平衡。

UCIQE代码如下:

import cv2
import numpy as np
import os


# 定义处理单张图片的函数
def process_image(image_path):
    image = cv2.imread(image_path)  # 读取图片
    if image is None:
        print(f"无法读取图片: {image_path}")
        return None

    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)  # RGB转为HSV
    H, S, V = cv2.split(hsv)

    delta = np.std(H) / 180  # 色度的标准差
    mu = np.mean(S) / 255  # 饱和度的平均值

    # 求亮度对比值
    n, m = np.shape(V)
    number = np.floor(n * m / 100).astype(np.int16)  # 所需像素的个数
    v = V.flatten() / 255
    v.sort()
    bottom = np.sum(v[:number]) / number
    v = -v
    v.sort()
    v = -v
    top = np.sum(v[:number]) / number
    conl = top - bottom

    uciqe = 0.4680 * delta + 0.2745 * conl + 0.2576 * mu

    return delta, conl, mu, uciqe


# 定义主函数,处理文件夹中的所有图片
def process_folder(folder_path):
    results = {}  # 用于存储每张图片的结果

    # 遍历文件夹中的所有文件
    for filename in os.listdir(folder_path):
        file_path = os.path.join(folder_path, filename)

        # 检查文件是否为图片
        if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.tiff')):
            # 处理图片
            result = process_image(file_path)
            if result is not None:
                results[filename] = result
              #  print(f"处理完成: {filename}")
             #   print(f"Delta: {result[0]}, Conl: {result[1]}, Mu: {result[2]}, UCIQE: {result[3]}")
            else:
              print(f"跳过文件: {filename}")

    return results


# 设置文件夹路径
folder_path = r"GT"

# 处理文件夹中的所有图片
results = process_folder(folder_path)

# 打印所有结果
for filename, result in results.items():
    print(f"{filename}:")
    print(f"  Delta: {result[0]}")
    print(f"  Conl: {result[1]}")
    print(f"  Mu: {result[2]}")
    print(f"  UCIQE: {result[3]}\n")

UIQM(水下图像质量测量)

综合考虑图像的色彩、清晰度和对比度三个维度。计算公式为:

其中,UICM 是色彩测量指标,UISM 是清晰度测量指标,UIConM 是对比度测量指标,c1​=0.0282,c2​=0.2953,c3​=3.5753。UIQM 值越高,说明越符合人眼的视觉感知。

UIQM代码如下:

import numpy as np
from scipy.ndimage import convolve
from skimage.transform import resize
from matplotlib.image import imread
import os


# 定义 UICM 函数
def UICM(img):
    # 将图像的 RGB 通道分离并转换为浮点类型
    R = np.double(img[:, :, 0])
    G = np.double(img[:, :, 1])
    B = np.double(img[:, :, 2])

    # 计算 RG 和 YB 通道
    RG = R - G
    YB = (R + G) / 2 - B

    # 获取图像的像素总数
    K = RG.size

    # 处理 RG 通道
    RG1 = RG.flatten()  # 将二维数组展平为一维
    RG1 = np.sort(RG1)  # 对数组进行排序
    alphaL = 0.1
    alphaR = 0.1
    # 截取中间部分的值
    RG1 = RG1[int(alphaL * K): int(K * (1 - alphaR))]
    N = K * (1 - alphaL - alphaR)
    meanRG = np.sum(RG1) / N  # 计算均值
    deltaRG = np.sqrt(np.sum((RG1 - meanRG) ** 2) / N)  # 计算标准差

    # 处理 YB 通道
    YB1 = YB.flatten()  # 将二维数组展平为一维
    YB1 = np.sort(YB1)  # 对数组进行排序
    alphaL = 0.1
    alphaR = 0.1
    # 截取中间部分的值
    YB1 = YB1[int(alphaL * K): int(K * (1 - alphaR))]
    N = K * (1 - alphaL - alphaR)
    meanYB = np.sum(YB1) / N  # 计算均值
    deltaYB = np.sqrt(np.sum((YB1 - meanYB) ** 2) / N)  # 计算标准差

    # 计算 UICM
    uicm = -0.0268 * np.sqrt(meanRG ** 2 + meanYB ** 2) + 0.1586 * np.sqrt(deltaRG ** 2 + deltaYB ** 2)

    return uicm


# 定义 UISM 函数
def UISM(img):
    # 将图像的 RGB 通道分离并转换为浮点类型
    Ir = np.double(img[:, :, 0])
    Ig = np.double(img[:, :, 1])
    Ib = np.double(img[:, :, 2])

    # 定义 Sobel 梯度模板
    hx = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
    hy = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])

    # 计算每个通道的 Sobel 梯度
    SobelR = np.abs(convolve(Ir, hx, mode='reflect') + convolve(Ir, hy, mode='reflect'))
    SobelG = np.abs(convolve(Ig, hx, mode='reflect') + convolve(Ig, hy, mode='reflect'))
    SobelB = np.abs(convolve(Ib, hx, mode='reflect') + convolve(Ib, hy, mode='reflect'))

    patchsz = 5
    m, n = Ir.shape

    # 调整图像大小以匹配 patchsz
    if m % patchsz != 0 or n % patchsz != 0:
        new_m = m - (m % patchsz) + patchsz
        new_n = n - (n % patchsz) + patchsz
        SobelR = resize(SobelR, (new_m, new_n))
        SobelG = resize(SobelG, (new_m, new_n))
        SobelB = resize(SobelB, (new_m, new_n))

    m, n = SobelR.shape
    k1 = m // patchsz
    k2 = n // patchsz

    # 计算每个通道的 EME 值
    EMER = 0
    for i in range(0, m, patchsz):
        for j in range(0, n, patchsz):
            im = SobelR[i:i + patchsz, j:j + patchsz]
            if np.max(im) != 0 and np.min(im) != 0:
                EMER += np.log(np.max(im) / np.min(im))
    EMER = 2 / (k1 * k2) * np.abs(EMER)

    EMEG = 0
    for i in range(0, m, patchsz):
        for j in range(0, n, patchsz):
            im = SobelG[i:i + patchsz, j:j + patchsz]
            if np.max(im) != 0 and np.min(im) != 0:
                EMEG += np.log(np.max(im) / np.min(im))
    EMEG = 2 / (k1 * k2) * np.abs(EMEG)

    EMEB = 0
    for i in range(0, m, patchsz):
        for j in range(0, n, patchsz):
            im = SobelB[i:i + patchsz, j:j + patchsz]
            if np.max(im) != 0 and np.min(im) != 0:
                EMEB += np.log(np.max(im) / np.min(im))
    EMEB = 2 / (k1 * k2) * np.abs(EMEB)

    # 计算 UISM
    lambdaR = 0.299
    lambdaG = 0.587
    lambdaB = 0.114
    uism = lambdaR * EMER + lambdaG * EMEG + lambdaB * EMEB

    return uism


# 定义 UIConM 函数
def UIConM(img):
    # 将图像的 RGB 通道分离并转换为浮点类型
    R = np.double(img[:, :, 0])
    G = np.double(img[:, :, 1])
    B = np.double(img[:, :, 2])

    patchsz = 5
    m, n = R.shape

    # 调整图像大小以匹配 patchsz
    if m % patchsz != 0 or n % patchsz != 0:
        new_m = m - (m % patchsz) + patchsz
        new_n = n - (n % patchsz) + patchsz
        R = resize(R, (new_m, new_n))
        G = resize(G, (new_m, new_n))
        B = resize(B, (new_m, new_n))

    m, n = R.shape
    k1 = m // patchsz
    k2 = n // patchsz

    # 计算每个通道的 AMEE 值
    AMEER = 0
    for i in range(0, m, patchsz):
        for j in range(0, n, patchsz):
            im = R[i:i + patchsz, j:j + patchsz]
            Max = np.max(im)
            Min = np.min(im)
            if (Max != 0 or Min != 0) and Max != Min:
                AMEER += np.log((Max - Min) / (Max + Min)) * ((Max - Min) / (Max + Min))
    AMEER = 1 / (k1 * k2) * np.abs(AMEER)

    AMEEG = 0
    for i in range(0, m, patchsz):
        for j in range(0, n, patchsz):
            im = G[i:i + patchsz, j:j + patchsz]
            Max = np.max(im)
            Min = np.min(im)
            if (Max != 0 or Min != 0) and Max != Min:
                AMEEG += np.log((Max - Min) / (Max + Min)) * ((Max - Min) / (Max + Min))
    AMEEG = 1 / (k1 * k2) * np.abs(AMEEG)

    AMEEB = 0
    for i in range(0, m, patchsz):
        for j in range(0, n, patchsz):
            im = B[i:i + patchsz, j:j + patchsz]
            Max = np.max(im)
            Min = np.min(im)
            if (Max != 0 or Min != 0) and Max != Min:
                AMEEB += np.log((Max - Min) / (Max + Min)) * ((Max - Min) / (Max + Min))
    AMEEB = 1 / (k1 * k2) * np.abs(AMEEB)

    # 计算 UIConM
    uiconm = AMEER + AMEEG + AMEEB

    return uiconm


# 定义 UIQM 函数
def UIQM(image, c1=0.0282, c2=0.2953, c3=3.5753):
    uicm = UICM(image)
    uism = UISM(image)
    uiconm = UIConM(image)

    uiqm = c1 * uicm + c2 * uism + c3 * uiconm

    return uiqm


# 检测函数
def evaluate_image_quality(image_folder):
    image_files = [f for f in os.listdir(image_folder) if os.path.isfile(os.path.join(image_folder, f))]
    total_quality = 0

    for i in range(len(image_files)):
        # 确保文件是图像,而不是其他类型的文件(如 Thumbs.db)
        if not os.path.isdir(image_files[i]):
            # 读取当前图像文件
            img = imread(os.path.join(image_folder, image_files[i]))

            # 计算图像质量
            quality = UIQM(img)  # 假设 UIQM 是有效的图像质量评价函数

            # 累加质量评分
            total_quality += quality

            # 显示当前图像的质量和文件名
            print(f'Image {image_files[i]} quality score: {quality}')

    # 计算平均质量评分
    avg_quality = total_quality / len(image_files)

    # 显示平均质量评分信息
    print(f'所有图像的质量评价均值: {avg_quality}')


# 示例用法
if __name__ == "__main__":
    image_folder = 'djw37/ww'  # 替换为你的图像文件夹路径
    evaluate_image_quality(image_folder)

PS:笔者在阅读论文的时候发现不同作者的uiqm指标区间有很大的不同,有的在1上下,也有3-5之间的。笔者分享代码仅供参考。

uiqm论文:K. Panetta, C. Gao, and S. Agaian, “Human-visual-system-inspired underwater image quality measures,” IEEE J Oceanic Eng, vol. 41, no. 3, pp. 541-551, 2015, doi: 10.1109/JOE.2015.2469915.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值