Python 如何在 OpenCV 中将 16 位图像转换为 8 位图像?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25485886/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to convert a 16 bit to an 8 bit image in OpenCV?
提问by pap-x
I have a 16bit grayscale image and I want to convert it to a 8bit grayscale image in OpenCV for python to use it with various functions (like findContours etc.). Is it possible to do it in python or I have to switch to C++?
我有一个 16 位灰度图像,我想在 OpenCV 中将其转换为 8 位灰度图像,以便 python 将其与各种功能(如 findContours 等)一起使用。是否可以在 python 中完成,或者我必须切换到 C++?
回答by mdh
You can do this in Python using NumPy by mapping the image trough a lookup table.
您可以使用 NumPy 在 Python 中通过通过查找表映射图像来执行此操作。
import numpy as np
def map_uint16_to_uint8(img, lower_bound=None, upper_bound=None):
'''
Map a 16-bit image trough a lookup table to convert it to 8-bit.
Parameters
----------
img: numpy.ndarray[np.uint16]
image that should be mapped
lower_bound: int, optional
lower bound of the range that should be mapped to ``[0, 255]``,
value must be in the range ``[0, 65535]`` and smaller than `upper_bound`
(defaults to ``numpy.min(img)``)
upper_bound: int, optional
upper bound of the range that should be mapped to ``[0, 255]``,
value must be in the range ``[0, 65535]`` and larger than `lower_bound`
(defaults to ``numpy.max(img)``)
Returns
-------
numpy.ndarray[uint8]
'''
if not(0 <= lower_bound < 2**16) and lower_bound is not None:
raise ValueError(
'"lower_bound" must be in the range [0, 65535]')
if not(0 <= upper_bound < 2**16) and upper_bound is not None:
raise ValueError(
'"upper_bound" must be in the range [0, 65535]')
if lower_bound is None:
lower_bound = np.min(img)
if upper_bound is None:
upper_bound = np.max(img)
if lower_bound >= upper_bound:
raise ValueError(
'"lower_bound" must be smaller than "upper_bound"')
lut = np.concatenate([
np.zeros(lower_bound, dtype=np.uint16),
np.linspace(0, 255, upper_bound - lower_bound).astype(np.uint16),
np.ones(2**16 - upper_bound, dtype=np.uint16) * 255
])
return lut[img].astype(np.uint8)
# Let's generate an example image (normally you would load the 16-bit image: cv2.imread(filename, cv2.IMREAD_UNCHANGED))
img = (np.random.random((100, 100)) * 2**16).astype(np.uint16)
# Convert it to 8-bit
map_uint16_to_uint8(img)
回答by Vasanth
You can use numpy conversion methods as an OpenCV mat is a numpy array.
您可以使用 numpy 转换方法,因为 OpenCV mat 是一个 numpy 数组。
This works:
这有效:
img8 = (img16/256).astype('uint8')
回答by Raju Saladi
For converting from 16 bit to 8 bit using python openCV:
使用 python openCV 从 16 位转换为 8 位:
import numpy as np
import cv2
imagePath = "--"
img_8bit = cv2.imread(imagePath).astype(np.uint8)
回答by Thomas Van Der Weide
It's really easy to convert to 8-bit using scipy.misc.bytescale. The OpenCV matrix is a numpy array, so bytescale will do exactly what you want.
使用 scipy.misc.bytescale 转换为 8 位真的很容易。OpenCV 矩阵是一个 numpy 数组,因此 bytescale 将完全满足您的需求。
from scipy.misc import bytescale
img8 = bytescale(img16)
回答by A. Attia
Code from scipy (now deprecated):
来自 scipy 的代码(现已弃用):
def bytescaling(data, cmin=None, cmax=None, high=255, low=0):
"""
Converting the input image to uint8 dtype and scaling
the range to ``(low, high)`` (default 0-255). If the input image already has
dtype uint8, no scaling is done.
:param data: 16-bit image data array
:param cmin: bias scaling of small values (def: data.min())
:param cmax: bias scaling of large values (def: data.max())
:param high: scale max value to high. (def: 255)
:param low: scale min value to low. (def: 0)
:return: 8-bit image data array
"""
if data.dtype == np.uint8:
return data
if high > 255:
high = 255
if low < 0:
low = 0
if high < low:
raise ValueError("`high` should be greater than or equal to `low`.")
if cmin is None:
cmin = data.min()
if cmax is None:
cmax = data.max()
cscale = cmax - cmin
if cscale == 0:
cscale = 1
scale = float(high - low) / cscale
bytedata = (data - cmin) * scale + low
return (bytedata.clip(low, high) + 0.5).astype(np.uint8)

