【问题标题】:Why does histogram equalization on a 16-bit image show a strange result?为什么 16 位图像上的直方图均衡会显示奇怪的结果?
【发布时间】:2022-01-23 07:00:24
【问题描述】:

我有一个 16 位图像,我想在实现高对比度的同时将其重新缩放为 8 位。现在我尝试了如下直方图均衡:

image_equ = cv.equalizeHist(cv_image.astype(np.uint8))

但是输出超级奇怪:

发生了什么?首先重新缩放到 8 位可能是问题吗?

【问题讨论】:

  • .astype(np.uint8)) 是如何工作的?我想没有执行缩放,而只是重新解释,也许是饱和。您可以尝试在 .astype 之前将所有像素乘以 255/65535 吗?
  • 'cv_image = cv.equalizeHist(((cv_image*255/65535).astype(np.uint8)))' 比图像全黑:
  • @Micka 除以 x 并查看强度直方图,我可以看到很大的差距,只有数字越大,差距越大
  • 您必须在 histEqualization 之后缩放值。直方图均衡化后的最小像素值和最大像素值能读出来吗?
  • astype(uint8) 不会“重新缩放”。实际上,它只是将高位切掉(没有饱和数学),这会导致回绕,如图所示——equalizeHist 只能处理 8 位值。你必须先缩放它们。确保中间结果 (image*255) 具有合适的类型并且不会环绕。更好的是,像 image * (255/65535) 那样加上括号,因为 python 会浮动

标签: numpy opencv image-processing


【解决方案1】:

cv2.equalizeHist 不支持uint16 输入,cv_image.astype(np.uint8) 结果溢出。
解决方案是使用不同的库,或者使用 NumPy 实现均衡。

我们可以在 OpenCV 文档中找到 uint8 均衡的 NumPy 实现:
Histograms - 2: Histogram Equalization

我们可以为uint16输入和输出调整代码(使用NumPy):

  • 256 替换为65536(256 = 2^8 和 65536 = 2^16)。
  • 255 替换为65535
  • uint8 替换为uint16

假设原始代码是正确的,下面的代码应该适用于uint16

hist, bins = np.histogram(img.flatten(), 65536, [0, 65536])  # Collect 16 bits histogram (65536 = 2^16).
cdf = hist.cumsum()

cdf_m = np.ma.masked_equal(cdf, 0)  # Find the minimum histogram value (excluding 0)
cdf_m = (cdf_m - cdf_m.min())*65535/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_m,0).astype('uint16')

# Now we have the look-up table...
img2 = cdf[img]

完整的代码示例(构建示例 16 位输入):

import cv2
import numpy as np

# Build sample input for testing.
################################################################################
img = cv2.imread('chelsea.png', cv2.IMREAD_GRAYSCALE)  # Read sample input image.
cv2.imshow('img', img)  # Show input for testing.
img = img.astype(np.uint16) * 16 + 1000  # Make the image 16 bit, but the pixels range is going to be [1000, 5080] not full range (for example).
################################################################################

#equ = cv2.equalizeHist(img) # error: (-215:Assertion failed) _src.type() == CV_8UC1 in function 'cv::equalizeHist'

# https://docs.opencv.org/4.x/d5/daf/tutorial_py_histogram_equalization.html
hist, bins = np.histogram(img.flatten(), 65536, [0, 65536])  # Collect 16 bits histogram (65536 = 2^16).
cdf = hist.cumsum()

cdf_m = np.ma.masked_equal(cdf, 0)  # Find the minimum histogram value (excluding 0)
cdf_m = (cdf_m - cdf_m.min())*65535/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_m,0).astype('uint16')

# Now we have the look-up table...
equ = cdf[img]

# Show result for testing.
cv2.imshow('equ', equ)
cv2.waitKey()
cv2.destroyAllWindows()

输入(缩放到 16 位之前):

输出:

【讨论】:

    猜你喜欢
    • 2016-11-27
    • 2022-08-06
    • 2013-11-20
    • 1970-01-01
    • 1970-01-01
    • 2016-02-13
    • 1970-01-01
    • 1970-01-01
    • 2014-03-11
    相关资源
    最近更新 更多