相关文章推荐
玩命的企鹅  ·  mvvm wpf 实例 - 百度·  1 年前    · 
暴躁的猴子  ·  access2013 ...·  2 年前    · 

如何在OpenCV中把16位图像转换为8位图像?

27 人关注

我有一张16位的灰度图像,我想在OpenCV for Python中把它转换成8位的灰度图像,以便用各种函数(如 findContours 等)来使用它。我怎样才能在Python中做到这一点?

4 个评论
In c++ its done with .convertTo . Maybe you can find it with this information. In addition if you want to convert to binary (e.g. for findContours) a simple > 0 operation might do the trick.
@Micka 即使我用你提到的方法改变了图像深度,OpenCV仍然会把图像当作16位图像。
对不起,对Python openCv无能为力。只有在C++ openCV方面有经验。
python
numpy
opencv
image-processing
pap-x
pap-x
发布于 2014-08-25
7 个回答
Vasanth
Vasanth
发布于 2022-02-23
已采纳
0 人赞同

你可以使用numpy转换方法,因为OpenCV的mat是一个numpy数组。

This works:

img8 = (img16/256).astype('uint8')
    
为了处理的目的,你可以添加另一个凹槽。 【替换代码0
mdh
mdh
发布于 2022-02-23
0 人赞同

你可以在Python中使用NumPy通过查找表对图像进行映射来做到这一点。

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)
    
uhoh
+1 的答案,尽管另一个答案更快 :)我想知道是否有可能直接使用 .clip(lb, ub) ,因为它能很好地处理 None
mdh
@uhoh clip() won't handle the case where lower_bound and upper_bound are both None . img.clip(None, None) raises ValueError: array_clip: must set either max or min
uhoh
老鼠!这是一个很好的观点。我对此感到惊讶;我想知道为什么决定不处理这种情况。这两个值可能来自不同的地方,而且事先不知道对方的情况。例如,在matplotlib中 plt.xlim(None, None) 就可以正常工作。好的,我会记住这一点的。谢谢!
had to modify here: if lower_bound is not None: if not(0 <= lower_bound < 2 16): raise ValueError( '"lower_bound" must be in the range [0, 65535]') if upper_bound is not None: if not(0 <= upper_bound < 2 16): raise ValueError( '"upper_bound "必须在[0, 65535]范围内')
Steven
Steven
发布于 2022-02-23
0 人赞同

Opencv provides the function cv2.convertScaleAbs()

image_8bit = cv2.convertScaleAbs(image, alpha=0.03)

Alpha只是一个可选的比例因子。也适用于多通道图像。

OpenCV 文件:

缩放,计算绝对值,并将结果转换为8位。

在输入数组的每个元素上,函数convertScaleAbs 依次进行三个操作:缩放、取绝对值、转换为无符号的8位类型。 值,转换为无符号8位类型。

Stackoverflow上的其他信息。OpenCV:如何使用convertScaleAbs()函数

Thomas Van Der Weide
Thomas Van Der Weide
发布于 2022-02-23
0 人赞同

使用scipy.misc.bytescale转换为8位真的很容易。OpenCV的矩阵是一个numpy数组,所以bytescale将完全按照你的要求来做。

from scipy.misc import bytescale
img8 = bytescale(img16)
    
替换代码0】在SciPy 1.0.0中被废弃,并将在1.2.0中被移除。
这已被skimage.util.img_as_ubyte取代。
A. Attia
A. Attia
发布于 2022-02-23
0 人赞同

来自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)
    
zoubin
zoubin
发布于 2022-02-23
0 人赞同

在Python中是可以的。为了得到预期的结果,根据你希望从uint16映射到uint8的值来选择一个方法。