利用拉格朗日多项式插值进行镜头阴影校正

简介

镜头阴影(Lens Shading)是摄影和成像过程中常见的问题,特别是在使用广角镜头时。镜头阴影会导致图像从中心到边缘的亮度逐渐减弱,影响图像的均匀性。为了解决这个问题,我们可以使用基于 Lagrange 插值的镜头阴影校正(Lens Shading Correction, LSC)技术。本文将详细介绍如何使用 Python 和 OpenCV 实现这一过程。

步骤解析
1. 读取图像

首先,我们需要读取待处理的图像。这里我们使用 OpenCV 读取图像,并进行简单的错误处理,以确保文件路径正确。

import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import lagrange

filePath = 'images/lsc.bmp'
num_rings = 16

# 读取图像
image = cv2.imread(filePath)
if image is None:
    raise FileNotFoundError(f"未找到图像文件: {filePath}")
2. 计算环形增益

为了校正镜头阴影,我们需要计算图像从中心到边缘的环形平均值。我们将图像分成若干同心环,并计算每个环内的平均像素值。然后,对这些平均值进行归一化处理,以确保增益值从中心向外平滑过渡.

def calculate_lsc_gain_circular(image, num_rings):
    height, width, _ = image.shape
    center_x, center_y = width // 2, height // 2
    max_radius = np.sqrt(center_x**2 + center_y**2)
    
    # 分离颜色通道
    image_r = image[:, :, 2]  # OpenCV 读取图像是 BGR 顺序,所以红色通道在最后
    image_g = image[:, :, 1]
    image_b = image[:, :, 0]
    
    # 初始化存储环形平均值的数组
    ring_means_r = np.zeros(num_rings)
    ring_means_g = np.zeros(num_rings)
    ring_means_b = np.zeros(num_rings)
    
    # 计算每个环的平均值
    y, x = np.ogrid[:height, :width]
    distance_from_center = np.sqrt((x - center_x)**2 + (y - center_y)**2)
    
    for r in range(num_rings):
        inner_radius = r * max_radius / num_rings
        outer_radius = (r + 1) * max_radius / num_rings
        
        mask = (distance_from_center >= inner_radius) & (distance_from_center < outer_radius)
        
        ring_means_r[r] = np.mean(image_r[mask])
        ring_means_g[r] = np.mean(image_g[mask])
        ring_means_b[r] = np.mean(image_b[mask])
    
    # 计算增益
    ring_means_r = ring_means_r[0] / ring_means_r
    ring_means_g = ring_means_g[0] / ring_means_g
    ring_means_b = ring_means_b[0] / ring_means_b
    
    return ring_means_r, ring_means_g, ring_means_b, center_x, center_y, max_radius / num_rings
3. Lagrange 插值

我们使用 Lagrange 插值多项式来平滑计算从中心到边缘的增益变化。这可以确保校正后的图像亮度过渡自然

def lagrange_interpolate(x, poly):
    return poly(x)
4. 应用 LSC 校正

我们将计算得到的增益应用于原始图像。对于每个像素,我们根据其到图像中心的距离,使用预计算的 Lagrange 插值多项式计算增益值,并对像素进行校正。

def apply_lsc_correction_circular(image, ring_means_r, ring_means_g, ring_means_b, center_x, center_y, radius_step):
    height, width, _ = image.shape
    max_radius = radius_step * len(ring_means_r)
    
    corrected_image = np.zeros_like(image, dtype=np.float32)
    
    # 生成半径数组
    radius_array = np.linspace(0, max_radius, len(ring_means_r))
    
    # 预计算多项式
    poly_r = lagrange(radius_array, ring_means_r)
    poly_g = lagrange(radius_array, ring_means_g)
    poly_b = lagrange(radius_array, ring_means_b)
    
    # 打印多项式系数用于调试
    print("Lagrange Polynomial Coefficients for R Channel:", poly_r)
    print("Lagrange Polynomial Coefficients for G Channel:", poly_g)
    print("Lagrange Polynomial Coefficients for B Channel:", poly_b)
    
    # 计算所有像素到中心的距离
    y, x = np.indices((height, width))
    distance_from_center = np.sqrt((x - center_x)**2 + (y - center_y)**2)
    
    # 确保半径不超过最大半径
    distance_from_center = np.clip(distance_from_center, 0, max_radius)
    
    # 使用预计算的多项式进行插值
    rGain = lagrange_interpolate(distance_from_center, poly_r)
    gGain = lagrange_interpolate(distance_from_center, poly_g)
    bGain = lagrange_interpolate(distance_from_center, poly_b)
    
    # 应用增益校正
    corrected_image[:, :, 2] = image[:, :, 2] * rGain
    corrected_image[:, :, 1] = image[:, :, 1] * gGain
    corrected_image[:, :, 0] = image[:, :, 0] * bGain
    
    return np.clip(corrected_image, 0, 255).astype(np.uint8)

