水下图像评价指标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.