[机器视觉]OpenCV+Python

实验环境

Anaconda3 + OpenCV3 + Spyder

图像处理基础

图像读入、显示与保存

1.读入图像

retval = cv2.imread(文件名[,显示控制参数])
参数:
-文件名:完整文件名
-显示控制参数:cv.IMREAD_UNCHANGED、cv.IMREAD_GRAYSCALE、cv.IMREAD_COLOR
范例:

1
img=cv2.imread("d:\\image.jpg")

2.显示图像

None=cv2.imshow(窗口名,图像名)
范例:

1
cv2.imshow("demo",image)

retval=cv2.waitKey([,delay])
delay:
-delay>0 等待delay毫秒
-delay<0 等待键盘单击
-delay=0 无限等待

范例:

1
cv2.waitKey(0)

cv2.destroyAllWindows()
功能:删除所有窗口

3.保存图像

retval=cv2.imwrite(文件地址,文件名)
范例:

1
cv2.imwrite("D:\\test.jpg",img)

图像处理入门基础

  1. 图像是由像素构成的
  2. 图像分类:二值图像、灰度图像、RGB图像
    OpenCV中通道顺序是BGR
    常见操作:RGB转灰度、灰度转二值

像素处理

读取像素

返回值=图像(位置参数)
-灰度图像,返回灰度值。
范例:

1
2
p=img[88,142]
print(p)

-BGR图像,返回值为B,G,R的值。
范例:

1
2
3
4
5
blue=img[78,125,0], green=img[78,125,1], red=img[78,125,2]
print(blue), print(green), print(red)

p=img[78,125]
print(p)

修改像素值

像素=新值

-灰度图像
范例:

1
img[88,99]=255

-BGR图像
范例:

1
2
3
img[88,99,0]=255, img[88,99,1]=255, img[88,99,2]=255

img[88,99]=[255,255,255]

使用numpy进行像素处理

读取像素

返回值=图像.item(位置参数)

-灰度图像,返回灰度值。
范例:

1
2
p=img.item(88,142)
print(p)

-BGR图像,返回值为B,G,R的值。
范例:

1
blue=img.item(78,125,0), green=img.item(78,125,1), red=img.item(78,125,2)

修改像素值

图像名.itemset(位置,新值)

-灰度图像
范例:

1
img.itemset((88,99), 255)

-BGR图像
范例:

1
2
3
img.itemset((88,99,0), 255)
img.itemset((88,99,1), 255)
img.itemset((88,99,2), 255)

获取图像属性

1.形状:行、列、通道数

shape可以获取图像的形状,返回包含行数,列数,通道数的元组。
-灰度 返回行数,列数
-彩色 返回行数,列数,通道数

范例:

1
img.shape

2.像素数目

size可以获取图像的像素数目。
-灰度 返回:行数*列数
-彩色 返回:行数*列数*通道数

范例:

1
img.size

3.图像的数据类型

dtype返回的是图像的数据类型。

范例:

1
img.dtype

感兴趣区域ROI

ROI(region of interest),感兴趣区域。
从被处理的图像以方框、圆、椭圆、不规则多边形等方式勾勒出需要处理的区域。
可以通过各种算子(Operator)和函数来求得感兴趣区域ROI,并进行图像的下一步处理。

范例:

1
2
face=img[200:400,200:400]
img[200:400,600:800]=face

通道的拆分与合并

1.拆分通道

范例:

1
2
3
4
5
6
7
8
9
10
11
import cv2
img = cv2.imread('图像名')
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]

b,g,r = cv2.split(img)

b = cv2.split(img)[0]
g = cv2.split(img)[1]
r = cv2.split(img)[2]

2.合并通道

范例:

1
2
3
4
5
rows, cols, chn = a.shape
b = cv2.split(img)[0]
g = np.zeros((rows,cols), dtype=a.dtype)
r = np.zeros((rows,cols), dtype=a.dtype)
m = cv2.merge([b,g,r])

图像运算

图像加法

1.Numpy加法

取模加法
运算方式:结果=图像1+图像2

2.OpenCV加法

