人脸图像复原-Basicsr退化样本生成脚本

人脸图像复原任务中经常会用到一些模拟合成的退化图像作为测试样本,以下脚本提供生成高斯模糊和马赛克的退化人脸图像,可在Basicsr/inference/目录中直接运行:

python 复制代码
import cv2
import numpy as np
import random
import os

def generate_degraded_image(input_image_path, output_path):
    """
    生成高强度模糊, 马赛克的退化图像
    模糊参数: kernel_size = [51, 127], sigma = [8.0, 15.0],可以通过调节列表中的参数调节模糊退化程度
    """
    
    # 1. 读取图像
    img = cv2.imread(input_image_path)
    if img is None:
        print(f"错误:无法读取图像 {input_image_path}")
        return None
    
    h, w = img.shape[:2]
    print(f"原始图像尺寸: {w}x{h}")
    
    # 2. 第一阶段:高斯模糊
    print("\n=== 第一阶段:高强度高斯模糊 ===")
    kernel_size = np.random.choice([51, 127])
    sigma = np.random.uniform(8.0, 15.0)
    
    # 确保kernel_size是奇数
    if kernel_size % 2 == 0:
        kernel_size += 1
    
    print(f"模糊参数: kernel_size={kernel_size}, sigma={sigma:.2f}")
    
    blurred = cv2.GaussianBlur(img, (kernel_size, kernel_size), sigma)
    
    cv2.imwrite('debug_1_heavy_blur.jpg', blurred)
    print(f"高强度模糊完成,保存为: debug_1_heavy_blur.jpg")
    
    # 3. 第二阶段:马赛克退化
    print("\n=== 第二阶段:马赛克退化 ===")
    
    # 随机选择马赛克块大小(根据图像尺寸自适应)
    base_size = min(h, w)
    if base_size > 1000:
        mosaic_sizes = [16, 24, 32, 48]
    elif base_size > 500:
        mosaic_sizes = [12, 16, 24, 32]
    else:
        mosaic_sizes = [8, 12, 16, 24]
    
    mosaic_size = random.choice(mosaic_sizes)
    print(f"马赛克块大小: {mosaic_size}")
    
    # 应用马赛克
    mosaic_img = blurred.copy()
    
    for y in range(0, h, mosaic_size):
        for x in range(0, w, mosaic_size):
            # 获取当前块
            block_h = min(mosaic_size, h - y)
            block_w = min(mosaic_size, w - x)
            
            block = mosaic_img[y:y+block_h, x:x+block_w]
            
            if block.size > 0:
                # 计算块的平均颜色
                avg_color = np.mean(block, axis=(0, 1))
                # 将整个块设置为平均颜色
                mosaic_img[y:y+block_h, x:x+block_w] = avg_color
    
    # 保存中间结果
    cv2.imwrite('debug_2_mosaic.jpg', mosaic_img)
    print(f"马赛克退化完成,保存为: debug_2_mosaic.jpg")
    
    # 4. 第三阶段:后处理模糊(平滑马赛克边缘)
    print("\n=== 第三阶段:后处理平滑 ===")
    
    # 随机选择后处理模糊强度
    post_blur_kernel = random.choice([3, 5, 7])
    post_blur_sigma = random.uniform(0.5, 1.5)
    
    if post_blur_kernel % 2 == 0:
        post_blur_kernel += 1
    
    final = cv2.GaussianBlur(mosaic_img, (post_blur_kernel, post_blur_kernel), post_blur_sigma)
    
    print(f"后处理平滑: kernel={post_blur_kernel}, sigma={post_blur_sigma:.2f}")
    
    # 5. 可选:添加轻微噪声(模拟压缩伪影)
    if random.random() > 0.5:
        print("添加轻微噪声...")
        noise_level = random.uniform(1.0, 3.0)
        noise = np.random.randn(*final.shape) * noise_level
        final = final + noise
        final = np.clip(final, 0, 255).astype(np.uint8)
        print(f"噪声水平: {noise_level:.2f}")
    
    cv2.imwrite(output_path, final)
    
    print("\n=== 处理完成 ===")
    print(f"输入图像: {input_image_path}")
    print(f"输出图像: {output_path}")
    print(f"最终图像尺寸: {final.shape[1]}x{final.shape[0]}")
    print(f"像素值范围: [{final.min()}, {final.max()}]")
    
    # 计算PSNR(峰值信噪比)来量化退化程度
    if img.shape == final.shape:
        mse = np.mean((img.astype(float) - final.astype(float)) ** 2)
        if mse > 0:
            psnr = 10 * np.log10(255.0 * 255.0 / mse)
            print(f"PSNR(峰值信噪比): {psnr:.2f} dB")
            print(f"MSE(均方误差): {mse:.2f}")
    
    return final

