如何在Python中实现CIE L*a*b*图像的多方向色彩曲线调整?
实现Photoshop风格的Lab*通道多方向曲线调整
伽马校正确实只能处理单调的幂函数型调整,没法实现Photoshop曲线工具那种灵活的多区间、多方向调整——毕竟伽马只是曲线工具里的一个特例而已。要复刻PS里的曲线调整效果,核心思路是自定义像素值的映射表(LUT),因为PS的曲线本质就是把输入像素值映射到你指定的输出值,我们可以用插值的方法生成平滑的映射表,然后应用到Lab*的各个通道上。
下面是具体实现方案和代码:
核心原理
Photoshop的曲线工具允许你在0-255的像素范围内设置任意控制点,软件会自动插值生成平滑的映射曲线。我们可以用同样的逻辑:
- 为每个通道(L、a、b)定义你想要的控制点(比如暗部、中间调、高光的输入输出值)
- 用插值算法(比如三次样条插值)生成完整的0-255像素值映射表(LUT)
- 将这个LUT应用到对应的Lab*通道上,最后合并通道转回RGB/BGR格式
代码实现
首先写一个生成自定义曲线LUT的工具函数,以及通道调整函数:
import numpy as np import cv2 import matplotlib.pyplot as plt from scipy.interpolate import interp1d def create_curve_lut(points): # 控制点格式:[(输入像素值, 输出像素值), ...],比如[(0,10), (127,160), (255,255)] # 先按输入值排序,避免插值出错 sorted_points = sorted(points, key=lambda x: x[0]) inputs = np.array([p[0] for p in sorted_points]) outputs = np.array([p[1] for p in sorted_points]) # 用三次样条插值生成平滑曲线,和PS的曲线平滑度一致 interp_func = interp1d(inputs, outputs, kind='cubic', fill_value="extrapolate") # 生成0到255的完整映射表 lut = np.round(interp_func(np.arange(0, 256))).astype(np.uint8) # 确保所有值都在0-255的合法范围内 lut = np.clip(lut, 0, 255) return lut def apply_curve_to_channel(channel, lut): # 用OpenCV的LUT函数快速应用映射 return cv2.LUT(channel, lut)
然后结合Lab*通道的完整工作流:
# 读取你的图像(OpenCV默认是BGR格式) image_BGR = cv2.imread("your_image_path.jpg") # 转换到L*a*b*色彩空间 lab_image = cv2.cvtColor(image_BGR, cv2.COLOR_BGR2LAB) L, a, b = cv2.split(lab_image) # 为每个通道定义自定义曲线控制点,你可以根据需求修改 # L通道示例:暗部稍微压暗,中间调提亮,高光保持不变 L_curve_points = [(0, 10), (60, 50), (127, 160), (200, 220), (255, 255)] # a通道示例:增加红色(a通道正值方向),弱化绿色(负值方向) a_curve_points = [(0, 0), (127, 140), (255, 255)] # b通道示例:增加黄色(b通道负值方向),弱化蓝色(正值方向) b_curve_points = [(0, 30), (127, 110), (255, 220)] # 生成各通道的映射表 L_lut = create_curve_lut(L_curve_points) a_lut = create_curve_lut(a_curve_points) b_lut = create_curve_lut(b_curve_points) # 应用曲线到每个通道 adjusted_L = apply_curve_to_channel(L, L_lut) adjusted_a = apply_curve_to_channel(a, a_lut) adjusted_b = apply_curve_to_channel(b, b_lut) # 合并通道并转换回BGR格式 adjusted_lab = cv2.merge([adjusted_L, adjusted_a, adjusted_b]) final_image = cv2.cvtColor(adjusted_lab, cv2.COLOR_LAB2BGR) # 对比原图和调整后的效果 cv2.imshow("Original vs Adjusted", np.hstack([image_BGR, final_image])) cv2.waitKey(0) cv2.destroyAllWindows()
额外技巧:可视化调整曲线
如果你想直观看到自己定义的曲线形状,可以加一个绘图函数:
def plot_curve(lut): plt.figure(figsize=(8, 4)) plt.plot(np.arange(0, 256), lut, linewidth=2) plt.xlabel("Input Pixel Value") plt.ylabel("Output Pixel Value") plt.title("Custom Adjustment Curve") plt.grid(True, linestyle="--", alpha=0.7) plt.show() # 示例:查看L通道的曲线形状 plot_curve(L_lut)
为什么这个方法比伽马校正更好?
- 伽马校正只是单调的幂函数调整,只能整体提亮或压暗;而自定义曲线可以在不同像素区间做差异化调整(比如暗部压暗同时中间调提亮),实现多方向的精细控制。
- 每个通道独立调整,不会出现伽马校正那种容易导致的色彩偏移问题,因为你可以精准控制a、b通道的色彩偏向。
- 三次样条插值生成的曲线平滑自然,和Photoshop的曲线工具效果几乎一致。
内容的提问来源于stack exchange,提问作者Deepti Hegde
相关产品推荐
相关产品推荐

