当最大像素值小于 65535 时,如何标准化 uint16 图像并将其转换为 uint8?

Len*_*nGF 1 opencv normalize python-3.x scikit-image

当 uint16 图像的最大像素值不是 65535(它小于该值)(实际上是 2970)时,我需要将图像从 uint16 转换为 uint8,以便将其保存到磁盘。我注意到 scikit-image 有用于此类转换的方法img_as_ubyte 。看来这个方法将 65535 转换为 255,并且所有值都与此成比例。问题是图像的最大值为 2000,转换为 12 后会损失大量分辨率。我也在考虑将图像保存为 numpy

我尝试使用此处提出的 rescale 函数以及 cv2.normalize 函数。但是,我注意到 cv2.normalize 函数创建了dtype=uint16的图像。

另外,我检查了 matlab 中的 mat2gray,发现 cv2.normalize 与 mat2gray 比普通 python 中带有标准化函数的方法更相似。

使用普通的Python:

orig_min = mammogram_dicom.min()
orig_max = mammogram_dicom.max()
target_min = 0.0
target_max = 255.0
mammogram_scaled = (mammogram_dicom-orig_min)*((target_max- 
target_min)/(orig_max-orig_min))+target_min
mammogram_uint8_by_function = mammogram_scaled.astype(np.uint8)
Run Code Online (Sandbox Code Playgroud)

我觉得使用 np.uint8 很奇怪,我宁愿不使用它,但这是我进入 uint 8 的唯一方法

对于 cv2.normalized 我还必须使用 np.uint8 来获取 uint8:

mammogram_uint8_by_cv2 = np.zeros(mammogram_dicom.shape).astype(np.uint8)
mammogram_uint8_by_cv2 = cv2.normalize(mammogram_dicom, None, 0, 255, cv2.NORM_MINMAX)
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法将 uint16 转换为 uint8 这个图像?

我期待与 matlab 中的 mat2gray 类似或更好的行为。我对来自 matlab 的同一张图像和用上面的代码计算的图像进行了比较。Cv2 归一化是最相似的。使用 rescale 函数的方法(我称之为 plain python)看起来与肉眼相似,但有所不同:mat2gray_from_matlab_image - plain_python_image

与 1 个像素的值有一些差异

有没有办法标准化 scikit-image 内的图像?

Ste*_*tef 6

1)OpenCV解决方案

如果未指定,OpenCVnormalize将返回与源类型相同的图像。要在不使用 numpy 的情况dtpye下标准化a :uint16uint8

mammogram_uint8_by_cv2 = cv2.normalize(mammogram_dicom, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
Run Code Online (Sandbox Code Playgroud)

2)Skimage解决方案

首先将rescale图像转换为全范围并将其转换为uint8使用img_as_ubyte

from skimage import exposure, img_as_ubyte
mammogram_uint8_by_ski = img_as_ubyte(exposure.rescale_intensity(mammogram_dicom))
Run Code Online (Sandbox Code Playgroud)