图像处理:模拟色差的生成

news/2025/2/23 5:29:46

图像处理:模拟色差的实战案例

在做瓷砖瑕疵检测的过程中,需要检测色差。但在实际生产环境中,瓷砖色差检测的数据量较少,无法直接获取足够的数据来训练和优化深度学习模型。于是就考虑通过人为生成色差数据的方式来扩充数据集,进行色差的模拟。

1. 什么是色差?

色差(Color Difference)是指两种颜色之间的视觉差异。在色彩科学中,CIEDE2000 是目前最先进的色差计算方法之一。然而,CIEDE1976 也常用于基础的色差分析。本项目主要使用 CIEDE1976 来计算颜色的变化程度。

2. 代码实现

编写一个 Python 脚本,该脚本能够读取一组图像,并生成不同色差版本的图像,同时计算其色差值。

2.1 依赖库

在开始之前,请确保你已经安装了必要的库:

pip install opencv-python numpy colormath

2.2 计算色差

我们使用 colormath 库来计算 CIEDE1976 色差:

from colormath.color_objects import LabColor
from colormath.color_diff import delta_e_cie1976

def calculate_delta_e(lab1, lab2):
    """
    计算 CIEDE1976 色差
    :param lab1: (L, a, b) of first color
    :param lab2: (L, a, b) of second color
    :return: ΔE 色差值
    """
    color1 = LabColor(lab1[0], lab1[1], lab1[2])
    color2 = LabColor(lab2[0], lab2[1], lab2[2])
    
    return delta_e_cie1976(color1, color2)

2.3 模拟色差

使用 OpenCV 将图像转换到 Lab 颜色空间,并对 L、a、b 通道进行调整:
注意:在处理ab通道时,如果按照255进行设置偏置,可能存在溢出,导致图片显示黑点,所以要进行归一化 a, b 到 [-128, 127]

import cv2
import numpy as np

def apply_lab_shift(image, l_shift, a_shift, b_shift):
    """
    在 Lab 颜色空间执行色差模拟
    """
    lab_image = cv2.cvtColor(image, cv2.COLOR_BGR2LAB).astype(np.float32)
    L, a, b = cv2.split(lab_image)
    
    # 归一化 a, b 到 [-128, 127]
    a -= 128
    b -= 128
    
    L = np.clip(L + l_shift, 0, 255)
    a = np.clip(a + a_shift, -128, 127)
    b = np.clip(b + b_shift, -128, 127)
    
    # 还原到 OpenCV 存储格式 [0,255]
    a += 128
    b += 128
    
    shifted_lab = cv2.merge([L, a, b]).astype(np.uint8)
    return cv2.cvtColor(shifted_lab, cv2.COLOR_LAB2BGR)

2.4 处理图片并保存结果

import os

def process_images(input_folder, output_folder, log_file):
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
        
    with open(log_file, 'w') as log:
        for root, _, files in os.walk(input_folder):
            for file_name in files:
                if file_name.lower().endswith(('.jpg', '.png', '.jpeg')):
                    image_path = os.path.join(root, file_name)
                    image = cv2.imread(image_path)

                    if image is None:
                        print(f"无法读取 {file_name},跳过...")
                        continue
                    
                    base_name, ext = os.path.splitext(file_name)
                    save_path = os.path.join(output_folder, base_name)
                    os.makedirs(save_path, exist_ok=True)
                    
                    # 生成不同色差版本
                    shifts = {"n": (0.5, 0.4, -0.4), "s": (2, 1.2, -1.2), "l": (3, 2.5, -3.5)}
                    for key, (l, a, b) in shifts.items():
                        shifted = apply_lab_shift(image, l, a, b)
                        cv2.imwrite(os.path.join(save_path, f"{base_name}_{key}{ext}"), shifted)
                        
                        # 计算 ΔE
                        lab_orig = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
                        lab_shifted = cv2.cvtColor(shifted, cv2.COLOR_BGR2LAB)
                        delta_e = calculate_delta_e(lab_orig.mean(axis=(0, 1)), lab_shifted.mean(axis=(0, 1)))
                        log.write(f"{file_name} - {key}色差 ΔE: {delta_e:.2f}\n")
                    
        print(f"处理完成,结果保存在 {output_folder}")

