OpenCV实战系列总目录
打印图像直接用这个函数:
import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
1、直方图
1.1 基本定义
图像中的直方图概念,将图像分解成像素点,直方图对像素点进行统计。
如左图读进来一个灰度图,用数值的形式展示出来,直方图就是统计0-255个像素值的分布情况,其中横坐标是0-255的像素值,纵坐标是每个像素值出现的次数。
需要用到这个函数:cv2.calcHist(images,channels,mask,histSize,ranges)
- images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如**[img]**
- channels: 同样用中括号括来它会告函数我们统幅图像的直方图。如果入图像是灰度图它的值就是 [0]如果是彩色图像 的传入的参数可以是 [0] [1] [2] 它们分别对应着 BGR。
- mask: 掩码图像。统整幅图像的直方图就把它为 None。但是如果你想统图像某一分的直方图的你就制作一个掩码图像并使用它。
- histSize:BIN的数目,也就是你需要多少根柱子,函数会自动按照柱子个数将取值范围均匀分布进去,也要用中括号括起来。
- ranges: 像素值范围常为 [0,256],python左闭右开嘛
所以后面两个参数基本不用改了。
1.2 代码实例
读进来一个小猫的灰度图,获取像素统计信息:
img = cv2.imread('cat.jpg',0) #0表示灰度图
hist = cv2.calcHist([img],[0],None,[256],[0,256])
print(hist.shape)
hist就是一个二维的ndarray,打印结果:
(256, 1)
将这个直方图用matplotlib画出来:
plt.hist(img.ravel(),256);
plt.show()
打印结果:
将刚刚的小猫图对三个颜色通道都进行统计:
img = cv2.imread('cat.jpg')
color = ('b','g','r')
for i,col in enumerate(color):
histr = cv2.calcHist([img],[i],None,[256],[0,256])
plt.plot(histr,color = col)
plt.xlim([0,256])
打印结果:
2 mask操作
怎样创建一个掩码,以及掩码的定义:
# 创建mast
mask = np.zeros(img.shape[:2], np.uint8)
print (mask.shape)
mask[100:300, 100:400] = 255
cv_show(mask,'mask')
打印结果:
(414, 500)
这个掩码只有两部分,一部分为黑一部分为白,当把这个掩码图像和原始图像结合在一起的效果就是图三。掩码图像和原始图像大小是一样的,掩码覆盖的地方设置成255,其他地方设置成0,掩码图像和原始图像结合相当于截取操作。
掩码的定义,就是利用np.zeros来定义,大小按照图像长宽的尺寸,然后按照数组的索引范围选择要保存的部位,把要保存的地方全部赋值为255。
把原始图像读进来:
img = cv2.imread('cat.jpg', 0)
cv_show(img,'img')
打印结果:
将原始图像和掩码图像做与操作:
masked_img = cv2.bitwise_and(img, img, mask=mask)#与操作
cv_show(masked_img,'masked_img')
对带掩码和不带掩码的图像都做一下直方图统计,通过子图的方式进行展示:
3、直方图的均衡化
如图这个直方图的像素分布特别不均匀,如何让他的像素分布稍微均匀一点呢?
均衡化的过程就是像素值的分布从左1变成左2,最后的效果是左3
比如下图的这两个个像素点表格,左边是原始图像,右边是均衡化后的图像。将原来的像素分布用一个固定的计算方法映射到另一个分布:
这个过程是怎么做的呢?
- 将像素值从大到小进行统计,如上图的第三个表格有四个像素值以及个数的统计,根据统计结果,将每个像素对应出现的概率如表格所示计算出来
- 按照大小进行计算累积概率。比如像素值为50的有4个,概率为0.25,累积概率仍为0.25,如果是128,有3个,概率为0.1875,累积概率就会加上它自己以及比它小的所有像素的概率,所以是0.4375,依次类推。
- 得到所有像素值的累积概率,再乘上像素的取值范围再取整。
读进来一个小猫的灰度图,获取像素统计信息:
img = cv2.imread('clahe.jpg',0) #0表示灰度图 #clahe
plt.hist(img.ravel(),256);
plt.show()
打印结果:
进行均衡化处理:
equ = cv2.equalizeHist(img)
plt.hist(equ.ravel(),256)
plt.show()
打印结果:
将均衡化处理前后的图作比较:
res = np.hstack((img,equ))
cv_show(res,'res')
打印结果:
换成lena的图:
4、自适应均衡化
均衡化实际上是整体上对像素进行了一个平均的处理操作,这意味着可能会丢失一些细节。那如何避免出现这种情况呢?我们可以将图像分成若干个部分,然后各个部分做自己的均衡化,这样就缓冲了细节的丢失。
在openCV中已经给了我们一些现成的函数来进行这个操作,这就是自适应直方图均衡化。
首先将自适应直方图均衡化的方法生成出来:
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
然后将这个自适应方法应用到当前的输出当中,将原始图像、均衡化处理图像、自适应均衡化处理图像都打印出来:
res_clahe = clahe.apply(img)
res = np.hstack((img,equ,res_clahe))
cv_show(res,'res')
打印结果:
如上图的1、2、3,很显然3图在细节的处理和保留比2要强出很多。