Matplotlib显示Trunc和TOZERO_INV阈值分割结果不合预期
笔者在学习到OpenCV的阈值分割时,试图用Matplotlib显示分割以后的图片。
我用于处理的图片如图:
使用THRESH_TRUNC模式分割,代码如下:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('gradient.jpg', 0)
ret, th = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
plt.figure(figsize=(8, 6), dpi=100)
plt.imshow(th, 'gray')
预期呈现的图片如图:
然而输出结果并不符合我的预期——
经检查发现,以灰度图模式读入、再用THRESH_TRUNC或THRESH_TOZERO_INV模式处理后,都会产生类似的不合预期的结果;而以彩色图模式读入文件作同样处理,产生的结果就是符合预期的:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('gradient.jpg', 0)
ret, th = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
plt.figure(figsize=(8, 6), dpi=100)
plt.imshow(th, 'gray')
再次运行,产生了符合预期的结果。
事后笔者分析认为,问题出在matplotlib不能区别灰度图与二维数组,误将我们的灰度图当作二维数组处理,从而导致了错误的结果。具体分析如下——
因为一个彩色图像传入opencv处理成灰度图,从opencv的角度无非就是把一个三维数组通过计算转换成另一个二维数组;但是matplotlib并不会把二维数组当作灰度图,所以把这个“灰度图”给matplotlib绘制的时候,它绘制的其实是这个二维数组的可视化图像,这样matplotlib画出的图像就有可能和opencv画出来的不一样。笔者画图的时候调了一下matplotlib的colorbar,发现cmap设置成’gray’时,它默认把二维数组的元素取值的最大值设置为白色 ,最小值设置为黑色,证实了我的猜测:
(使用其他分割方法也存在这样的问题,只是其他分割方式分割完毕后数组元素的取值范围为[0, 255],正好避免了这样的问题。)
鉴于此,建议各位以后再使用matplotlib绘图时不应直接在自己的程序内把图像转换为灰度图,否则有可能产生错误的绘图结果。笔者建议通过其他软件将彩色图转化为灰度图后再以彩色图模式传入matplotlib绘图。
参考资料:http://codec.wang/#/opencv/start/06-image-thresholding
OpenCV官方文档
matplotlib官方文档