完整代码 

import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import lagrange


def calculate_lsc_gain_circular(image, num_rings):
    height, width, _ = image.shape
    center_x, center_y = width // 2, height // 2
    max_radius = np.sqrt(center_x ** 2 + center_y ** 2)

    # 分离颜色通道
    image_r = image[:, :, 2]  # OpenCV 读取图像是 BGR 顺序,所以红色通道在最后
    image_g = image[:, :, 1]
    image_b = image[:, :, 0]

    # 初始化存储环形平均值的数组
    ring_means_r = np.zeros(num_rings)
    ring_means_g = np.zeros(num_rings)
    ring_means_b = np.zeros(num_rings)

    # 计算每个环的平均值
    y, x = np.ogrid[:height, :width]
    distance_from_center = np.sqrt((x - center_x) ** 2 + (y - center_y) ** 2)

    for r in range(num_rings):
        inner_radius = r * max_radius / num_rings
        outer_radius = (r + 1) * max_radius / num_rings

        mask = (distance_from_center >= inner_radius) & (distance_from_center < outer_radius)

        ring_means_r[r] = np.mean(image_r[mask])
        ring_means_g[r] = np.mean(image_g[mask])
        ring_means_b[r] = np.mean(image_b[mask])

    # 计算增益
    ring_means_r = ring_means_r[0] / ring_means_r
    ring_means_g = ring_means_g[0] / ring_means_g
    ring_means_b = ring_means_b[0] / ring_means_b

    return ring_means_r, ring_means_g, ring_means_b, center_x, center_y, max_radius / num_rings


def lagrange_interpolate(x, poly):
    return poly(x)


def apply_lsc_correction_circular(image, ring_means_r, ring_means_g, ring_means_b, center_x, center_y, radius_step):
    height, width, _ = image.shape
    max_radius = radius_step * len(ring_means_r)

    corrected_image = np.zeros_like(image, dtype=np.float32)

    # 生成半径数组
    radius_array = np.linspace(0, max_radius, len(ring_means_r))

    # 预计算多项式
    poly_r = lagrange(radius_array, ring_means_r)
    poly_g = lagrange(radius_array, ring_means_g)
    poly_b = lagrange(radius_array, ring_means_b)

    # 打印多项式系数用于调试
    print("Lagrange Polynomial Coefficients for R Channel:", poly_r)
    print("Lagrange Polynomial Coefficients for G Channel:", poly_g)
    print("Lagrange Polynomial Coefficients for B Channel:", poly_b)

    # 计算所有像素到中心的距离
    y, x = np.indices((height, width))
    distance_from_center = np.sqrt((x - center_x) ** 2 + (y - center_y) ** 2)

    # 确保半径不超过最大半径
    distance_from_center = np.clip(distance_from_center, 0, max_radius)

    # 使用预计算的多项式进行插值
    rGain = lagrange_interpolate(distance_from_center, poly_r)
    gGain = lagrange_interpolate(distance_from_center, poly_g)
    bGain = lagrange_interpolate(distance_from_center, poly_b)

    # 应用增益校正
    corrected_image[:, :, 2] = image[:, :, 2] * rGain
    corrected_image[:, :, 1] = image[:, :, 1] * gGain
    corrected_image[:, :, 0] = image[:, :, 0] * bGain

    return np.clip(corrected_image, 0, 255).astype(np.uint8)


if __name__ == "__main__":
    filePath = '../images/LSC.png'
    num_rings = 16

    # 读取图像
    image = cv2.imread(filePath)
    if image is None:
        raise FileNotFoundError(f"未找到图像文件: {filePath}")

    # 计算 LSC 增益
    ring_means_r, ring_means_g, ring_means_b, center_x, center_y, radius_step = calculate_lsc_gain_circular(image,
                                                                                                            num_rings)

    # 打印每个环的平均值用于调试
    print("Normalized Ring Means R:", ring_means_r)
    print("Normalized Ring Means G:", ring_means_g)
    print("Normalized Ring Means B:", ring_means_b)

    # 应用 LSC 校正
    corrected_image = apply_lsc_correction_circular(image, ring_means_r, ring_means_g, ring_means_b, center_x, center_y,
                                                    radius_step)

    # 显示图像
    plt.figure(figsize=(12, 6))
    plt.subplot(121)
    plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    plt.title('原始图像')

    plt.subplot(122)
    plt.imshow(cv2.cvtColor(corrected_image, cv2.COLOR_BGR2RGB))
    plt.title('校正后图像')
    plt.show()

总结

在镜头阴影校正中,我们选择使用 Lagrange 插值是因为它能够在已知点之间提供高精度的平滑过渡,适合处理图像中的亮度渐变问题。然而,Lagrange 插值在处理大量插值点时可能会出现精度下降的情况,因此在实际应用中需要根据具体需求选择合适的插值算法。

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值