即使现在有这么高级的质量评估方法:
https://mp.weixin.qq.com/s/77F6JlbLN6cFaU7vR4N0CA
本文写一些以前用的质量评估方法。
图像上色(Image Colorization)是计算机视觉中的一项重要任务,它将灰度图像转换为彩色图像。评估上色结果的质量是一个复杂问题,因为颜色不仅要逼真,还需要与图像内容语义相符。今天,我们将深入探讨几种常用的图像上色评估指标,从理论公式到代码实现,全面了解如何客观评估上色结果的质量。
评估图像上色质量通常需要多个指标,这些指标可以从不同角度衡量生成图像与真实图像的差异:
接下来,我们将详细介绍每个指标的原理、数学公式以及代码实现。
SSIM是一种衡量两幅图像结构相似度的指标。与MSE和PSNR等仅关注像素差异的指标不同,SSIM考虑了亮度、对比度和结构三个方面,更符合人类视觉感知系统。
SSIM指标通过以下公式计算:
其中:
python展开代码from skimage.metrics import structural_similarity as ssim
def calculate_ssim(img1, img2):
    """计算两幅图像之间的结构相似性指标"""
    return ssim(img1, img2, channel_axis=2, data_range=255)
SSIM取值范围为[-1, 1],值越接近1表示两幅图像结构越相似。对于图像上色任务,高SSIM值意味着生成的彩色图像保持了原始图像的结构特征。
PSNR是评估重建图像质量的常用指标,用于测量信号最大值与背景噪声之间的比率,通常以分贝(dB)表示。PSNR值越高,表示重建图像与原始图像越接近。
PSNR基于MSE计算,公式如下:
其中:
python展开代码from skimage.metrics import peak_signal_noise_ratio as psnr
def calculate_psnr(img1, img2):
    """计算两幅图像之间的峰值信噪比"""
    return psnr(img1, img2, data_range=255)
通常,PSNR值在20-40dB之间被视为可接受的图像质量。PSNR值越高,表示上色结果与真实彩色图像在像素级别上越接近。
MSE是最基本的图像差异度量方法,计算两幅图像对应像素差值的平方平均值。它直接反映像素差异的大小,但不考虑人类视觉感知。
其中:
python展开代码from skimage.metrics import mean_squared_error as mse
def calculate_mse(img1, img2):
    """计算两幅图像之间的均方误差"""
    return mse(img1, img2)
MSE值越小,表示上色结果与真实图像越接近。但需要注意的是,MSE对于视觉感知并不总是可靠的,因为人眼对不同类型的失真有不同的敏感度。
MAE计算两幅图像对应像素差的绝对值平均值,与MSE类似,但对异常值不那么敏感。
python展开代码import numpy as np
def calculate_mae(img1, img2):
    """计算两幅图像之间的平均绝对误差"""
    return np.mean(np.abs(img1.astype(np.float32) - img2.astype(np.float32)))
与MSE一样,MAE值越小表示上色结果越好。MAE和MSE都是像素级别的度量,但MAE对异常值的惩罚较轻。
对于图像上色任务,在LAB颜色空间中评估颜色准确性更为合适。LAB颜色空间的L通道表示亮度,a和b通道表示颜色信息。颜色误差专注于评估a和b通道的差异,忽略亮度差异。
其中 和 表示两幅图像在LAB颜色空间的a和b通道。
python展开代码import cv2
import numpy as np
def rgb2lab(rgb_image):
    """将RGB图像转换为LAB颜色空间"""
    lab_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2LAB)
    return lab_image
def calculate_color_accuracy(img1, img2):
    """计算LAB颜色空间ab通道的颜色准确性"""
    lab1 = rgb2lab(img1)
    lab2 = rgb2lab(img2)
    # 提取a和b通道
    ab1 = lab1[:, :, 1:3]
    ab2 = lab2[:, :, 1:3]
    # 计算颜色通道的平均绝对误差
    color_error = np.mean(np.abs(ab1.astype(np.float32) - ab2.astype(np.float32)))
    return color_error
