import cv2
import numpy as np
from skimage.metrics import peak_signal_noise_ratio as compare_psnr
from skimage.metrics import structural_similarity as compare_ssim
from PIL import Image
import matplotlib.pyplot as plt
from matplotlib import cm

def dataset_reader(input_path):
    """
    使用OpenCV读取图像，支持 uint8 和 uint16 图像，并兼容三通道转单通道灰度。
    输出PIL图像对象和对应的原始dtype。
    """
    img_cv = cv2.imread(input_path, cv2.IMREAD_UNCHANGED)
    if img_cv is None:
        raise RuntimeError(f"无法用OpenCV读取图像文件 {input_path}")

    print(f"OpenCV读取图像: dtype={img_cv.dtype}, shape={img_cv.shape}")

    if img_cv.ndim == 2:
        single_channel = img_cv
    elif img_cv.ndim == 3 and img_cv.shape[2] == 3:
        print("三通道图像，转为单通道灰度（均值）")
        gray_float = img_cv.mean(axis=2)
        if img_cv.dtype == np.uint8:
            single_channel = gray_float.astype(np.uint8)
        elif img_cv.dtype == np.uint16:
            single_channel = gray_float.astype(np.uint16)
        else:
            raise TypeError(f"不支持的图像dtype {img_cv.dtype}，仅支持uint8和uint16")
    else:
        raise ValueError(f"不支持的图像通道数和形状: {img_cv.shape}")

    dtype = single_channel.dtype
    if dtype == np.uint8:
        mode = 'L'
    elif dtype == np.uint16:
        mode = 'I;16'
    else:
        raise TypeError(f"不支持的dtype进行保存: {dtype}")

    out_img = Image.fromarray(single_channel, mode=mode)
    return out_img, dtype

def pil_to_np(img_pil):
    """PIL图像转numpy ndarray"""
    return np.array(img_pil)

def calculate_metrics(img1_np, img2_np):
    """
    计算PSNR, SSIM, RMSE
    这里限定为单通道灰度图或相同shape的图像
    """
    # 确保输入是float64方便计算
    img1_f = img1_np.astype(np.float64)
    img2_f = img2_np.astype(np.float64)

    data_range = img1_np.max() - img1_np.min()
    if data_range == 0:
        data_range = 255  # 保底按8bit图处理

    psnr = compare_psnr(img1_f, img2_f, data_range=data_range)
    ssim = compare_ssim(img1_f, img2_f, data_range=data_range)
    rmse = np.sqrt(np.mean((img1_f - img2_f) ** 2))
    return psnr, ssim, rmse

def crop_and_save(pil_img, x, y, w, h, save_path):
    """
    裁剪PIL图像且保存
    """
    cropped = pil_img.crop((x, y, x+w, y+h))
    cropped.save(save_path)
    print(f"裁剪图像保存到: {save_path}")

def save_diff_heatmap(np_img1, np_img2, save_path):
    diff = np.abs(np_img1.astype(np.float64) - np_img2.astype(np.float64))
    diff_norm = (diff - diff.min()) / (diff.max() - diff.min() + 1e-15)

    colormap = cm.get_cmap('jet')
    heatmap_rgba = colormap(diff_norm)
    heatmap_rgb = np.uint8(heatmap_rgba[:, :, :3] * 255)

    heatmap_pil = Image.fromarray(heatmap_rgb, mode='RGB')
    heatmap_pil.save(save_path)
    print(f"差异热力图保存到: {save_path}")

if __name__ == "__main__":
    # 测试路径（请替换成你的真实路径）
    input_path = "/home/jianruobing/code/FITTING/logs/ICL0/imgs/train_pred_img_step_9000.png"
    gt_path = "/home/jianruobing/code/FITTING/fitting_curves/data/ICL0_bix2.png"

    # 读取图像（灰度PIL图，uint8或uint16）
    input_pil, input_dtype = dataset_reader(input_path)
    gt_pil, gt_dtype = dataset_reader(gt_path)

    # 转换为numpy数组进行计算
    input_np = pil_to_np(input_pil)
    gt_np = pil_to_np(gt_pil)

    if input_np.shape != gt_np.shape:
        raise ValueError(f"输入图像和GT尺寸不匹配: {input_np.shape} vs {gt_np.shape}")

    # 计算指标
    psnr, ssim, rmse = calculate_metrics(input_np, gt_np)
    print(f"PSNR: {psnr:.4f}, SSIM: {ssim:.4f}, RMSE: {rmse:.4f}")

    # 裁剪参数（示例）
    x, y, w, h = 50, 50, 100, 100
    crop_and_save(input_pil, x, y, w, h, "cropped_input.png")
    crop_and_save(gt_pil, x, y, w, h, "cropped_gt.png")

    # 保存热力图
    save_diff_heatmap(input_np, gt_np, "ICL0_diff_heatmap.png")
请帮我解释一下，这个代码产生的热力图中黑色和蓝色分别是什么意思