饱和运算
运算方式:结果=cv2.add(图像1, 图像2)

范例:

1
2
result1 = a + b
result2 = cv2.add(a,b)

注意的问题:
参与运算的图像大小、类型必须一致。

图像融合

将2张或2张以上的图像信息的融合到1张图像上
融合的图像含有更多的信息、能够更方便人来观察或者计算机处理

图像加法:结果图像=图像1+图像2
img=img1+img2

图像融合:结果图像=图像1*系数1+图像2*系数2+亮度调节量
img=img1*0.3+img2*0.7+18

函数addWeighted
dst = cv2.addWeighted(src1, aplha, scr2, beta, gamma)
dst = scr1*alpha + src2*beta + gamma
-参数gamma不能省略

范例:

1
result = cv2.addWeighted(a,1,b,1,0)

图像类型转换

将图像由一种类型转换为另外一种类型

OpenCV提供了200多种不同类型之间的转换。
cv2.COLOR_BGR2GRAY 彩色转灰度
cv2.COLOR_BGR2RGB BGR转RGB
cv2.COLOR_GRAY2BGR 灰度转BGR

范例:

1
2
3
b = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

bb,bg,br = cv2.split(img)

几何变换

图像缩放

resize函数

语法格式
dst = cv2.resize(src,dsize[,dst[,fx[,fy[,interpolation]]]])

dst = cv2.resize(src,dsize,fx,fy)
-scr 原始图像
-dsize 缩放大小
-fx,fy 缩放大小
①dsize, ②fx,fy 设置一个即可

范例:

1
2
3
4
rows,clos = a.shape[:2]
b = cv2.resize(a,(round(cols*5),round(rows*1.2))) #列,行

b = cv2.resize(a,None,fx=1.2,fy=0.5)

图像翻转

flip函数
语法:
dst = cv2.flip(src, flipCode)
-flipCode=0 以X轴为对称轴翻转
-flipCode>0 以Y轴为对称轴翻转
-flipCode<0 在X轴、Y轴方向同时翻转

范例:

1
dst = cv2.flip(src, 1)

阈值分割

基础知识

原始图像像素值分布

二进制阈值化

先要选定一个特定的阈值量,比如:127
新的阈值产生规则为:

  • 大于等于127的像素点的灰度值设定为最大值(如8位灰度值最大为255)
  • 灰度值小于127的像素点的灰度值设定为0

反二进制阈值化

该阈值化与二进制阈值化相似,先选定一个特定的灰度值作为阈值。以8位灰度图为例:

  • 大于阈值的设定为0
  • 小于该阈值的设定为255

截断阈值化

首先需要选定一个阈值,图像中大于该阈值的像素点被设定为该阈值,小于该阈值的保持不变。例如:阈值选取为127

  • 小于127的阈值不改变
  • 大于等于127的像素点设定为该阈值127

反阈值化为0

先选定一个阈值,然后对图像做如下处理:

  • 大于等于阈值的像素点,值变为0
  • 小于该阈值的像素点,值保持不变

阈值化为0

先选定一个阈值,然后对图像做如下处理:

  • 大于等于阈值的像素点,值保持不变
  • 小于该阈值的像素点,值变为0

threshold函数

函数threshold
retval, dst = cv2.threshold(src, thresh, maxval, type)
-retval,阈值
-dst,处理结果
-src,源图像
-threshold,阈值
-maxval,最大值
-type,类型

二进制阈值化:cv2.THRESH_BINARY
反二进制阈值化:cv2.THRESH_BINARY_INV
截断阈值化:cv2.THRESH_TRUNC
反阈值化为0:cv2.THRESH_TOZERO_INV
阈值化为0:cv2.THRESH_TOZERO

范例:

1
r,b = cv2.threshold(a,127,255,cv2.THRESH_BINARY)

图像平滑处理

均值滤波

任意一点的像素值,都是周围N*N个像素值的均值
针对原始图像内的像素点,逐个采用核进行处理,得到结果图像。

函数blur
处理结果 = cv2.blur(原始图像, 核大小)

