结论(不一定正确,暂是个人理解)
-
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