颜色误差值越小,表示上色结果的颜色与真实图像越接近。由于这个指标专注于颜色差异,它对上色任务特别有意义。
感知相似度(Learned Perceptual Image Patch Similarity, LPIPS)是基于深度学习的图像质量评估指标,它利用深度神经网络提取的特征来评估图像的感知相似度,更接近人类的视觉感知。
LPIPS通过预训练的卷积神经网络(如AlexNet、VGG等)提取图像特征,然后计算这些特征之间的距离:
其中:
python展开代码import torch
import lpips
import torchvision.transforms as transforms
class LPIPS_Metric:
    def __init__(self, device='cuda' if torch.cuda.is_available() else 'cpu'):
        self.device = device
        self.model = lpips.LPIPS(net='alex').to(device)
        
    def calculate_lpips(self, img1, img2):
        """计算两幅图像之间的LPIPS感知距离"""
        # 将numpy转换为torch张量
        transform = transforms.ToTensor()
        img1_tensor = transform(img1).unsqueeze(0).to(self.device)
        img2_tensor = transform(img2).unsqueeze(0).to(self.device)
        
        # 归一化到[-1, 1]
        img1_tensor = img1_tensor * 2 - 1
        img2_tensor = img2_tensor * 2 - 1
        
        with torch.no_grad():
            distance = self.model(img1_tensor, img2_tensor)
        return distance.item()
LPIPS值越小,表示两幅图像在感知上越相似。LPIPS特别适合评估生成内容的质量,因为它能够抓住人类视觉系统关注的细节。
FID是评估生成图像质量的重要指标,特别适用于GAN等生成模型。它测量真实图像分布和生成图像分布之间的距离,使用预训练的Inception网络提取特征。
假设真实图像和生成图像的特征服从多元高斯分布,FID计算两个分布之间的距离:
其中:
python展开代码import torch
import numpy as np
from scipy import linalg
import torchvision.models as models
import torchvision.transforms as transforms
from PIL import Image
from tqdm import tqdm
class FID_Metric:
    def __init__(self, device='cuda' if torch.cuda.is_available() else 'cpu'):
        self.device = device
        self.model = models.inception_v3(pretrained=True).to(device)
        self.model.eval()
        
        # 移除分类器部分
        self.model.fc = torch.nn.Identity()
        
        # 设置图像变换
        self.transform = transforms.Compose([
            transforms.Resize((299, 299)),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
        ])
    
    def get_features(self, images_list):
        """从图像路径列表中提取特征"""
        features = []
        
        for img_path in tqdm(images_list, desc="提取特征"):
            img = Image.open(img_path).convert('RGB')
            img = self.transform(img).unsqueeze(0).to(self.device)
            
            with torch.no_grad():
                feat = self.model(img)
            
            features.append(feat.cpu().numpy())
            
        return np.concatenate(features, axis=0)
    
    def calculate_fid(self, real_images, fake_images):
        """计算真实图像和生成图像之间的FID距离"""
        real_features = self.get_features(real_images)
        fake_features = self.get_features(fake_images)
        
        # 计算均值和协方差
        mu1, sigma1 = real_features.mean(axis=0), np.cov(real_features, rowvar=False)
        mu2, sigma2 = fake_features.mean(axis=0), np.cov(fake_features, rowvar=False)
        
        # 计算FID
        diff = mu1 - mu2
        covmean, _ = linalg.sqrtm(sigma1.dot(sigma2), disp=False)
        
        if np.iscomplexobj(covmean):
            covmean = covmean.real
        
        fid = diff.dot(diff) + np.trace(sigma1) + np.trace(sigma2) - 2 * np.trace(covmean)
        return fid
