【困惑实验记录】用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顺序)


实验代码

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孟孟单单

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值