范例:

1
r = cv2.blur(o,(5,5))

方框滤波

函数boxFilter
处理结果 = cv2.boxFilter(原始图像, 目标图像深度, 核大小, normalize属性)
目标图像深度:int类型的目标图像深度。通常使用“-1”表示与原始图像一致。
核大小:(5,5)、(3,3)
normalize属性:是否对目标图像进行归一化处理。

范例:

1
2
3
r = cv2.boxFilter(o,-1,(5,5),normalize=1) #归一化处理,与均值滤波相同

r = cv2.boxFilter(o,-1,(2,2)) #省略normalize参数,进行归一化处理

高斯滤波

让临近的像素具有更高的重要度。对周围像素计算加权平均值,较近的像素具有较大的权重值。

GaussianBlur函数
dst = cv2.GaussianBlur(src, ksize, sigmaX)
src:原始图像,要处理的源图像
ksize:核大小(N,N)必须是奇数

sigmaX:X方向方差,控制权重
sigmaX=0时:sigma = 0.3((ksize-1)0.5 - 1) + 0.8

范例:

1
r = cv2.GaussianBlur(o,(3,3),0)

中值滤波

让临近的像素按照大小排列,取排序像素集中位于中间位置的值作为中值滤波后的像素值。

medianBlur函数
dst = cv2.medianBlur(src, ksize)
src:源图像
ksize:核大小,必须是比1大的奇数,如3,5,7等

范例:

1
r = cv2.medianBlur(o,3)

形态学操作

基础
1.形态学转换主要针对的是二值图像。
2.两个输入对象。
对象1:二值图像
对象2:卷积核

图像腐蚀

卷积核的中心点逐个像素扫描原始图像。

被扫描到的原始图像中的像素点,只有当卷积核对应的元素值均为1时,其值才为1,否则值为0。

函数erode
dst = cv2.erode(src, kernel, iterations)
-dst,处理结果
-src,源图像
-kernel,卷积核 kernel=np.ones((5,5),np.uint8)

-iterations,迭代次数 默认情况下,迭代次数是1,根据需要可以进行多次腐蚀操作

范例:

1
2
3
4
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(img, kernel)

erosion = cv2.erode(img, kernel, iterations=9)

图像膨胀

膨胀是腐蚀操作的逆操作

被扫描到的原始图像中的像素点,当卷积核对应的元素值只要有一个为1时,其值就为1,否则值为0。

函数dilate
dst=cv2.dilate(src, kernel, iterations)
-dst,处理结果
-src,源图像
-kernel,卷积核 kernel=np.ones((5,5),np.uint8)
-iterations,迭代次数

范例:

1
2
kernel = np.ones((5,5),np.uint8)
dilation = cv2.dilate(img, kernel)

开运算

开运算(image)=膨胀(腐蚀(image))

  • 图像被腐蚀后,去除了噪声,但是会压缩图像。
  • 对腐蚀过的图像,进行膨胀处理,可以去除噪声,并保持原有形状。

函数morphologyEx
result = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
-result,结果
-img,源图像
-cv2.MORPH_OPEN,开运算
-cv2.MORPH_CLOSE,闭运算
-cv2.MORPH_GRADIENT,梯度
-cv2.MORPH_TOPHAT,礼帽
-cv2.MORPH_BLACKHAT,黑帽
-kernel,卷积核 kernel=np.ones((5,5),np.uint8)

范例:

1
2
kernel = np.ones((5,5),np.uint8)
r = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

闭运算

闭运算(image)=腐蚀(膨胀(image))

  • 先膨胀,后腐蚀
  • 它有助于关闭前景物体内部的小孔,或物体上的小黑点

梯度运算

梯度(image)=膨胀(image)-腐蚀(image)

像素值:白色(1)、黑色(0)

  • 梯度图像=膨胀图像-腐蚀图像
  • 得到轮廓图像

礼帽(顶帽)操作

礼帽(image)=image-开运算(image)

  • 礼帽图像=原始图像-开运算图像
  • 得到噪声图像

黑帽操作

