【问题标题】:Normalizing images in OpenCV在 OpenCV 中标准化图像
【发布时间】:2016-10-27 19:23:02
【问题描述】:

我编写了以下代码来使用 OpenCV 中的 NORM_L1 对图像进行归一化。但输出图像只是黑色。如何解决?

import cv2
import numpy as np
import Image

img = cv2.imread('img7.jpg')
gray_image = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
a = np.asarray(gray_image)


dst = np.zeros(shape=(5,2))

b=cv2.normalize(a,dst,0,255,cv2.NORM_L1)


im = Image.fromarray(b)

im.save("img50.jpg")

cv2.waitKey(0)
cv2.destroyAllWindows()

【问题讨论】:

  • 使用 L1 标准化图像的动机是什么?

标签: python image opencv image-processing computer-vision


【解决方案1】:

如果要将范围更改为 [0, 1],请确保输出数据类型为 float

image = cv2.imread("lenacolor512.tiff", cv2.IMREAD_COLOR)  # uint8 image
norm_image = cv2.normalize(image, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)

【讨论】:

  • Python 要求我指定一个 dst 输入参数。在这种情况下,您可能希望将 norm_image 初始化为图像的副本并将其作为 dst 传递。
  • @ckirksey3 您只需将None 传递为dst。没有必要添加额外的代码行。
【解决方案2】:

当您使用 NORM_L1 对矩阵进行归一化时,您将每个像素值除以图像中所有像素的绝对值之和。 结果,所有像素值都远小于 1,您将获得黑色图像。试试 NORM_MINMAX 而不是 NORM_L1。

【讨论】:

  • 那么 NORM_MINMAX 到底发生了什么?
  • 最小像素值会映射到最小输出值(alpha),最大像素值会映射到最大输出值(beta)。我相信线性缩放介于两者之间。
  • NORM_MINMAX 沿着 ((pixel_value - alpha)/(beta - alpha)) * beta 的线计算。这符合@rsaxvc
【解决方案3】:

其他答案基于整个图像对图像进行归一化。但是,如果您的图像具有主要颜色(例如黑色),它将掩盖您要增强的功能,因为它不会那么明显。为了解决这个限制,我们可以根据感兴趣的子部分区域 (ROI) 对图像进行归一化。本质上,我们将根据我们想要增强的图像部分进行归一化,而不是用相同的权重同等对待每个像素。以这张地球图片为例:

输入图像->基于整幅图像的归一化

如果我们想通过基于整个图像的归一化来增强云层,结果将不会很清晰,并且会由于黑色背景而过度饱和。要增强的功能丢失了。因此,为了获得更好的结果,我们可以裁剪 ROI,基于 ROI 进行归一化,然后将归一化应用回原始图像。假设我们裁剪了以绿色突出显示的 ROI:

这给了我们这个投资回报率

想法是计算ROI的均值和标准差,然后根据上下限裁剪帧。此外,我们可以使用偏移量来动态调整剪辑强度。从这里我们将原始图像标准化到这个新范围。结果如下:

之前->之后

代码

import cv2
import numpy as np

# Load image as grayscale and crop ROI
image = cv2.imread('1.png', 0)
x, y, w, h = 364, 633, 791, 273
ROI = image[y:y+h, x:x+w]

# Calculate mean and STD
mean, STD  = cv2.meanStdDev(ROI)

# Clip frame to lower and upper STD
offset = 0.2
clipped = np.clip(image, mean - offset*STD, mean + offset*STD).astype(np.uint8)

# Normalize to range
result = cv2.normalize(clipped, clipped, 0, 255, norm_type=cv2.NORM_MINMAX)

cv2.imshow('image', image)
cv2.imshow('ROI', ROI)
cv2.imshow('result', result)
cv2.waitKey()

可以通过对结果应用热图来可视化基于整个图像与 ROI 的特定部分进行归一化之间的差异。请注意云的定义方式不同。

输入图片->热图

在整个图像上标准化->热图

在 ROI 上归一化 -> 热图

热图代码

import matplotlib.pyplot as plt
import numpy as np
import cv2

image = cv2.imread('result.png', 0)
colormap = plt.get_cmap('inferno')
heatmap = (colormap(image) * 2**16).astype(np.uint16)[:,:,:3]
heatmap = cv2.cvtColor(heatmap, cv2.COLOR_RGB2BGR)

cv2.imshow('image', image)
cv2.imshow('heatmap', heatmap)
cv2.waitKey()

注意:ROI边界框坐标使用how to get ROI Bounding Box Coordinates without Guess & Check获取,热图代码来自how to convert a grayscale image to heatmap image with Python OpenCV

【讨论】:

  • 优秀的答案。只是一个小兴趣点。我注意到应该能够使用 skimage rescale_intensity 将 np.clip 和 cv2.normalize 组合在一个命令中。见scikit-image.org/docs/dev/api/…
猜你喜欢
  • 2017-03-31
  • 2017-07-05
  • 1970-01-01
  • 2019-12-11
  • 2014-06-03
  • 2022-01-12
  • 1970-01-01
  • 2019-11-24
  • 2021-05-12
相关资源
最近更新 更多