我们先来看一个图像的混合,也就是相加操作。这个是有广播机制的,我们前面知道,不过一般是针对形状一样的图片,如果不一样,我们可以在画图里面调像素。
我分别用三种方法加了一下。
经过cv2.imread的图片的像素数组的dtype都是uint8。
这个cv2.add结果居然不一样哎。
这个产生差异的区别是,+和np.add是溢出舍弃机制,144+172=316-256=60,而cv2.add是饱和机制,注意下面有一个saturate,就是饱和的意思,超过255的全部取值为255,所以144+172>255,就直接取为255了,这个还会有负饱和,意思是小于0的都认为是0。而且cv2.add是没有广播机制的,有一句same size and same number of channels,这个可能会想到如果都是三通道,前两个维度乘积一样,但是数值不等可以吗?
事实证明是不行的。
下面就试一下减。
144-159=-15+256=241。144-159<0就是饱和了。乘除也都是如此,cv2的函数是cv2.multiply和cv2.divide,np的前面介绍过了,和cv2的函数名是一样的。并且它们都是元素相乘,而不是矩阵乘法,乘除对于cv2来说也有饱和。
我觉得我需要重新认识一下imshow。
注意看红圈里面的内容,意思是如果dtyp而是无符号8位整数,就正常显示,如果是16位无符号数或者32位整数,还是分成256份,意思就是说还是会映射到[0,255]之间,如果是32位或者64位浮点数,像素会乘以255,意思是[0,1]也会被映射到[0,255]。我们下面来验证一下:首先是默认的float64,255.0*255>255,我觉得这个应该按照饱和处理,就是255了,所以是白色。
下面这个也不难理解。
默认的整数类型是32位的有符号整数。这个除的话,我觉得应该是整除或者说地板除,255//256=0,所以是黑色。
16位这个我感觉应该要拿255/512*255,这个约等于128。
的确是灰色。
256没差多少。
为什么256是黑色,因为256溢出了,高位就被舍弃了,这里为什么不是饱和?因为上面是因为其实数据可以存得下,但是是经过了imshow的处理计算之后,不在[0,255]的范围内,所以表现出来是饱和,而这个是还没有经过imshow处理就已经溢出了,存不下了,对于溢出这样的问题,计算机的处理就是舍弃溢出位,然后00000000才进入imshow进行处理,所以是黑色。
数据类型还是很影响计算结果的。更改数据类型甚至可以影响数组的元素个可以去https://www.cnblogs.com/hhh5460/p/5129032.html
了解一下。这里举一个简单例子。
opencv还有一些统计的API,比np的方便一些。
cv.mean是求每一个通道的平均值,a图片B平均值为149.....,G为104...,R为130......,b图片分别为194,189,213,meanStdDev是求平均值和标准差。np.mean只能分别求单个通道的,最后还得组合一下,这个cv2的函数更直接。
上面是算术运算,我们还有逻辑运算。这个时候np就和cv2没有区别了,至少在目前应用的范围内是的。
看到其实效果是每个像素点得每个通道的结果都小于等于是亮度较小的值,原因是黑色是0,那么任意数和0与都是0。144和159相与,结果是144,这个是正好等于较小的值了。还有可能比min还要小。比如100 & 001。
那么或则正好相反,两张图片或的结果的每一个像素点的值大于等于任何一张,表现出来就是比任意一张都亮。
not的机制其实以前也说过,144+111=255,159+96=255。这个每一个对应位置的颜色都是互补色,因为加起来是[255,255,255]就是白色。前面的bitwise_and和bitwise_or应用在有一张图片是二值图(也就是非黑即白的图)的时候效果会比较特殊,因为纯黑是0,和任何数与都是0,结果都是黑,纯白是255,和任意数或都是255,结果都是白。
这种效果叫做遮罩。另外说一点,上面的timg.jpg我也是用画图把它的像素调成了200*298。
我们前面过滤颜色的时侯,出来的图片是二值图片,我们想要的颜色默认是白色,那么有没有方法让我们想要的颜色显示出来呢?就是说我只要蓝色,那么其它颜色就变成了黑色。这个怎么做呢?就可以利用inRange出来的是二值图,而且二值图具有遮罩的作用。
由于红色有两个区间,我们用两次inRange,最后按位或一下就可以了。e是我们得到的二值图,但是它只有一个通道,所以我们转换了一下,变成三个通道的e1,这样e1和a的尺寸就一样了,才不会报错,然后把e1和原来的a相与就可以实现我们想要的结果了。
这个也可以用mask做。参考了https://blog.csdn.net/u011028345/article/details/77278467
mask的要求就是单通道的dtype是uint8的数组。那么下面的代码也是可以的。
这个时候我们不需要我们把e转化成BGR了,可能cv2.bitwise_and里面都封装好了。不过由于mask前面还有一个dst参数,所以mask要有关键字mask=,不然第三个位置的参数会被认为是dst,就变成了a和a与,那结果还是a。
这个时候我们需要用到一个函数:cv2.addWeighted。
这个函数其实是把两张图的像素加权处理的,不过我们可以用这个函数来增强对比度,怎么增强呢?注意看有一个公式:dst=src1*alpha+src2*beta+gamma,我们让src2=0,gamma=0,那么alpha就是像素乘以的倍数,如果alpha>1,那么对比度就增强了,举一个例子,原来的4-2=2,只差了2,那么如果alpha=2,那么8-4=4,就差了4,差距大了,对比就明显了。增加亮度很简单,就只需要gamma>0,就是增加亮度。
144*1.2=172.8,四舍五入就是173。
这个也是有饱和的,144*2=288,饱和了,就是255了。
这个是提高亮度的一个效果。
这是降低亮度。
144+120=264>255。
再一次看到饱和和溢出的区别。
我们自己实现其实也不难的,首先要注意dtype,然后也就是要加判断语句来实现饱和这个有点麻烦,要用到三层循环,我觉得看到这里的大家应该都会。