def generate_varied_degradations(input_image_path, output_dir, num_variations=5):
    """
    生成多种变化的退化图像
    """
    os.makedirs(output_dir, exist_ok=True)
    
    # 获取文件名和扩展名
    filename = os.path.basename(input_image_path)
    name_only, ext = os.path.splitext(filename)
    
    results = []
    
    for i in range(num_variations):
        print(f"\n{'='*50}")
        print(f"生成第 {i+1}/{num_variations} 种退化")
        print(f"{'='*50}")
        
        output_filename = f"{name_only}_degraded_{i+1}{ext}"
        output_path = os.path.join(output_dir, output_filename)
        
        result = generate_degraded_image(input_image_path, output_path)
        if result is not None:
            results.append(output_path)
        
        print(f"完成: {output_filename}")
    
    print(f"\n总计生成 {len(results)} 张退化图像")
    return results

def create_comparison_grid(input_image_path, degraded_image_path, output_comparison_path):
    """
    创建原图与退化图的对比网格
    """
    original = cv2.imread(input_image_path)
    degraded = cv2.imread(degraded_image_path)
    
    if original is None or degraded is None:
        print("无法读取图像用于对比")
        return
    
    # 调整大小确保一致
    h, w = original.shape[:2]
    degraded = cv2.resize(degraded, (w, h))
    
    # 创建对比网格
    comparison = np.zeros((h, w*2, 3), dtype=np.uint8)
    comparison[:, :w] = original
    comparison[:, w:] = degraded
    
    # 添加标签
    font = cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(comparison, 'Original', (10, 30), font, 1, (255, 255, 255), 2)
    cv2.putText(comparison, 'Degraded', (w+10, 30), font, 1, (255, 255, 255), 2)
    
    # 添加分界线
    cv2.line(comparison, (w, 0), (w, h), (255, 255, 255), 2)
    
    cv2.imwrite(output_comparison_path, comparison)
    print(f"对比图已保存: {output_comparison_path}")
    
    return comparison

def analyze_degradation_effect(input_image_path, degraded_image_path):
    """
    分析退化效果
    """
    original = cv2.imread(input_image_path)
    degraded = cv2.imread(degraded_image_path)
    
    if original is None or degraded is None:
        print("无法读取图像用于分析")
        return
   
    h, w = original.shape[:2]
    degraded = cv2.resize(degraded, (w, h))
    
    print("\n=== 退化效果分析 ===")
    
    # 转换为灰度计算清晰度
    original_gray = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
    degraded_gray = cv2.cvtColor(degraded, cv2.COLOR_BGR2GRAY)
    
    # 计算拉普拉斯方差(清晰度指标)
    original_sharpness = cv2.Laplacian(original_gray, cv2.CV_64F).var()
    degraded_sharpness = cv2.Laplacian(degraded_gray, cv2.CV_64F).var()
    
    print(f"原始图像清晰度: {original_sharpness:.2f}")
    print(f"退化图像清晰度: {degraded_sharpness:.2f}")
    print(f"清晰度降低: {((original_sharpness - degraded_sharpness) / original_sharpness * 100):.1f}%")
    
    # 计算PSNR和MSE
    mse = np.mean((original.astype(float) - degraded.astype(float)) ** 2)
    psnr = 10 * np.log10(255.0 * 255.0 / mse) if mse > 0 else float('inf')
    
    print(f"MSE(均方误差): {mse:.2f}")
    print(f"PSNR(峰值信噪比): {psnr:.2f} dB")
    
    try:
        from skimage.metrics import structural_similarity as ssim
        ssim_value = ssim(original_gray, degraded_gray)
        print(f"SSIM(结构相似性): {ssim_value:.4f}")
    except ImportError:
        print("安装scikit-image以计算SSIM: pip install scikit-image")
    
    return {
        'original_sharpness': original_sharpness,
        'degraded_sharpness': degraded_sharpness,
        'mse': mse,
        'psnr': psnr
    }

