Noise Filter for Chroma(色度去噪)

这是 ISP(Image Signal Processing)流水线中的一个步骤,主要目的是:

降低色度通道(Cb、Cr)的噪声,提高图像质量,特别是在低光、压缩或传感器噪声较高的场景下。

为什么只滤波 Chroma?

  • 噪声主要集中在色度通道(Cb、Cr),而亮度(Y)更重要,用来体现图像细节。

  • 人眼对颜色变化不敏感,对亮度变化非常敏感。

  • 所以:

    •  对 Cb/Cr 用更强的去噪

    •  对 Y 保留更多细节

工作流程(常见方式)

RGB → YCbCr → 仅对 Cb 和 Cr 做去噪(如双边滤波) → 合并回 → RGB

代码:



def NFC(cbcr_img, alpha, thresh):
  """
  inputs:
    cbcr_img = Cb and Cr channels of the YCbCr image
    alpha = controls intensity of correction for noisy pixels
    thresh = controls strictness of noisy pixel detection

  outputs:
    nfc_img = Cb and Cr channels of YCbCr image after applying noise filter on both
  """

  cbcr_img = cbcr_img.astype(np.uint16)
  nfc_img = np.copy(cbcr_img) # make a copy of the cbcr_img to apply noise filter for chroma

  for k in range(len(cbcr_img[0,0])):
    # apply the filter to both Cb and Cr
    img = cbcr_img[:, :, k]
    padded_img = np.pad(img, (1, 1), 'reflect') # apply reflect padding on the image to give edge pixels neighbors

    p1 = padded_img[:-2:1, :-2:1] # define p0 : p8 to use in filter
    p2 = padded_img[:-2:1, 1:-1:1]
    p3 = padded_img[:-2:1, 2::1]
    p4 = padded_img[1:-1:1, :-2:1]
    p0 = padded_img[1:-1:1, 1:-1:1]
    p5 = padded_img[1:-1:1, 2::1]
    p6 = padded_img[2::1, :-2:1]
    p7 = padded_img[2::1, 1:-1:1]
    p8 = padded_img[2::1, 2::1]

    neighbors = np.array([p1, p2, p3, p4, p5, p6, p7, p8]) # place all neighbor pixels into a seperate array

    mean = np.mean(neighbors, axis = 0) # calculate mean
    std = np.std(neighbors, axis = 0) # calculate standard deviation
    limit_upper = mean + (thresh * std) # calculate upper and lower limits for the values of p0 relative to neighbors
    limit_lower = mean - (thresh * std)

    editted_img = np.where((p0 > limit_upper) | (p0 < limit_lower), alpha * mean + (1 - alpha) * p0, img) # apply filter

    nfc_img[:, :, k] = editted_img # update the nfc_img

  return nfc_img.astype(np.uint8) # rescale the nfc_img
     

关键点:

    limit_upper = mean + (thresh * std)
    limit_lower = mean - (thresh * std)

定义异常检测的上下限。

  • 如果某像素超出这个区间,就认为它可能是噪声;

  • thresh 是倍数阈值,比如 2.5 表示“超出 2.5×标准差”。

    editted_img = np.where(
        (p0 > limit_upper) | (p0 < limit_lower),
        alpha * mean + (1 - alpha) * p0,
        img
    )

使用 np.where() 来做条件更新:

  • 如果 p0 超出范围,则更新为“均值修正值”:
    alpha * mean + (1 - alpha) * p0
    → 更平滑但保留部分原始信息;

  • 否则,保留原像素。

 

alpha * mean + (1 - alpha) * p0

这是在色度去噪中的 柔性替代(soft replacement)策略,在图像处理里非常常见,用来平滑掉异常像素,但又不完全丢弃原始信息

这句的意思是:

如果当前像素 p0 被判断为噪声(即远离周围邻域像素太多),
就用“邻域均值” 和 “当前像素自身值”的加权平均来修正它。

其中:

  • mean:邻域 8 个像素的平均值(认为更可靠)

  • p0:当前像素值(可能是噪声,但可能也包含真实信息)

  • alpha ∈ [0,1]:控制你更相信 mean 还是 p0

修正后 = α × 周围均值 + (1 - α) × 当前值 

  • 如果 α=1 → 完全信任邻居(最大去噪,最模糊)

  • 如果 α=0 → 完全保留原值(无去噪)

  • 如果 α=0.6 → 更倾向邻域均值,但保留一部分原始信息 ✨

 

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