Closed hwZhang98 closed 5 years ago
在前面的回答 #8 中,我疏忽了语法问题,Numpy 数组 RGB 转 BGR 应该是:
IMG_URL = "lenna.jpg"
img = Image.open(IMG_URL).convert('RGB')
plt.imshow(np.array(img)[:,:,::-1])
plt.show()
我之前给出的 plt.imshow(np.array(img)[:,:,-1])
作用是显示索引为 -1
的通道,即绿色通道。
回到这个问题,先看一个我机器上的对比例程:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img = Image.open('lenna.jpg')
img = np.array(img)
if img.ndim == 3:
img = img[:,:,1]
plt.subplot(221); plt.imshow(img)
plt.subplot(222); plt.imshow(img, cmap ='gray')
plt.subplot(223); plt.imshow(img, cmap = plt.cm.gray)
plt.subplot(224); plt.imshow(img, cmap = plt.cm.gray_r)
plt.show()
我想你现在已经知道理想输出的情况是什么了,而且分析了这么多,我们可以认为 plt.imshow()
这个函数在你的机器上没有体现出差异。
split()
分离出三通道后,得到的是 3 个单通道的 PIL 图片对象plt.imshow()
对于 PIL 和 Numpy 的显示机制不一样,用代码来显示这个差异就是:
IMG_URL = "lenna.jpg"
img = Image.open(IMG_URL).convert('RGB')
plt.subplot(1,2,1)
plt.imshow(img.split()[1]) # PIL (without cmap setting)
plt.subplot(1,2,2)
plt.imshow(np.array(img)[:,:,1]) # numpy
plt.show()
如果我对你的问题理解没有出错,你运行上面这段代码,可能会得到效果相同的图片 : ( 就像下面这样
而通过观察 Numpy 数组我们排除了 convert('L')
的嫌疑
所以问题是 imshow.()
对于单通道的 PIL 图片没有按照默认的灰度图方式去显示...
这个问题在其他人的机器上能复现吗?因为产生这样的情况的原因不好分析了,只能用 cmap='gray'
临时纠正这种问题。
如果的确是 matplotlib
不能够很好地显示图片,你可以使用 PIL
自带的显示方式看看效果:
img = Image.open(IMG_URL, 'r').convert('L')
img.show() # 不用带参数
我们只能猜测 WTF , matplotlib
的 imshow()
不够智能,在我机器上的 matplotlib
是 3.0.2 版本,一切都是正常的。
不要因为这个地方的一些小 BUG 打击自信心,你已经做得相当好了!
谢谢助教,自己去钻研也确实搞明白很多东西
我现在在想的是,是不是由于 plt.imshow()
的默认显示方式设置出现了问题,你尝试运行下面这个代码:
import matplotlib.pyplot as plt
plt.gray()
官方文档在这里 , 我帮你大概翻译一下:
将 colormap
设置为 “gray” - 这会更改默认的 colormap
以及当前图像的 colormap
(如果有的话).
它的源码也很简单:
def gray():
"""
Set the colormap to "gray".
This changes the default colormap as well as the colormap of the current
image if there is one. See ``help(colormaps)`` for more information.
"""
set_cmap("gray")
如果的确是这个原因,这将一劳永逸地解决你的问题。
这也说明可能你在 python 练习笔记本中玩 matplotlib
的时候对默认的参数不小心进行了改动。
可以了,加上这句代码后,结果正常了,但是imshow()依然没有在我的机器上体现出差异,convert可以正常使用了,结果如下
行,先这样处理吧,周五的时候线下再看看。:blush:
在看过助教给的博客和可能BUG分析后,我又专门的进行了尝试,首先全部代码如下: `from PIL import Image import numpy as np import matplotlib.pyplot as plt
IMG_URL = "lenna.jpg" img = Image.open(IMG_URL) print('img mode'+str(img.mode)) img_np = np.array(img) plt.subplot(1,2,1) plt.imshow(img) print('img size'+str(img.size)) print('img_np shape'+str(img_np.shape)) print('img_np size'+str(img_np.size))
img_1 = img.convert('L') img_1_np = np.array(img_1) print('img_1 mode'+str(img_1.mode)) plt.subplot(1,2,2) plt.imshow(img_1) print('img_1 size'+str(img_1.size)) print('img_1_np shape'+str(img_1_np.shape)) print('img_1_np size'+str(img_1_np.size)) print('Value range from ' + str(img_1_np.min()) + ' to ' + str(img_1_np.max())) plt.show() print(img_1_np)
下面为分离通道测试------------------------------------------------------------------------分割线
img_r, img_g, img_b = img.convert('RGB').split()
plt.figure(figsize=(10,10)) # 调整子图大小 plt.subplots_adjust(wspace =0.5, hspace =0.5) # 调整子图间距
plt.subplot(2,3,1) plt.imshow(img_r) # 红色 Red plt.xlabel('red channel')
plt.subplot(2,3,2) plt.imshow(img_g) # 绿色 Green plt.xlabel('green channel')
plt.subplot(2,3,3) plt.imshow(img_b) # 蓝色 Blue plt.xlabel('blue channel')
plt.subplot(2,3,4) plt.imshow(img_np[:, :, 0]) # 红色 Red plt.xlabel('red channel2')
plt.subplot(2,3,5) plt.imshow(img_np[:, :, 1]) # 绿色 Green plt.xlabel('green channel2')
plt.subplot(2,3,6) plt.imshow(img_np[:, :, 2]) # 蓝色 Blue plt.xlabel('blue channel2')
plt.show()` 博客指出问题可能是以下两种情况 1.第一种是用open打开函数后,图片为错误的两维图片而不是三维,会将强制性把图片认为是灰度图格式。运行一次代码,结果如下:
可以看到,图片转化为矩阵后的维度没有问题,是三维的,并且mode也为RGB模式,所以第一种情况排除。 2.第二种是如果是三维的图片,可能打开的图片错误的用BGR格式打开,此时需要转化为RGB,我用博客上的方法进行转化后,结果如下: 可以看到输入的原图因为格式的原因发生了变化,所以说明输入的本来就是RGB格式,第二种情况也排除。 接下来我又进行了思考和分析,首先进行convert转化为灰度模式后,img_1的模式确实是‘L’,说明确实是灰度模式,接着我发现这个图和应该正常的结果像素大小范围也是一样的,并且矩阵中每一个元素都一样。。。也就是模式一样都是L,矩阵元素也都一样,可是显示出来却不对,对比如下: 接下来我又分离三通道,也就是分割线之下的代码,发现了和示例不一样的地方,文档说用手动分离和用函数分离得到的单通道图不一样,可是我的经过分离之后,两种情况却一样。。。。无语了。。下图是示例结果,接着是我的结果: 我觉得已经超出我能力范围了,因为确实一些函数文档全英我看的很吃力,只能看懂一部分,而且明明模式一样,每个像素矩阵也一样,为什么显示就不一样