if __name__ == "__main__":
    import sys
    
    input_image = "2910.jpg"  # 输入图像路径
    output_image = "degraded_output.jpg"  # 输出图像路径
    output_dir = "degraded_variations"  # 多版本输出目录
    
    print("=" * 60)
    print("高强度模糊 + 马赛克退化生成器")
    print("模糊参数: kernel_size ∈ [51, 127], sigma ∈ [8.0, 15.0]")
    print("=" * 60)
    
    if not os.path.exists(input_image):
        print(f"错误:输入文件不存在 {input_image}")
        print("请确保图像文件在当前目录下")
        sys.exit(1)
   
    print("\n请选择模式:")
    print("1. 生成单张退化图像")
    print("2. 生成多张不同退化的图像")
    print("3. 生成并分析退化效果")
    
    try:
        choice = int(input("请输入选择 (1-3): "))
    except:
        choice = 1
    
    if choice == 1:
        # 生成单张退化图像
        result = generate_degraded_image(input_image, output_image)
        
        # 创建对比图
        if result is not None:
            comparison = create_comparison_grid(input_image, output_image, "comparison.jpg")

            analysis = analyze_degradation_effect(input_image, output_image)
            
    elif choice == 2:
        # 生成多张不同退化的图像
        num_variations = 3
        try:
            num_variations = int(input(f"请输入要生成的图像数量 (默认{num_variations}): "))
        except:
            pass
        
        results = generate_varied_degradations(input_image, output_dir, num_variations)
        
        print(f"\n生成的图像保存在: {output_dir}/")
        for i, path in enumerate(results, 1):
            print(f"{i}. {os.path.basename(path)}")
    
    elif choice == 3:
        result = generate_degraded_image(input_image, output_image)
        if result is not None:
            analysis = analyze_degradation_effect(input_image, output_image)

            report = f"""退化效果分析报告
            ====================
            输入图像: {input_image}
            输出图像: {output_image}
            
            清晰度降低: {analysis.get('original_sharpness', 0):.1f} -> {analysis.get('degraded_sharpness', 0):.1f}
            均方误差(MSE): {analysis.get('mse', 0):.2f}
            峰值信噪比(PSNR): {analysis.get('psnr', 0):.2f} dB
            
            说明:
            - PSNR < 20 dB: 严重退化
            - PSNR 20-30 dB: 明显退化
            - PSNR > 30 dB: 轻微退化
            """
            
            print("\n" + report)
            
            with open("degradation_report.txt", "w") as f:
                f.write(report)
            print("详细报告已保存为: degradation_report.txt")
    
    print("\n处理完成!")
    
    print("\n生成的文件:")
    for file in ['degraded_output.jpg', 'debug_1_heavy_blur.jpg', 
                 'debug_2_mosaic.jpg', 'comparison.jpg']:
        if os.path.exists(file):
            size = os.path.getsize(file) / 1024
            print(f"  {file} ({size:.1f} KB)")

单张图像退化样本生成结果示例: