内容
1. 计算机视觉与图像处理
1.1 什么是计算机视觉?
1.2 什么是图像处理?
1.3 计算机视觉和图像处理的关系
2. 图像处理工具包
2.1 PIL:Python图像处理类库
2.1.1 Python安装PIL
2.1.2 Image对象
2.1.3 转换图像格式
2.1.4 创建缩略图
2.1.5 复制和粘贴图像区域
2.1.6 调整尺寸和旋转
2.2 Matplotlib类库
2.2.1 绘制图像、点和线
2.2.2 绘制图像的格式
2.3 OpenCV视觉库
2.3.1 基本操作
3.2 OpenCV读取和PIL读取的差异
3.图像直方图和直方图均衡化
3.1 图像直方图
3.1.1 图像直方图的定义
3.1.2 图像直方图的性质
3.1.3 绘制直方图
3.2 直方图均衡化
3.2.1 直方图均衡化的定义
3.2.2 基本思想
3.2.3 编程实现
四、高斯滤波
4.1 什么是高斯滤波?
4.2 基本原理
4.3 使用示例
1. 计算机视觉与图像处理
从20世纪中期至今,计算机视觉不断发展,研究经历了从二维图像到三维到视频再到真实空间的探知,操作方法从构建三维向特征识别转变,算法由浅层神经网络到深度学习,数据的重要性逐渐被认知,伴随着计算机从理论到应用的速度加快,高质量的各种视觉数据不断沉淀,无论在社会经济农业还是工业领域,还是视频直播、游戏、电商不断发展,有计算机视觉应用层出不穷,为我们生活添加了丰富色彩,那么计算机视觉到底是什么?
1.1 什么是计算机视觉?
计算机视觉是一门研究如何让机器“看见”的科学。更具体地说,是指用照相机和计算机代替人眼对目标进行识别、跟踪和测量,并进一步进行图形处理,使计算机处理。它成为更适合人类观察或传输到仪器进行检测的图像。计算机视觉也可以被视为如何使人工系统从图像或多维数据中“感知”的科学。
简单来说,计算机视觉是人工智能的一个重要分支。它需要解决的问题是理解图像的内容。给定一幅二维图像,计算机视觉系统必须识别图像中的物体及其特征,如形状、纹理、颜色、大小、空间排列等,以尽可能完整地描述图像。
例如,如下图所示:
- 图中有多少人?
- 图中的人在做什么?
- 这张照片的背景是什么?
我们人类能够理解和描述图像中的场景。我们眼睛可以检测到图片里有两个人,且一男一女,他们在海边。除了这些基本信息,我们还能够看出图像中看到,女生穿着浅绿色衣服,男生穿的白色T恤,并且他们两都穿着黑色运动短裤,在沙滩上跑步。我们还可以理性地推断出图中人物是外国人,女生的头发是金色,男生的头发是褐色。我们从材质与纹理方面,还能描述出男生的裤子相较于女生的裤子比较宽松。
以上也是计算机视觉系统所需的技能。
1.2 什么是图像处理?
一幅图像可以定义成一个二维空间函数,即 I = f(x,y),I 是二维空间,x和y是空间中的坐标,f是位于二维空间中x和y坐标处的灰度值,即使在计算机中可以把图像看做一个矩阵。
图像处理(狭义)是对输入图像进行一些变换得到输出图像,是一个图像到图像的过程。主要是指对图像进行各种操作以提高图像的视觉效果,或者对图像进行压缩和编码以减少所需的存储空间或传输时间,以及传输路径的要求,包括图像增强、图像恢复和重建、图像编码。
1.3 计算机视觉和图像处理的关系
图像处理旨在处理原始图像以应用一些变换,通常是为了改进图像或将其用作特定任务的输入,而计算机视觉旨在描述和解释图像。计算机视觉使用机器学习技术对图像处理进行建模。计算机视觉应用机器学习来识别解释图像的模式。就像人类视觉的视觉推理过程一样;我们可以区分物体,分类它们,根据它们的大小对它们进行分类等。
2. 图像处理工具包
在深度学习领域,图像和视频样本的处理占很大比例。同样,对于计算机视觉,基本的图像处理操作也很重要。图像处理结果的好坏可能直接影响研究结果。下面我将介绍一些关于图像处理的基础知识。
2.1 PIL:Python图像处理类库
PIL(Python Imaging Library,图像处理类库) 提供了通用的图像处理功能,以及大量有用的基本图像操作,比如:打开显示,灰度转换,图像缩放,旋转,裁剪等。PIL功能非常强大,但API却非常简单易用。
2.1.1 Python安装PIL
PIL仅支持到Python2.7以下的版本,加上年久失修,于是一群志愿者在PIL的基础上创建了兼容的版本,名字叫Pillow,支持最新Python 3.x,又加入了许多新特性,因此,如果我们python的版本比较高,我们可以直接安装使用Pillow。
安装Pillow需要对应满足版本的pip,所以安装前最好更新一下pip,不然容易安装失败!
python -m pip install --upgrade pip
然后在命令行下直接通过pip安装:
pip install pillow
安装完成后,我们可以在命令行输入:
pip list
我们就可以看到安装好的pip和Pillow的版本了。
2.1.2 Image对象
利用 PIL 中的函数,我们可以从大多数图像格式的文件中读取数据,然后写入最常 见的图像格式文件中。PIL 中最重要的模块为 Image,使用下列导包方式引入 Image 模块:
from PIL import Image
1)创建Image对象
使用 Image 类可以实例化一个 Image 对象,通过调用该对象的一系列属性和方法对图像进行处理。Pilow 提供了两种创建 Image 实例对象的方法,下面对它们进行简单的介绍。
方法一:open()
使用 Image 类的 open() 方法,可以创建一个 Image 对象,语法格式如下:
img = Image.open(fp, mode="r")
参数说明:
- fp:即 filepath 的缩写,表示文件路径,字符串格式;
- mode:可选参数,若出现该参数,则必须设置为 “r”,否则会引发 ValueError 异常。
使用示例:
from PIL import Image
# 读取图片,返回一个PIL图像对象
img = Image.open('C:/Users/Administrator/Desktop/picture1.jpg')
# 显示图片,调用 show()方法
img.show()
输出结果:
方法二:new()
使用 Image 类提供的 new() 方法可以创建一个新的 Image 对象,语法格式如下:
img = Image.new(mode, size, color)
参数说明:
- mode:图像模式,字符串参数,比如 RGB(真彩图像)、L(灰度图像)、CMYK(色彩图打印模式)等;
- size:图像大小,元组参数(width, height)代表图像的像素大小;
- color:图片颜色,默认值为 0 表示黑色,参数值支持(R,G,B)三元组数字格式、颜色的十六进制值以及颜色英文单词
使用示例:
# 使用颜色的十六进制格式
img2 = Image.new(mode='RGB', size=(500,500), color="#98e9e7")
img2.show()
输出结果:
在文件目录下,读取多张图片:
如果某个文件夹中有多张图片,我们可以写一个函数进行批处理:
import os
# 返回目录中所有JPG 图像的文件名列表
def get_imlist(path):
return [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.jpg')]
运行测试:
if __name__ == '__main__':
img_list = get_imlist('C:\\Users\\Administrator\\Desktop\\Test1')
for str in img_list:
print(str)
如下面这个文件夹,可以知道,上面运行结果是正确读取出了JPG图像,共六张。
2) Image对象属性
Image 对象有一些常用的基本属性,我们来了解一下这些图片的基本信息:
属性 | 说明 |
size | 图像的尺寸 |
format | 图片的格式 |
readonly | 图片是否为只读 |
info | 图片相关信息 |
mode | 图像模式 |
from PIL import Image
# 读取图片
img = Image.open('C:/Users/Administrator/Desktop/picture1.jpg')
# 查看图片尺寸
# 方式一: 直接打印
print(img)
# 方式二: 分别打印图片宽高
print("图像的宽:", img.width, "; 图像的高:", img.height)
# 方式三: 打印图片尺寸
print("图像的大小:", img.size)
# 查看图片的格式
print("图像的格式:", img.format)
# 查看图像是否为只读: 是返回为0, 否为1
print("图像是否为只读:", img.readonly)
# 查看图片相关信息: 返回值为字典格式
print("图像信息:", img.info)
# 查看图像模式
print("图像模式信息:", img.mode)
2.1.3转换图像格式
通过 save() 方法,PIL 可以将图像保存成多种格式的文件。save() 方法保存图像,当不指定文件格式时,它会以默认的图片格式来存储;如果指定图片格式,则会以指定的格式存储图片。save() 的语法格式如下:
Image.save(fp, format=None)
参数说明:
- fp:图片的存储路径,包含图片的名称,字符串格式;
- format:可选参数,可以指定图片的格式。
from PIL import Image
# 读取图片
img = Image.open('C:/Users/Administrator/Desktop/picture.jpg')
# 把图像图片格式由jpg改成png
img.save('C:/Users/Administrator/Desktop/picture.png', 'PNG')
运行结束后,生成了一个格式为png的图片。
2.1.4创建缩略图
缩略图(thumbnail image)指的是将原图缩小至一个指定大小(size)的图像。通过创建缩略图可以使图像更易于展示和浏览。
Image 对象提供了一个 thumbnail() 方法用来生图像的缩略图,该函数的语法格式如下:
thumbnail(size,resample)
参数说明:
- size:元组参数,指的是缩小后的图像大小;
- resample:可选参数,指图像重采样滤波器,有四种过滤方式,分别是 Image.BICUBIC(双立方插值法)、PIL.Image.NEAREST(最近邻插值法)、PIL.Image.BILINEAR(双线性插值法)、PIL.Image.LANCZOS(下采样过滤插值法),默认为 Image.BICUBIC。
使用示例:
from PIL import Image
# 读取图片
img = Image.open('C:/Users/Administrator/Desktop/Test1/picture1.jpg')
# 制定缩略尺寸
img.thumbnail((500, 100))
print("缩略图尺寸:", img.size)
输出结果:
有时候,缩略图的尺寸可能与我们指定的尺寸不一致,这是因为 Pillow 会对原图像的长、宽进行等比例缩小,当指定的尺寸不符合图像的尺寸规格时,缩略图就会创建失败, 比如指定的尺寸超出了原图像的尺寸规格。
2.1.5复制和粘贴图像区域
拷贝、粘贴操作几乎是成对出现的,Image 类提供了 copy() 和 paste() 方法来实现图像的复制和粘贴。
1)复制:copy()方法
使用 crop()
方法从图像中裁剪指定区域:
box = (left, top, right, bottom)
img.crop(box) # img是读取的图片对象
参数说明:
- box 该图像中的一个矩形方块,是一个含有 4 个元素的元组:(left, top, right, bottom),表示矩形左上角与右下角的坐标。
2)粘贴:paste()方法
paste() 粘贴方法,该函数的作用是将一张图片粘贴至另一张图片中,粘贴后的图片模式将自动保持一致,不需要进行额外的转换。语法格式如下所示:
paste(image, box=None, mask=None)
参数说明:
- image:指被粘贴的图片;
- box:指定图片被粘贴的位置或者区域,其参数值是长度为 2 或者 4 的元组序列,长度为 2 时,表示具体的某一点 (x,y);长度为 4 则表示图片粘贴的区域,此时区域的大小必须要和被粘贴的图像大小保持一致。
- mask:可选参数,为图片添加蒙版效果。
使用示例:
from PIL import Image
# 读取图片
img = Image.open('C:/Users/Administrator/Desktop/Test1/picture1.jpg')
# 复制原图片副本
img_copy = img.copy()
# 对副本进行裁剪
box = (1000, 1000, 3000, 3000)
region = img_copy.crop(box)
# 旋转180°上面获取的区域
region = region.transpose(Image.ROTATE_180)
# 将裁剪后的副本粘贴至副本图像上
img.paste(region, box)
# 显示粘贴后的图像
img.show()
输出结果:
2.1.6调整尺寸和旋转
1)调整尺寸
在图像处理过程中经常会遇到缩小或放大图像的情况,Image 类提供的 resize() 方法能够实现任意缩小和放大图像。
resize() 函数的语法格式如下:
resize(size, resample=image.BICUBIC, box=None, reducing_gap=None)
参数说明:
- size:元组参数 (width,height),图片缩放后的尺寸;
- resample:可选参数,指图像重采样滤波器,与 thumbnail() 的 resample 参数类似,默认为 Image.BICUBIC;
- box:对指定图片区域进行缩放,box 的参数值是长度为 4 的像素坐标元组,即 (左,上,右,下)。注意,被指定的区域必须在原图的范围内,如果超出范围就会报错。当不传该参数时,默认对整个原图进行缩放;
- reducing_gap:可选参数,浮点参数值,用于优化图片的缩放效果,常用参数值有 3.0 和 5.0
使用示例:
from PIL import Image
# 读取图片
img = Image.open('C:/Users/Administrator/Desktop/Test1/picture1.jpg')
# 调整尺寸
img1 = img.resize((128, 128))
# 输出图片
img1.show()
输出结果:
注意:
1. resize()方法可以缩小也可以放大,而thumbnail()方法只能缩小;
2. resize()方法不会改变对象的大小,只会返回一个新的Image对象,而thumbnail()方法会直接改变对象的大小,返回值为none;
2) 图片旋转
Image 类提供了函数rotate(),可以任意角度旋转:
Image.rotate(angle, resample=PIL.Image.NEAREST, expand=None, center=None, translate=None, fillcolor=None)
参数说明:
- angle:表示任意旋转的角度;
- resample:重采样滤波器,默认为 PIL.Image.NEAREST 最近邻插值方法;
- expand:可选参数,表示是否对图像进行扩展,如果参数值为 True 则扩大输出图像,如果为 False 或者省略,则表示按原图像大小输出;
- center:可选参数,指定旋转中心,参数值是长度为 2 的元组,默认以图像中心进行旋转;
- translate:参数值为二元组,表示对旋转后的图像进行平移,以左上角为原点;
- fillcolor:可选参数,填充颜色,图像旋转后,对图像之外的区域进行填充。
使用示例:
from PIL import Image
# 读取图片
img = Image.open('C:/Users/Administrator/Desktop/Test1/picture1.jpg')
# 旋转45°
img1 = img.rotate(45)
# 输出图片
img1.show()
输出结果:
2.2 Matplotlib类库
我们处理数学运算、绘制图表,或者在图像上绘制点、直线和曲线时,Matplotlib是个很好的类库,具有比 PIL 更强大的绘图功能。Matplotlib可以绘制出高质量的 图表,就像本书中的许多插图一样。Matplotlib 中的 PyLab 接口包含很多方便用户创建图像的函数。
2.2.1绘制图像、点和线
尽管 Matplotlib 可以绘制出较好的条形图、饼状图、散点图等,但是对于大多数计 算机视觉应用来说,仅仅需要用到几个绘图命令。最重要的是,我们想用点和线来表示一些事物,比如兴趣点、对应点以及检测出的物体。下面是用几个点和一条线绘制图像的例子:
from PIL import Image
from pylab import *
# 读取图像到数组中
img = array(Image.open('C:/Users/Administrator/Desktop/Test1/picture1.jpg'))
# 绘制图像
imshow(img)
# 一些点
x = [500, 500, 1000, 1000]
y = [200, 900, 200, 900]
# 使用红色星状标记绘制点
plot(x, y, 'r*')
# 绘制连接前两个点的线
plot(x[:2], y[:2])
# 添加标题,显示绘制的图像
title('Plotting: "picture1.jpg"')
show()
# 坐标轴不显示
axis('off')
2.2.2绘制图像的格式
绘图时,有很多选项可以控制图像的颜色和样式,见下例:
- plot(x,y) # 默认为蓝色实线
- plot(x,y,’r*’) # 红色星状标记
- plot(x,y,’go-‘) # 带有圆圈标记的绿线
- plot(x,y,’ks:’) # 带有正方形标记的黑色虚线
用PyLab库绘图的基本颜色格式命令:
- b’ 蓝色
- ‘g’ 绿色
- ‘r’ 红色
- ‘c’ 青色
- ‘m’ 品红
- ‘y’ 黄色
- ‘k’ 黑色
- ‘w’ 白色
用PyLab库绘图的基本线型格式命令:
- ‘-‘ 实线
- ‘–‘ 虚线
- ‘:’ 虚线
用PyLab库绘图的基本绘制标记格式命令:
- ‘。’观点
- ‘o’ 圆圈
- ‘s’ 正方形
- ‘*’ 星星
- ‘+’ 加号
- ‘x’ 叉号
2.3 OpenCV视觉库
在计算机视觉项目的开发中,OpenCV作为较大众的开源库,拥有了丰富的常用图像处理函数库,采用C/C++语言编写,可以运行在Linux/Windows/Mac等操作系统上,能够快速的实现一些图像处理和识别的任务。
此外,OpenCV还提供了Java、python、cuda等的使用接口、机器学习的基础算法调用,从而使得图像处理和图像分析变得更加易于上手,让开发人员更多的精力花在算法的设计上。OpenCV是用于快速处理图像处理、计算机视觉问题的工具,支持多种语言进行开发如c++、python、java等。我使用OpenCV-Python,使用python语言对图像进行处理和研究。
2.3.1 基本操作
注意,使用PyCharm开发,要先引入cv2库,若引入不成功就引入opencv-python。
1)读入图像
cv2.imread(filepath,flags)
参数说明:
- filepath:要读入图片的完整路径;
- flags:读入图片的标志 ;
- cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道 也可以以1指定
- cv2.IMREAD_GRAYSCALE:读入灰度图片 也可以以0指定
- cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道
2)显示图像
cv2.imshow(wname, img)
参数说明:
- 第一个参数是显示图像的窗口的名称;
- 第二个参数是要显示的图像(imread读入的图像),窗口大小自动调整为图片大小;
ps:显示图片时注意,让程序暂停cv2.waitKey(0),否则图片一闪而过,我们来不及观察图片 。
3)保存图像
cv2.imwrite(file,img,num)
参数说明:
- 第一个参数是要保存的文件名;
- 第二个参数是要保存的图片;
- 可选的第三个参数是写入图像的质量。
使用示例:
import cv2
# 读入图像
# 1的话读取全彩图片 0读取灰度图片即黑白图片
img1 = cv2.imread('C:/Users/Administrator/Desktop/Test1/picture1.jpg', 1)
img2 = cv2.imread('C:/Users/Administrator/Desktop/Test1/picture1.jpg', 0)
# 显示图像
cv2.namedWindow('img1', cv2.WINDOW_NORMAL)
cv2.namedWindow('img2', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img1', 600, 450)
cv2.resizeWindow('img2', 600, 450)
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.waitKey(0)
# 保存图像
# IMWRITE_JPEG_QUALITY的取值范围为0-100,下面写入jpg格式,数值越小,压缩比越高,图片失真严重
cv2.imwrite('C:/Users/Administrator/Desktop/Test1/picture1_copy.jpg', img1, [cv2.IMWRITE_JPEG_QUALITY, 0])
输出结果:
3.2 OpenCV读取和PIL读取的差异
输出差
cv2.imread()读取的是图像的真实数据。lmage.open()函数只是保持了图像被读取的状态,但是图像的真实数据并未被读取态。
渠道差异
Image.open()读取的通道顺序是RGB,cv2.imread()读取的通道顺序为BGR。
import cv2
from PIL import Image
from matplotlib import pyplot as plt
# 读入图像
# OpenCV读取
img1 = cv2.imread('C:/Users/Administrator/Desktop/Test1/picture1.jpg')
# PIL读取
img2 = Image.open('C:/Users/Administrator/Desktop/Test1/picture1.jpg')
# 显示图像
plt.figure(dpi=120)
plt.subplot(121) # 1代表行,2代表列,所以一共有2个图,1代表此时绘制第一个图。
plt.axis('off') # 取消坐标轴
plt.title("OpenCV") # 标题
plt.imshow(img1) # 显示图片
plt.subplot(122) # 1代表行,2代表列,所以一共有2个图,2代表此时绘制第二个图。
plt.axis('off') # 取消坐标轴
plt.title("PIL") # 标题
plt.imshow(img2) # 显示图片
plt.show() # 显示窗口
我们可以看到,两种方式输出的效果是不一样,用OpenCV读取的图片显示的颜色比较奇怪,用PIL读取图片就和实际原图是一致的,造成两个输出效果不一致的原因就是通道差异,PIL中Image.open()读取的通道顺序是RGB,OpenCV中cv2.imread()读取的通道顺序为BGR。
3.图像直方图和直方图均衡化
3.1 图像直方图
3.1.1 图像直方图的定义
⼀幅数字图像在范围[0, G]内总共有L个灰度级,其直⽅图定义为离散函数:
式中:为级亮度,为灰度级、图像中像素的个数
在实际处理中,图像直方图的x轴区间一般是[0, 255],对应的是8位位图的256个灰度级;y轴对应的是具有相应灰度级的像素点的个数。虽然8位的图像都具有256个灰度级(每一个像素可以有256个灰度值),但是属于不同灰度级的像素数量是很不一样的。有时为了便于表示,也会采用归一化直方图。在归一化直方图中,x轴仍然表示灰度级;y轴不再表示灰度级出现的次数,而是灰度级出现的频率。
3.1.2 图像直方图的性质
- 直方图反映了图像中的灰度分布规律。它描述了每个灰度级中的像素数量,但不包含有关这些像素在图像中的位置的信息。
- 任何特定的图像都有一个与之对应的唯一直方图,但不同的图像可以有相同的直方图。
- 如果一幅图像由两个不相交的区域组成,并且每个区域的直方图已知,则整幅图像的直方图就是这两个区域的直方图之和。
对于每张图像,可以制作其灰度直方图。根据直方图的形状,可以大致推断出图像的质量。由于图像中包含大量像素,因此像素灰度值的分布应符合概率和统计分布规律。假设一个像素的灰度值是随机分布的,那么它的直方图应该是一个正态分布。
图像的灰度值是一个离散变量,因此直方图表示一个离散的概率分布。若以各灰度级的像素数与总像素数的比值作为纵坐标轴,制作图像的直方图,将直方图中各条的最高点连接起来形成一条外轮廓线,纵坐标的比值是某个灰度的概率密度,等高线可以近似地看成图像对应的连续函数的概率分布曲线。
3.1.3 绘制直方图
Python的模块matplotlib.pyplot中的hist()函数能够方便地绘制直方图,我们通常采用该函数直接绘制直方图。除此以外,OpenCV中的cv2.calcHist()函数能够计算统计直方图,还可以在此基础上绘制图像的直方图。
1)使用Numpy绘制直方图
模块matplotlib.pyplot提供了一个类似于MATLAB绘图方式的框架,可以使用其中的matplotlib.pyplot.hist()函数。
matplotlib.pyplot.hist(X,BINS)
参数说明:
- X: 数据源,必须是一维的。图像通常是二维的,需要使用ravel()函数将图像处理为一维数据源以后,再作为参数使用。
- BINS: BINS的具体值,表示灰度级的分组情况。
使用示例:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('C:/Users/Administrator/Desktop/Test1/picture1.jpg')
plt.hist(img.ravel(), 256)
plt.show()
输出结果:
2)使用OpenCV绘制直方图
OpenCV提供了函数cv2.calcHist()用来计算图像的统计直方图,该函数能统计各个灰度级的像素点个数。利用matplotlib.pyplot模块中的plot()函数,可以将函数cv2.calcHist()的统计结果绘制成直方图。
hist = cv2.calcHist( images, channels, mask, histSize,ranges, accumulate)
参数说明:
- hist:返回的统计直方图,是一个一维数组,数组内的元素是各个灰度级的像素个数。
- images:原始图像,该图像需要使用“[ ]”括起来。
- channels:指定通道编号。通道编号需要用“[ ]”括起来,如果输入图像是单通道灰度图像,该参数的值就是[0]。对于彩色图像,它的值可以是[0]、[1]、[2],分别对应通道B、G、R。
- mask:掩模图像。当统计整幅图像的直方图时,将这个值设为None。当统计图像某一部分的直方图时,需要用到掩模图像。
- histSize:BINS的值,该值需要用“[ ]”括起来。例如,BINS的值是256,需要使用“[256]”作为此参数值。
- ranges:即像素值范围。例如,8位灰度图像的像素值范围是[0,255]。
- accumulate:累计(累积、叠加)标识,默认值为False。如果被设置为True,则直方图在开始计算时不会被清零,计算的是多个直方图的累积结果,用于对一组图像计算直方图。该参数允许从多个对象中计算单个直方图,或者实时更新直方图。该参数是可选的,一般情况下不需要设置。
使用示例:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('C:/Users/Administrator/Desktop/Test1/picture1.jpg')
hist = cv2.calcHist([img], [0], None, [256], [0, 255])
# hist是一个shape为(256,1)的数组,表示0-255每个像素值对应的像素个数,下标即为相应的像素值
# plot一般需要输入x,y,若只输入一个参数,那么默认x为range(n),n为y的长度
plt.plot(hist)
plt.show()
输出结果:
3.2 直方图均衡化
3.2.1 直方图均衡化的定义
将原始图像的灰度直方图从比较集中的某个灰度区间变换为在整个灰度范围内均匀分布的技术。直方图均衡可以增强图像对比度。
3.2.2 基本思想
直方图均衡化方法的基本思想是在图像中像素数较多的情况下扩大灰度,在像素数较少的情况下降低灰度。从而达到清晰图像的目的。
计算步骤:
- 确定图像的灰度
- 计算原始直方图分布概率p(i)
- 计算直方图概率累计值s(i)
- 根据公式求像素映射关系
- 灰度映射
3.2.3 编程实现
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 获取直方图——计算像素值出现概率
def GetHist(img):
assert isinstance(img, np.ndarray)
prob = np.zeros(shape=(256))
for rv in img:
for cv in rv:
prob[cv] += 1
row, col = img.shape
prob = prob / (row * col)
return prob
# 直方图均衡化
def EqualHist(img, prob):
# 累计概率
prob = np.cumsum(prob)
# 像素值映射
img_map = [int(i * prob[i]) for i in range(256)]
# 像素值替换
assert isinstance(img, np.ndarray)
row, col = img.shape
for i in range(row):
for j in range(col):
img[i, j] = img_map[img[i, j]]
return img
# 画直方图
def Draw_plot(y, name):
plt.figure(num=name)
plt.bar([i for i in range(256)], y, width=1)
if __name__ == '__main__':
# 读取灰度图
img = cv2.imread("C:/Users/Administrator/Desktop/Test1/picture1.jpg", 0)
# 获取原图取直方图
prob = GetHist(img)
# 画原图直方图
Draw_plot(prob, "原图直方图")
# 直方图均衡化
img = EqualHist(img, prob)
cv2.imwrite("source_hist.jpg", img) # 保存图像
# 获取均衡化后直方图
prob = GetHist(img)
# 画均衡化后的直方图
Draw_plot(prob, "直方图均衡化结果")
plt.show()
运行结果:
四、高斯滤波
4.1 什么是高斯滤波?
高斯滤波是一种线性平滑滤波器,适用于去除高斯噪声,广泛应用于图像处理的降噪过程中。通俗的讲,高斯滤波就是对整个图像进行加权平均的过程。每个像素的值是通过对自身和其邻域内的其他像素值进行加权平均得到的。高斯滤波的具体操作是:用一个模板(或卷积、掩码)对图像中的每个像素进行扫描,用模板确定的邻域内像素的加权平均灰度值代替模板的中心像素的价值 。
4.2 基本原理
在数值图像处理中,高斯滤波可以通过两种主要方式实现。一种是离散窗口滑动窗口卷积,另一种是通过傅里叶变换。最常见的是滑动窗口实现。只有当离散化窗口很大,滑动窗口的计算量很大时,才可以考虑基于傅里叶变换的实现方法。因此,本文将主要介绍滑动窗口实现的卷积。
高斯核主要用在对窗口行卷积进行离散化时,高斯核的大小是奇数,因为高斯卷积会在其覆盖区域的中心输出结果。常用的高斯模板有以下几种形式:
高斯模板通过高斯函数计算得到,公式如下:
4.3 使用示例
opencv函数 cv2.GaussianBlur实现高斯滤波:
cv2.GaussianBlur(src, ksize, sigmaX, sigmaY, borderType)
参数详情:
- 第一个参数:InputArray类型的src,输入图像,Mat类的对象。该函数对通道是独立处理的,且可以处理任意通道数的图像,但是待处理的图像深度应该是CV_8U,CV_16U,CV_16S,CV_32F,CV_64F。
- 第二个参数:OutputArray类型的dst,目标图像,需要和输入图像有相同的尺寸和类型。
- 第三个参数:Size类型的lsize,内核的大小。一般用Size(w,h)的写法表示,w和h可以不同,但是必须是正数和奇数,例如Size(3,3),Size(5,5)。
- 第四个参数:double类型的sigmaX,表示高斯核函数在X方向上的标准偏差。
- 第五个参数:double类型的sigmaY,表示高斯核函数在Y方向上的标准偏差。如果sigmaY是0,就将它设为sigmaX。如果sigmaX和sigmaY都是0,那么就由ksize.width和ksize.height计算出来。为了结果的正确性,最好是将Size、sigmaX、sigmaY全部指定到。
- 第六个参数:int类型的borderType,用于推断图像外部像素的某种边界模式,默认值 BORDER_DEFAULT,我们一般不管它。
使用示例:
import cv2
img = cv2.imread('C:/Users/Administrator/Desktop/Test1/picture1.jpg')
img1 = cv2.GaussianBlur(img, (3, 3), 10)
img2 = cv2.GaussianBlur(img, (3, 3), 100)
img3 = cv2.GaussianBlur(img, (3, 3), 1000)
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.namedWindow('img1', cv2.WINDOW_NORMAL)
cv2.namedWindow('img2', cv2.WINDOW_NORMAL)
cv2.namedWindow('img3', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 600, 450)
cv2.resizeWindow('img1', 600, 450)
cv2.resizeWindow('img2', 600, 450)
cv2.resizeWindow('img3', 600, 450)
cv2.imshow('img', img)
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('img3', img3)
cv2.waitKey(0)
输出结果:
下面四张图中,img为原图,其他都是经过高斯滤波后的图像,可以看出草地变得更加平滑了!
文章出处登录后可见!