opencv, Image 模块在单通道与三通道互相转换上的疑问与解答
一、前言
最近项目处理图片比较多,有时忘记改默认值,使得API将灰度图读成了三通道图,事后虽然改了过来,但很好奇二者后期转化的结果与原始读入的区别。本着动手多折腾的想法,抽个时间好好试验了一下,结果如下。
二、试验
1.opencv 模块
凡事先上代码,再谈结果,代码如下:
src_1 = cv2.imread(r"F:\demo\MS_DMS\add\0_\2.jpg", 0) # 正确读入单通道的方式
src_3 = cv2.imread(r"F:\demo\MS_DMS\add\0_\2.jpg") # 以三通道的方式读入
print(src_1)
gray = cv2.cvtColor(src_3, cv2.COLOR_BGR2GRAY) # 再将后者由三通道转换为单通道
list_ = ((gray == src_1).astype("int8")).tolist() # 转为列表,方便计算比对结果中 0(False) 的个数
print(list_.count(0))
结果为
src_1 =
[[148 149 150 ... 154 154 154]
[148 149 150 ... 154 154 154]
[148 150 151 ... 154 154 154]
...
[154 146 132 ... 213 195 154]
[144 135 130 ... 172 207 169]
[134 123 118 ... 210 180 199]]
list_.count(0) = 0 # 说明两个数组相等
由上可以看出,原始读入灰度图 与 先按三通道图读入,后面再转换为单通道图的方式相比,二者结果是相等的。再看看,单通道变为三通道是怎么变化的。
src_1 = [[148 149 150 ... 154 154 154]
[148 149 150 ... 154 154 154]
[148 150 151 ... 154 154 154]
...
[154 146 132 ... 213 195 154]
[144 135 130 ... 172 207 169]
[134 123 118 ... 210 180 199]]
src_3 = [[[148 148 148]
[149 149 149]
[150 150 150]
...
[154 154 154]
[154 154 154]
[154 154 154]]
[[148 148 148]
[149 149 149]
[150 150 150]
...
[154 154 154]
[154 154 154]
[154 154 154]]
[[148 148 148]
[150 150 150]
[151 151 151]
...
[154 154 154]
[154 154 154]
[154 154 154]]
...
[[154 154 154]
[146 146 146]
[132 132 132]
...
[213 213 213]
[195 195 195]
[154 154 154]]
[[144 144 144]
[135 135 135]
[130 130 130]
...
[172 172 172]
[207 207 207]
[169 169 169]]
[[134 134 134]
[123 123 123]
[118 118 118]
...
[210 210 210]
[180 180 180]
[199 199 199]]]
src_3[0:1, 0:1, :] = [[[148 148 148]]] # 打印了三通道图的第一个像素点的数值看了一下
比较长,大致看下就行,程序就是将单通道的数据单纯的复制了一下,使得其他2个通道的数据与另一个一样,这个从我特意打印的第一个像素点的数值可以看出来。像我们在pytorch中,数组形状是 (C, H, W),那样是个什么样子呢?
# 特意将数组形状转换了一下,数值表现如下:
src_3_ = [[[148 148 148 ... 152 152 152]
[152 152 149 ... 151 152 152]
[152 152 152 ... 154 154 154]
...
[157 157 157 ... 157 157 157]
[150 150 150 ... 172 172 191]
[191 191 208 ... 151 158 158]]
[[158 161 161 ... 155 155 155]
[150 150 150 ... 203 203 213]
[213 213 173 ... 144 158 158]
...
[ 96 96 68 ... 134 151 151]
[151 129 129 ... 163 163 163]
[142 142 142 ... 84 84 74]]
[[ 74 74 94 ... 122 115 115]
[115 95 95 ... 164 164 164]
[140 140 140 ... 110 110 116]
...
[134 134 134 ... 163 163 163]
[163 163 163 ... 165 166 166]
[166 166 166 ... 199 199 199]]]
src_3_.shape = (3, 74, 76)
2.Image 模块
ptyorch里这个模块用的比较多,所以也试验了一下。
src = Image.open(r"F:\demo\MS_DMS\add\0_\2.jpg")
print(np.array(src))
结果为:
[[[148 148 148]
[149 149 149]
[150 150 150]
...
[154 154 154]
[154 154 154]
[154 154 154]]
[[148 148 148]
[149 149 149]
[150 150 150]
...
[154 154 154]
[154 154 154]
[154 154 154]]
[[148 148 148]
[150 150 150]
[151 151 151]
...
[154 154 154]
[154 154 154]
[154 154 154]]
...
[[154 154 154]
[146 146 146]
[132 132 132]
...
[213 213 213]
[195 195 195]
[154 154 154]]
[[144 144 144]
[135 135 135]
[130 130 130]
...
[172 172 172]
[207 207 207]
[169 169 169]]
[[134 134 134]
[123 123 123]
[118 118 118]
...
[210 210 210]
[180 180 180]
[199 199 199]]]
Image的 open函数并没有按灰度图读取的设置(看了该函数的文档也没有什么发现),只有后期再将其转换为单通道图,所以pytorch读取单通道图时一般还要再转换一下。回到结果上面,这与opencv的结果是一致的,不信可以做个对比。
src2 = cv2.imread(r"F:\demo\MS_DMS\add\0_\2.jpg")
src = Image.open(r"F:\demo\MS_DMS\add\0_\2.jpg")
print(((src2 == np.array(src).astype("int8")).tolist()).count(0))
结果为 0 ,说明以不同API读取的两个数组结果是一样的。
此外,Image将单通道转为三通道也是直接将一个通道上的数据再复制两份,所以三个通道数据一样。
下面试试单通道结果。
src2 = cv2.imread(r"F:\demo\MS_DMS\add\0_\2.jpg", 0) # opencv按单通道读取图片
src = Image.open(r"F:\demo\MS_DMS\add\0_\2.jpg").convert("L") # Image将三通道转为单通道
print("src = ",np.array(src))
print(((src2 == np.array(src).astype("int8")).tolist()).count(0)) # 比对二者是否一样
结果为:
src = [[148 149 150 ... 154 154 154]
[148 149 150 ... 154 154 154]
[148 150 151 ... 154 154 154]
...
[154 146 132 ... 213 195 154]
[144 135 130 ... 172 207 169]
[134 123 118 ... 210 180 199]]
((src2 == np.array(src).astype("int8")).tolist()).count(0) = 0 # 为 0 表示上面两个数组是相等的
三、总结
经过这次试验,终于一解我心中疑惑,总结一下:
① opencv 按 单通道读取图片的结果 与 先按三通道读取图片再转为单通道的结果,二者一致的;
② Image 只能按三通道读取图片,其读取的三通道的结果与 opencv 的方式一致。转换为 单通道后,其结果也与 opencv 一致。
可能后面还有其他疑惑,再慢慢试验吧。舒服~~