2.5 运行代码

if __name__ == "__main__":
    current_folder = os.path.dirname(os.path.abspath(__file__))
    input_folder = os.path.join(current_folder, "input_images")
    output_folder = os.path.join(current_folder, "color_diff_images")
    log_file = os.path.join(output_folder, "process_log.txt")
    process_images(input_folder, output_folder, log_file)

3. 运行效果

当我们运行代码后,程序会:

  • 读取 input_images 文件夹中的图片。
  • 生成无色差(ΔE≈0.5)、小色差(ΔE≈0.5-3)、大色差(ΔE≈10-15)的版本。
  • 计算色差并记录到 process_log.txt

最终,我们可以在 color_diff_images 目录下找到处理后的图像,并通过日志查看每张图像的 ΔE 数值。

#CIELab#
#色差生成#


http://www.niftyadmin.cn/n/5862996.html

相关文章

力扣hot100——LRU缓存(面试高频考题)

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -…

新书上线 |《零门槛AIGC应用实战——Serverless+AI 轻松玩转高频AIGC场景》免费下载

《零门槛AIGC应用实战——ServerlessAI 轻松玩转高频AIGC场景》电子书正式上线!多种精选 AI 部署方案带你深入了解 ServerlessAI 最新趋势、AI 应用的架构设计与详细的部署教程等。函数计算 AI 技术解决方案助您一键上云,高效部署。 点击链接&#xff0c…

tauri2实现监听记住窗口大小变化,重启回复之前的窗口大小

要想实现记住窗口大小的功能,整体逻辑就是要监听窗口大小变化,将窗口大小保存下来,重启之后,读取保存的大小,然后恢复。这里可以使用rust层实现,也可以在前端实现。我这里就纯rust层实现了。 监听窗口变化…

UE5 编辑器辅助/加强 插件搜集

1. Actor Locker 地址:https://www.fab.com/listings/ec26ac5e-4720-467c-a3a6-b5103b6b74d0 使用说明:https://github.com/Gradess2019/ActorLocker 支持:5.0 – 5.5 简单的编辑器扩展。它允许你通过世界轮廓窗口/热键/上下文菜单在编辑器视…

centos9安装k8s集群

以下是基于CentOS Stream 9的Kubernetes 1.28.2完整安装流程(containerd版): 一、系统初始化(所有节点执行) # 关闭防火墙 systemctl disable --now firewalld# 关闭SELinux sed -i "s/SELINUXenforcing/SELINU…

Spring事务原理 二

在上一篇博文《Spring事务原理 一》中,我们熟悉了Spring声明式事务的AOP原理,以及事务执行的大体流程。 本文中,介绍了Spring事务的核心组件、传播行为的源码实现。下一篇中,我们将结合案例,来讲解实战中有关事务的易…

记录首次安装远古时代所需的运行环境成功npm install --save-dev node-sass

最开始的报错: 最后根据报错一步步 安装所需要的pythong之类的环境,最后终于成功了,得以让我在github上拉的vuehr项目(狗头18年还是20年的远古项目)成功本地运行,最后附上本地运行成功的贴图。如果大家也在…

如果后台的Long类型的数据返回是null,那么Android客户端的数据bean的kotlin的Long类型的字段接受到数据后是null空指针吗?

如果后台的Long类型的数据返回是null,那么Android客户端的数据bean的kotlin的Long类型的字段接受到数据后是null空指针吗? DeepSeek R1 思考 35 秒 思考过程 好的,用户的问题是关于在Android客户端使用Kotlin处理后台返回的Long类型数据为n…