【困惑实验记录】用cv2和PIL取出的像素值为何不同?cv2读出的是颜色三元组,PIL的getpixel是读取出该位置的实际像素值(该点存放的值)

结论(不一定正确,暂是个人理解)

  • PIL会自行判断出图像的模式是:1、L、P、RGB等哪一种(依次为二值图,灰度图,调色板图,真彩图),然后再调用image.getpixel((x,y))函数,则可得到该图该点的值,也就是图像中的真值(这个值不一定是反应到现实世界的像素色彩值,尤其是对于P模式尤为明显。在P模式中的这个值是映射到某一像素值的index,而且是P模式图像本身是8bit单通道图像,但是如果用cv2去逐像素读取像素值,会发现是正常的3元组像素值

  • cv2是会读出该图该点的颜色三元组,所以不管图像是什么模式的(P、L、RGB等)、多少bit的图(P、L:8bit,RGB:24bit),用cv2.imread(),注意是没有转成灰度图而是直接BGR读入的,反映出来的都是颜色三元组(三元组的顺序是BGR,记得要用image = image[...,::-1]来反一下变为RGB顺序)

    • mode=RGB时,像素值与颜色三元组相同
    • mode=P时,像素值是colormap中的index,但是cv2读出来的就是映射出来的真实颜色值,例如当前位置的像素值是6时,对应的就是index=6时的真实颜色值(128, 0, 0),可移步看另一篇博文:【困惑实验记录】调色盘,即PIL读出的P模式,常用于语义分割标签格式。1)如何固定设置某些index的颜色?2)怎么查看调色盘颜色?3)不设置调色盘颜色的话,是否每次都会转成不同的颜色?
    • mode=L时,颜色三元组中的每个值都是当前的像素值。例如像素值=100,那么cv2读出的颜色三元组就是(100, 100, 100)

实验代码

def getpixel_count(path):
    image = Image.open(path)
    # print(image.mode)  # P
    arr = []
    for w in range(image.size[0]):
        for h in range(image.size[1]):
            p = image.getpixel((w, h))
            if p not in arr:
                arr.append(p)
    print(arr)

    # 统计调色板情况
    palette = image.getpalette()  # 获取调色板
    count = Counter(np.array(image).flatten())
    print(count)
    return arr, count


def getpixel_cv(image_gray):
    arr = []
    dim = image_gray.ndim
    height, width = image_gray.shape[:2]
    for h in range(height):
        for w in range(width):
            if dim == 3:    # 如果是3维图像,即RGB,则倒一下才是正确的RGB顺序
                p = image_gray[h, w]
                p = (p[..., ::-1]).tolist()
            else:
                p = image_gray[h, w]

            if p not in arr:    # 如果p不存在与arr中,则插入到列表中
                arr.append(p)
    print(arr)


if __name__ == '__main__':
    # 自己来做一张灰度图
    # arr = np.array((300, 300, 3), dtype=np.uint8)
    # cv2.imwrite('self_gray.png', arr)
    #
    # self_gray_2 = Image.new(mode='L', size=(300, 300), color=1)  # 做一个灰度图
    # self_gray_2.save('self_gray_2.png')
    # print(self_gray_2.mode)
    # getpixel_cv(cv2.imread('self_gray_2.png', 0))
    #
    # gray2P = self_gray_2.convert('P')
    # gray2P.save('gray2P.png')
    # getpixel_cv(cv2.imread('gray2P.png', 0))
    #
    # # lbl_pil = Image.fromarray(gray2P.astype(np.uint8), mode="P")  # 转为uint8数据类型,调为P模式
    # colormap = imgviz.label_colormap()  # 获取颜色映射
    # gray2P.putpalette(colormap.flatten())
    # gray2P.save('lbl_pil.png')
    # getpixel_cv(cv2.imread('lbl_pil.png', 0))

    # 用cv2读取单通道图像,0 或者是等会再转为灰度图,再查像素,看是否与PIL的getpixel相同

    imagepath = r'D:\SoftWareInstallMenu\JetBrains\PycharmProjects\tunnel_datadeal\crackop\labels\001.png'  # 一张P模式的图

    print('------------- 原始mode -----------------')
    image = Image.open(imagepath)
    print(image.mode)  # 居然是RGB模式
    getpixel_count(imagepath)

    print('\n ------------- P -----------------')
    image_p = image.convert('P')
    print(image_p.mode)
    image_p.save('image_p.png')
    getpixel_count('image_p.png')
    getpixel_cv(cv2.imread('image_p.png'))

    print('\n ------------- L -----------------')
    image_L = image.convert('L')
    print(image_L.mode)
    image_p.save('image_L.png')
    getpixel_count('image_L.png')
    getpixel_cv(cv2.imread('image_L.png'))

    print('\n ------------- 1 -----------------')
    image_binary = image.convert('1')
    print(image_binary.mode)
    image_p.save('image_binary.png')
    getpixel_count('image_binary.png')
    getpixel_cv(cv2.imread('image_binary.png'))

    # -----------用cv2 灰度图读入,方式1---------- #
    print('\n-----------用cv2 单通道图读入-------')
    image_gray_1 = cv2.imread(imagepath, 0)
    # print(image_gray_1)
    getpixel_cv(image_gray_1)

    # -------方式2:正常BGR读入然后转为灰度图----------------- #
    image_bgr = cv2.imread(imagepath)
    image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_RGB2GRAY)
    # print(image_gray)
    getpixel_cv(image_gray)

    print((image_gray == image_gray_1).any())	# True,测试两种用cv2读取灰度图的值是否完全相同

运行结果

# ------------- 原始mode -----------------
# P
# [0, 1]
# Counter({0: 151769, 1: 1831})
# 
#  ------------- P -----------------
# P
# [0, 1]
# Counter({0: 151769, 1: 1831})
# [[0, 0, 0], [255, 0, 0]]
# 
#  ------------- L -----------------
# L
# [0, 1]
# Counter({0: 151769, 1: 1831})
# [[0, 0, 0], [255, 0, 0]]
# 
#  ------------- 1 -----------------
# 1
# [0, 1]
# Counter({0: 151769, 1: 1831})
# [[0, 0, 0], [255, 0, 0]]
# 
# -----------用cv2 灰度图读入-------
# [0, 76]
# [0, 29]
# True

你可能感兴趣的:(opencv,计算机视觉)