FID值越小,表示生成图像分布与真实图像分布越接近。FID能够检测出生成内容的多样性和质量,是评估上色模型整体性能的重要指标。
在实际应用中,我们通常需要对大量图像对进行评估。下面的代码展示了如何组织评估流程:
python展开代码def evaluate_images(image_groups, metrics_to_compute=None, use_lpips=True, use_fid=False):
    """评估模型性能"""
    if metrics_to_compute is None:
        metrics_to_compute = ['ssim', 'psnr', 'mse', 'mae', 'color_error']
    
    # 初始化指标
    metrics = {metric: [] for metric in metrics_to_compute}
    
    if use_lpips:
        lpips_metric = LPIPS_Metric()
        metrics['lpips'] = []
    
    # 处理每组图像
    for name, paths in tqdm(image_groups.items(), desc="评估图像"):
        # 加载图像
        real_B = cv2.imread(paths['real_B_rgb'])
        fake_B = cv2.imread(paths['fake_B_rgb'])
        
        # 转换BGR为RGB
        real_B = cv2.cvtColor(real_B, cv2.COLOR_BGR2RGB)
        fake_B = cv2.cvtColor(fake_B, cv2.COLOR_BGR2RGB)
        
        # 计算各项指标
        if 'ssim' in metrics_to_compute:
            metrics['ssim'].append(calculate_ssim(real_B, fake_B))
        if 'psnr' in metrics_to_compute:
            metrics['psnr'].append(calculate_psnr(real_B, fake_B))
        if 'mse' in metrics_to_compute:
            metrics['mse'].append(calculate_mse(real_B, fake_B))
        if 'mae' in metrics_to_compute:
            metrics['mae'].append(calculate_mae(real_B, fake_B))
        if 'color_error' in metrics_to_compute:
            metrics['color_error'].append(calculate_color_accuracy(real_B, fake_B))
        if use_lpips:
            metrics['lpips'].append(lpips_metric.calculate_lpips(real_B, fake_B))
    
    # 计算FID(如果需要)
    if use_fid:
        real_images = [paths['real_B_rgb'] for paths in image_groups.values()]
        fake_images = [paths['fake_B_rgb'] for paths in image_groups.values()]
        
        fid_metric = FID_Metric()
        fid_score = fid_metric.calculate_fid(real_images, fake_images)
        metrics['fid'] = fid_score
    
    return metrics
收集完所有指标后,我们需要进行统计分析和可视化,以便于理解模型性能:
python展开代码def summarize_metrics(metrics):
    """汇总指标并返回DataFrame"""
    summary = {}
    
    # 计算每个指标的统计数据
    for metric_name, values in metrics.items():
        if metric_name == 'fid':  # FID是单一值
            if values is not None:
                summary[metric_name] = values
        else:
            if len(values) > 0:
                summary[f"{metric_name}_mean"] = np.mean(values)
                summary[f"{metric_name}_std"] = np.std(values)
                summary[f"{metric_name}_min"] = np.min(values)
                summary[f"{metric_name}_max"] = np.max(values)
    
    return pd.DataFrame([summary])
def plot_metrics_distribution(metrics, output_dir):
    """绘制指标分布并保存到输出目录"""
    os.makedirs(output_dir, exist_ok=True)
    
    for metric_name, values in metrics.items():
        if metric_name == 'fid':  # 跳过FID,因为它是单一值
            continue
            
        plt.figure(figsize=(10, 6))
        plt.hist(values, bins=30, alpha=0.7)
        plt.title(f'Distribution of {metric_name.upper()}')
        plt.xlabel(metric_name.upper())
        plt.ylabel('Count')
        plt.grid(True, alpha=0.3)
        plt.savefig(os.path.join(output_dir, f'{metric_name}_distribution.png'))
        plt.close()
为了全面评估上色结果,我们需要了解各指标的适用场景:
| 指标 | 优点 | 缺点 | 适用场景 | 
|---|---|---|---|
| SSIM | 考虑结构相似性,符合人类视觉感知 | 对颜色差异不够敏感 | 评估上色结果的结构保持度 | 
| PSNR | 计算简单,广泛使用 | 仅基于像素差异,不符合视觉感知 | 粗略评估上色质量 | 
| MSE | 计算简单,直观 | 不符合人类视觉感知 | 像素级差异的基准测量 | 
| MAE | 对异常值不敏感 | 同样不符合视觉感知 | 像素级差异的稳健测量 | 
| Color Error | 专注于颜色差异 | 忽略了结构信息 | 评估上色的颜色准确性 | 
| LPIPS | 接近人类视觉感知 | 计算复杂,依赖预训练模型 | 评估感知质量 | 
| FID | 评估整体分布相似度 | 需要大量样本,计算成本高 | 评估上色模型的整体性能 | 
在实际应用中评估上色模型时,建议采取以下策略:
多指标综合评估:单一指标难以全面反映上色质量,应综合考虑多个指标。
权衡计算成本与精度:LPIPS和FID虽然更准确,但计算成本高,可根据实际需求选择。
考虑颜色准确性:对于上色任务,颜色误差是一个特别重要的指标。
结合主观评估:客观指标无法完全替代人类主观评价,可结合小规模的主观评测。
评估指标组合:
图像上色评估是一个多维度的问题,需要从结构相似性、像素差异、颜色准确性和感知质量等多个角度进行衡量。通过合理选择和组合不同指标,我们可以全面客观地评估上色模型的性能,为模型改进提供有力支持。


本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!