黑帽(image)=闭运算(image)-image

  • 黑帽图像=闭运算图像-原始图像
  • 得到图像内部的小孔,或前景色中的小黑点

腐蚀:去除边缘(变细)

可逆性研究:尺度一样、清晰度不一样、不可逆

图像梯度

sobel算子的理论基础

sobel算子及其函数使用

scharr算子函数及其使用

sobel算子和scharr算子的比较

laplacian算子及使用

canny边缘检测

canny边缘检测原理

canny函数及使用

图像金字塔

理论基础

pyrDown函数及使用

pyrUp函数及使用

取样可逆性研究

拉普拉斯金字塔

图像轮廓

图像轮廓(极简版)

1.轮廓是什么?
边缘检测能够测出边缘,但是边缘是不连续的。
将边缘连接为一个整理,构成轮廓。

2.注意问题:
对象是二值图像。所以需要预先进行阈值分割或者边缘检测处理。
查找轮廓需要更改原始图像。因此,通常使用原始图像的一份拷贝操作
在OpenCV中,是从黑色背景中查找白色对象。因此,对象必须是白色的,背景必须是黑色的。

3.使用函数:
cv2.findContours()
cv2.drawContours()

查找图像轮廓的函数是cv2.findContours(),通过cv2.drawContours()将查找到的轮廓绘制到图像上。

image, contours, hierarchy = cv2.findContours(image, mode, method)
-image,修改后的原始图像(即二值化处理后的图像)
-contours,轮廓
-hierarchy,图像的拓扑信息(轮廓层次)
-image,原始图像
-mode,轮廓检索模型

  • cv2.RETR_EXTERNAL:表示只检测外轮廓
  • cv2.RETR_LIST:检测的轮廓不建立等级关系
  • cv2.RETR_CCOMP:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
  • cv2.RETR_TREE:(常用)建立一个等级树结构的轮廓。

-method,轮廓的近似方法

  • cv2.CHAIN_APPROX_NONE:(常用)存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2), abs(y2-y1))==1
  • cv2.CHAIN_APPROX_SIMPLE:(常用)压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
  • cv2.CHAIN_APPROX_TC89_L1:使用teh_Chinl chain近似算法
  • cv2.CHAIN_APPROX_TC89_KCOS:使用teh_Chinl chain近似算法

r = cv2.drawContours(o, contours, contourIdx, color[, thickness])
-r:目标图像,直接修改目标的像素点,实现绘制
-o:原始图像
-contours:需要绘制的边缘数组
-contourIdx:需要绘制的边缘索引,如果全部绘制则为-1
-color:绘制的颜色,为BGR格式的Scalar。
-thickness:可选,绘制的密度,即描绘轮廓时所用的画笔粗细

4.范例

1
2
3
4
5
6
7
8
9
10
11
12
import cv2
o = cv2.imread('image\\contours.png')
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY) #色彩空间的转换(BGR转为灰度)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) #灰度图像调整为二值图像
image, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #查找边界
co = o.copy() #不想改变原始图像
r = cv2.drawContours(co, contours, -1, (0,0,255), 1) #绘制所有边界,红色
# r = cv2.drawContours(co, contours, 0, (0,0,255), 6) #绘制第1个边界,粗细调粗
cv2.imshow("original",o)
cv2.imshow("contours",r)
cv2.waitKey()
cv2.destroyAllWindows()

直方图

直方图的概念

绘制直方图

使用OpenCV统计直方图

绘制OpenCV统计直方图

使用掩膜的直方图

掩膜原理及演示

直方图均衡化原理

直方图均衡化函数equalizeHist

subplot函数的使用

matplotlib.pyplot.imshow函数的使用

直方图均衡化对比

参考

书名 出版日期 简要评价
Python+OpenCV图穷匕见 py3.6 网易云课堂
OpenCV-Python-Toturial-中文版 py3.5 官方文档翻译
OpenCV-Python-Tutorial py3.6 官方文档翻译+博主自己的demo
【视觉与图像】OpenCV篇:Python+OpenCV实用教程 py3.6 优质博客
1
2