计算对比图

Computing a contrast map

我正在尝试计算 NxN window 中每个像素周围的对比度并将结果保存在新图像中,其中新图像中的每个像素都是其周围区域的对比度在旧图像中。从另一个 post 我得到这个:

1) Convert the image to say LAB and get the L channel
2) Compute the max for an NxN neighborhood around each pixel
3) Compute the min for an NxN neighborhood around each pixel
4) Compute the contrast from the equation above at each pixel.
5) Insert the contrast as a pixel value in new image.

目前我有:

def cmap(roi):
    max = roi.reshape((roi.shape[0] * roi.shape[1], 3)).max(axis=0)
    min = roi.reshape((roi.shape[0] * roi.shape[1], 3)).min(axis=0)
    contrast = (max - min) / (max + min)
    return contrast


def cm(img):
    # convert to LAB color space
    lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

    # separate channels
    L, A, B = cv2.split(lab)

    img_shape = L.shape

    size = 5

    shape = (L.shape[0] - size + 1, L.shape[1] - size + 1, size, size)
    strides = 2 * L.strides
    patches = np.lib.stride_tricks.as_strided(L, shape=shape, strides=strides)
    patches = patches.reshape(-1, size, size)

    output_img = np.array([cmap(roi) for roi in patches])
    cv2.imwrite("labtest.png", output_img)

代码抱怨 roi 的大小。有没有更好的(pythonic)方式来做我想做的事?

您可以使用 Dilation and Erosion 形态学运算来查找 NxN 邻域的最大值和最小值。

    NxN 的
  • Dilation 等于 NxN 邻域的 maximum
  • NxN 的侵蚀 相当于 NxN 邻域的最小值

使用形态学操作使解决方案比“手动”将图像分成小块更简单。

您可以使用以下阶段:

  • 转换为 LAB 颜色 space 并获得 L 通道。
  • 使用“dilate”形态学操作(dilate相当于在NxN邻域中寻找最大像素)。
  • 使用“侵蚀”形态学操作(扩张相当于在NxN邻域中寻找最大像素)。
  • 将图像转换为 float 类型(在使用除法运算之前需要)。
  • 计算对比图(对比图范围为[0, 1])。
  • 将对比图转换为带舍入的 uint8 类型 - 转换会降低准确性,因此我不推荐它(但我假设您需要转换才能将输出作为图像)。

这是一个完整的代码示例:

import numpy as np
import cv2

size_n = 5 # NxN neighborhood around each pixel

# Read input image
img = cv2.imread('chelsea.png')

# Convert to LAB color space
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

# Get the L channel
L = lab[:, :, 0]

# Use "dilate" morphological operation (dilate is equivalent to finding maximum pixel in NxN neighborhood)
img_max = cv2.morphologyEx(L, cv2.MORPH_DILATE, np.ones((size_n, size_n)))

# Use "erode" morphological operation (dilate is equivalent to finding maximum pixel in NxN neighborhood)
img_min = cv2.morphologyEx(L, cv2.MORPH_ERODE, np.ones((size_n, size_n)))

# Convert to type float (required before using division operation)
img_max = img_max.astype(float)
img_min = img_min.astype(float)

# Compute contrast map (range of img_contrast is [0, 1])
img_contrast = (img_max - img_min) / (img_max + img_min)

# Convert contrast map to type uint8 with rounding - the conversion loosed accuracy, so I can't recommend it.
# Note: img_contrast_uint8 is scaled by 255 (scaled by 255 relative to the original formula).
img_contrast_uint8 = np.round(img_contrast*255).astype(np.uint8)

# Show img_contrast as output
cv2.imshow('img_contrast', img_contrast_uint8)
cv2.waitKey()
cv2.destroyAllWindows()

输入图像:

L 图片:

img_max:

img_min:

对比图img_contrast_uint8