opencv学习笔记一


opencv学习笔记一

opencv模块

core:实现了最核心的数据结构及其基本运算,如绘图函数,数组操作相关函数等。

highgui:实现了视频与图像的读取,显示,存储等接口

imgproc:实现了图像处理的基础方法,包括图像滤波,图像的几何变换,平滑,阈值分割,形态学处理,边缘检测,目标检测,运动分析和对象跟踪等等。

features2d:用于提取图像特征以及特征匹配,nonfree模块实现了一些专利算法,如sift特征。
objectect:实现了一些目标检测的功能,经典的基于haar,LBP特征的人脸检测,基于HOG的行人,汽车等目标检测,分类器使用Cascade Classification(级联分类)和Latent SVM等。
stitching:实现了图像拼接功能。
FLANN:包含快速近似最近邻搜索FLANN和聚类Clustering算法
ml:机器学习模块(SVM,决策树,Boosting等等)
photo:包含图像修复和图像去噪两部分
video:针对视频处理,如背景分离,前景检测,对象跟踪等。
calib3d:即Calibration3D,这个模块主要是相机校准和三维重建相关的内容。包含了基本的多视角几何算法,单个立体摄像头标定,物体姿态估计,立体相似性算法,3D信息的重建等等。
G-API:包含超高效的图像处理pipline引擎

图像的基本操作

读取图像

cv.imread(var1,var2)
var1为读取图像的路径
var2:cv.IMREAD*COLOR:以彩色模式加载图像,任何图像的透明度都将被忽略。这是默认参数。var2为1
cv.IMREAD*GRAYSCALE:以灰度模式加载图像。var2为0
cv.IMREAD_UNCHANGED:包括alpha通道的加载图像模式。var2为-1

显示图像

cv.imshow(var1,var2)
var1:显示图像的窗口名称,以字符串类型表示
var2:要加载的图像的代理对象
注意:在调用显示图像的API后,要调用cv.waitKey(var)给图像绘制留下时间,否则窗口会出现无响应情况,并且图像无法显示出来。

plt.imshow(img,camp=plt.cm.) cmap即colormaps,图谱 plt.cm是matplotlib库中内置的色彩映射函数 plt.cm.[色彩](’[数据集]’)即对[数据集]应用[色彩]
plt.show()

及其他色彩表

保存图像

cv.imwrite(var1,var2)
var1:图片保存的路径
var2:保存图像的代理对象

import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread('/Users/dinggongcheng/Downloads/me.JPG', 0)
#cv.imshow('image', img)
#cv.waitKey(0)
#cv.destroyAllWindows()
#cv.waitKey(1)
plt.imshow(img, cmap=plt.cm.gray)
plt.show()

绘制几何图形

绘制直线

cv.line(img,start,end,color,thickness)
img:要绘制直线的图像
start,end:直线的起点和终点
color:线条的颜色
thickness:线条宽度

绘制圆形

cv.circle(img,centerpoint,r,color,thickness)
img:要绘制图形的图像
centerpoint,r:圆心和半径
color:线条的颜色
thickness:线条宽度,为-1时生成闭合图案并填充颜色

绘制矩形

cv.rectangle(img,leftupper,rightdown,color,thickness)
img:要绘制矩形的图像
leftupper,rightdown:矩形的左上角和右下角坐标
color:线条的颜色
thickness:线条宽度

向图像中添加文字

cv.putText(img,text,station,font,fontsize,color,thickness,cv.LINE_AA)
img:图像
text:要写入的文本数据
station:文本的放置位置
font:字体
fontsize:字体大小

# author:dinggc
# date:2021/3/29 上午10:54
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 创建一个空白的图像
img = np.zeros((512, 512, 3), np.uint8)
# 绘制图形
cv.line(img, (0, 0), (511, 511), (255, 0, 0), 5)
cv.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)
cv.circle(img, (447, 63), 63, (0, 0, 255), -1)
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(img, 'OpenCV', (10, 500), font, 4, (255, 255, 255), 2, cv.LINE_AA)
# 图像展示
plt.imshow(img[:, :, ::-1])
plt.title('匹配结果'), plt.xticks([]), plt.yticks([])
plt.show()

获取并修改图像中的像素点

可以通过行和列的坐标值获取该像素点的像素值。对于BGR图像,它返回一个蓝,绿,红值的数组。对于灰度图像,仅返回相应的强度值。使用相同的方法对像素值进行修改。

img = np.zeros((256, 256, 3), np.uint8)

# 获取某个像素点的值
px = img[100, 100]
print(px)
# 仅获取蓝色通道的强度值
blue = img[100, 100, 0]
print(blue)
# 修改某个位置的像素值
img[100, 100] = [255, 255, 255]

plt.imshow(img[:, :, ::-1])
plt.show()

获取图像的属性

图像属性包括行数,列数和通道数,图像数据类型,像素数等。

属性 API
形状 img.shape
图像大小 img.size
数据类型 img.dtype

图像通道的拆分与合并

有时需要在B,G,R通道图像上单独工作。在这种情况下,需要将BGR图像分割为单个通道。或者在其他情况下,可能需要将这些单独的通道合并到BGR图像。

# 通道拆分
b,g,r = cv.split(img)
# 通道合并
img = cv.merge((b,g,r))

色彩空间的改变

cv.cvtColor(input_image, flag)
input_images:进行颜色空间转换的图像
flag:转换类型
cv.COLOR_BGR2GRAY:BGR-GRAY
cv.COLOR_BGR2HSV:BGR-HSV

算数操作

图像的加法

可以使用OpenCV的cv.add()函数把两幅图像相加,或者可以简单的通过numpy操作添加两个图像,如res = img1 + img2.两个图像应该具有相同的大小和类型,或者第二个图像可以是标量值。

注意:OpenCV加法和Numpy加法之间存在差异。OpenCv的加法是饱和操作,而Numpy添加是模运算。

>>> x = np.uint8([250])
>>> y = np.uint8([10])
>>> print(cv.add(x,y)) # 250+10 = 260 => 255
[[255]]
>>> print(x+y)  # 250+10 = 260 % 256 = 4
[4]

这种差别在你对两幅图像进行加法时会更加明显。OpenCV的结果会更好一点。所以尽量使用OpenCV中的函数。

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

# 读取图像
img1 = cv.imread('/Users/dinggongcheng/Downloads/me.JPG')
img2 = cv.imread('/Users/dinggongcheng/Downloads/me.JPG')

# 加法操作
img3 = cv.add(img1, img2)
img4 = img1 + img2

# 图像显示
plt.imshow(img3[:, :, ::-1])
plt.imshow(img4[:, :, ::-1])
plt.show()

cv相加

直接相加

图像的混合

通过加法实现,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉。图像混合的计算公式如下:
g(x) = (1-a)f0(x) + af1(x)
通过修改a的值(0->1),可以实现非常炫酷的混合。
现在把两幅图混合在一起。第一幅图的权重是0.7,第二幅图的权重是0.3。函数cv2.addWeighted()可以按下面的公式对图片进行混合操作。
dst = a*img1 + b*img2 + c

# 读取图像
img1 = cv.imread('/Users/dinggongcheng/Downloads/me.JPG')
img2 = cv.imread('/Users/dinggongcheng/Downloads/me.JPG')

# 图像混合
img3 = cv.addWeighted(img1, 0.8, img2, 0.6, 0)

# 图像显示
plt.figure(figsize=(8, 8))
plt.imshow(img3[:, :, ::-1])
plt.show()

几何变换

图像缩放

缩放是对图像的大小进行调整
cv.resize(src,dsize,fx=0,fy=0,interpolation=cv.INTER_LINEAR)
src:输入图像
dsize:绝对尺寸,直接指定调整后图像的大小
fx,fy:相对尺寸,将dsize设置为None,然后将fx和fy设置为比例因子即可
interpolation:插值方法

插值 含义
cv.INTER_LINEAR 双线性插值法
cv.INTER_NEAREST 最近邻插值
cv.INTER_AREA 像素区域重采样
cv.INTER_CUBIC 双三次插值
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread("/Users/dinggongcheng/Downloads/me.JPG")

# 绝对尺寸缩放
rows, cols = img.shape[:2]
res = cv.resize(img, (2*cols, 2*rows), interpolation=cv.INTER_CUBIC)

# 相对尺寸缩放
res1 = cv.resize(img, None, fx=0.5, fy=0.5)

# 图像显示
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(10, 8), dpi=100)
axes[0].imshow(res[:, :, ::-1])
axes[0].set_title("dsize big")
axes[1].imshow(img[:, :, ::-1])
axes[1].set_title("from")
axes[2].imshow(res1[:, :, ::-1])
axes[2].set_title("fx small")
plt.show()

图像平移

图像平移将图像按照指定方向和距离,移动到相应的位置。
cv.warpAffine(img,M,dsize)
img:输入图像
M:2*3移动矩阵,对于(x,y)处的像素点,要把它移动到(x+tx,y+ty)处时,M矩阵应如下设置:
M = 1 0 tx
0 1 ty
注意:将M设置为np.float32类型的Numpy数组
dsize:输出图像的大小
注意:输出图像的大小,它应该是(宽度,高度)的形式。请记住,width=列数,height=行数。

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread("/Users/dinggongcheng/Downloads/me.JPG")

# 图像平移
rows, cols = img.shape[:2]
M = np.float32([[1, 0, 100], [0, 1, 50]]) #平移矩阵
dst = cv.warpAffine(img, M, (cols, rows))

# 图像显示
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(dst[:, :, ::-1])
axes[0].set_title("move")
axes[1].imshow(img[:, :, ::-1])
axes[1].set_title("from")
plt.show()

图像旋转

图像旋转是指图像按照某个位置转动一定角度的过程,旋转中图像仍保持原始尺寸。图像旋转后图像的水平对称轴,垂直对称轴及中心坐标原点都可能发生变换。因此需要对图像旋转中的坐标进行相应转换。
在OpenCV中图像旋转首先根据旋转角度和旋转中心获取旋转矩阵,然后根据旋转矩阵进行变换,即可实现任意角度和任意中心的旋转效果。
cv.getRotationMatrix2D(center, angle,scale)
center:旋转中心
angle:旋转角度
scale:缩放比例
返回:
M:旋转矩阵
调用cv.warpAffine完成图像的旋转

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread("/Users/dinggongcheng/Downloads/me.JPG")

# 图像旋转
rows, cols = img.shape[:2]
# 生成旋转矩阵
M = cv.getRotationMatrix2D((cols/2, rows/2), 90, 1)
# 进行旋转变换
dst = cv.warpAffine(img, M, (cols, rows))

# 图像显示
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(dst[:, :, ::-1])
axes[0].set_title("rotate")
axes[1].imshow(img[:, :, ::-1])
axes[1].set_title("from")
plt.show()

仿射变换

图像的仿射变换涉及到图像的形状位置角度的变化,是深度学习预处理中常用到的功能,仿射变换主要是对图像的缩放,旋转,翻转和平移等操作的组合。
需要注意的是,对于图像而言,宽度方向是x,高度方向是y,坐标的顺序和图像像素对应下标一致。所以原点的位置不是左下角而是右上角,y的方向也不是向上,而是向下。
在仿射变换中,原图中所有的平行线在结果图像中同样平行。为了创建这个矩阵我们需要从原图像中找到三个点以及他们在输出图像中的位置。然后cv.getAffineTransform会创建一个2*3的矩阵,最后这个矩阵会被传给函数cv.warpAffine

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread("/Users/dinggongcheng/Downloads/me.JPG")

# 仿射变换
rows, cols = img.shape[:2]

# 创建变换矩阵
pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
pts2 = np.float32([[100, 100], [200, 50], [100, 250]])
M = cv.getAffineTransform(pts1, pts2)

# 完成仿射变换

dst = cv.warpAffine(img, M, (cols, rows))

# 图像显示
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(dst[:, :, ::-1])
axes[0].set_title("affine")
axes[1].imshow(img[:, :, ::-1])
axes[1].set_title("from")
plt.show()

透射变换

透射变换是视角变换的结果,是指利用透视中心,像点,目标点三点共线的条件,按透视旋转定律使承影面绕迹线旋转某一角度,破坏原有的投影光线束,仍能保持承影面上投影几何图形不变的变换。
在OpenCV中,我们要找到四个点,其中任意三个不共线,然后获取变换矩阵T,在进行透射变换。通过函数cv.getPerspectiveTransform找到其变换矩阵,将cv.warpPerspective应用于此3*3变换矩阵。

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread("/Users/dinggongcheng/Downloads/me.JPG")

# 透射变换
rows, cols = img.shape[:2]

# 创建变换矩阵
pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389,390]])
pts2 = np.float32([[100, 145], [300, 100], [80, 290], [310, 300]])
T = cv.getPerspectiveTransform(pts1,pts2)

# 进行变换
dst = cv.warpPerspective(img, T, (cols, rows))

# 图像显示
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(dst[:, :, ::-1])
axes[0].set_title("perspective")
axes[1].imshow(img[:, :, ::-1])
axes[1].set_title("from")
plt.show()

图像金字塔

图像金字塔是图像多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。
图像金字塔用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。
金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似,层级越高,图像越小,分辨率越低。
cv.pyrUp(img) 对图像进行上采样
cv.pyrDown(img) 对图像进行下采样

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread("/Users/dinggongcheng/Downloads/me.JPG")

# 进行图像采样
up_img = cv.pyrUp(img)
down_img = cv.pyrDown(img)

# 图像显示
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(up_img[:, :, ::-1])
axes[0].set_title("Up")
axes[1].imshow(down_img[:, :, ::-1])
axes[1].set_title("Down")
plt.show()

形态学操作

连通性

连通性是描述区域和边界的重要概念,两个像素联通的两个必要条件是:
1.两个像素的位置是否相邻
2.两个像素的灰度值是否满足特定的相似性准则

腐蚀和膨胀

腐蚀和膨胀是最基本的形态学操作,腐蚀和膨胀都是针对白色部分(高亮部分)而言的。
膨胀就是使图像中高亮部分扩张,效果图拥有比原图更大的高亮区域;腐蚀是原图中的高亮区域被蚕食,效果图拥有比原图更小的高亮区域。膨胀是求局部最大值的操作,腐蚀是求局部最小值的操作。

腐蚀的具体操作是用一个结构元素扫描图像中的每一个元素,用结构元素中的每一个像素与其覆盖的像素做与操作,如果都为1,则该像素为1,否则为0.
腐蚀的作用是消除物体边界点,使目标缩小,可以消除小于结构元素的噪声点。
cv.erode(img,kernel,iterations)
img:要处理的图像
kernel:核结构
iterations:腐蚀的次数,默认是1

膨胀的具体操作是用一个结构元素扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做与操作,如果都为0,则该像素为0,否则为1.
膨胀的作用是将与物体接触的所有背景点合并到物体中,使目标增大,可添补目标中的孔洞。
cv.dilate(img,kernel,iterations)img:要处理的图像
kernel:核结构
iterations:腐蚀的次数,默认是1

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 读取图像
img = cv.imread("/Users/dinggongcheng/Downloads/me.JPG")
# 创建核结构
kernel = np.ones((5, 5), np.uint8)

# 图像腐蚀和膨胀
erosion = cv.erode(img, kernel)
dilate = cv.dilate(img, kernel)

# 图像显示
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(10, 8), dpi=100)
axes[0].imshow(img[:, :, ::-1])
axes[0].set_title("from")
axes[1].imshow(erosion[:, :, ::-1])
axes[1].set_title("erosion")
axes[1].imshow(dilate[:, :, ::-1])
axes[1].set_title("dilate")
plt.show()

开闭运算

开运算和闭运算是将腐蚀和膨胀按照一定的次序进行处理。但这两者并不是可逆的,即先开后闭并不难得到原来的图像。
开运算是先腐蚀后膨胀,其作用是分离物体,消除小区域。消除噪点,去除小的干扰块,而不影响原来的图像。
闭运算与开运算相反,是先膨胀后腐蚀,作用是消除/闭合物体里面的孔洞。可以填充闭合区域。

cv.morphologyEx(img,op,kernel)
img:要处理的图像
op:处理方式:若进行开运算,则设为cv.MORPH_OPEN,若进行闭运算,则设为cv.MORPH_CLOSE
kernel:核结构

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 读取图像
img = cv.imread("/Users/dinggongcheng/Downloads/me.JPG")
# 创建核结构
kernel = np.ones((10, 10), np.uint8)

# 图像的开闭运算
cvOpen = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
cvClose = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)

# 图像显示
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(10, 8), dpi=100)
axes[0].imshow(img[:, :, ::-1])
axes[0].set_title("from")
axes[1].imshow(cvOpen[:, :, ::-1])
axes[1].set_title("cvOpen")
axes[1].imshow(cvClose[:, :, ::-1])
axes[1].set_title("cvClose")
plt.show()
礼帽和黑帽

礼帽运算
原图像与开运算的结果图之差,如下式计算:
dst = tophat(src,element) = src - open(src,element)
因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。
礼帽运算用来分离比邻近点亮一些的斑块。当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用礼帽运算进行背景提取。

黑帽运算
为闭运算的结果图与原图像之差,数学表达式为
dst = blackout(src,element) = close(src,element) - src
黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关。黑帽运算用来分离比邻近点暗一些的斑块。

cv.morphologyEx(img,op,kernel)
img:要处理的图像
op:处理方式:若进行开运算,则设为cv.MORPH_OPEN,若进行闭运算,则设为cv.MORPH_CLOSE。若进行礼帽运算,则设为cv.MORPH_TOPHAT,若进行黑帽运算,则设为cv.MORPH_BLACKHAT。
kernel:核结构

图像平滑

图像噪声

椒盐噪声
椒盐噪声也称为脉冲噪声,是图像中经常见到的一种噪声,它是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或是在暗的区域有白色像素。

高斯噪声
噪声密度函数服从高斯分布的一类噪声。

图像平滑
均值滤波

cv.blur(src,ksize,anchor,borderType)
src:输入图像
ksize:卷积核的大小
anchor:默认值(-1,-1),表示核中心
borderType:边界类型

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 图像读取
img = cv.imread("/Users/dinggongcheng/Downloads/me.png")

# 均值滤波
blur = cv.blur(img, (5, 5))

# 图像显示

plt.figure(figsize=(10, 8), dpi=100)
plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title('from')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur[:, :, ::-1]), plt.title('blur')
plt.xticks([]), plt.yticks([])
plt.show()

高斯滤波

cv.GaussianBlur(src,ksize,sigmaX,sigmaY,borderType)
src:输入图像
ksize:高斯卷积核大小,注意:卷积核的宽度和高度都应为奇数,且可以不同
sigmaX:水平方向的标准差
sigmaY:垂直方向的标准差,默认值为0,表示与sigmaX相同
borderType:填充边界类型

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 图像读取
img = cv.imread("/Users/dinggongcheng/Downloads/me.png")

# 高斯滤波
gauss = cv.GaussianBlur(img, (3, 3), 1)

# 图像显示

plt.figure(figsize=(10, 8), dpi=100)
plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title('from')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(gauss[:, :, ::-1]), plt.title('gauss')
plt.xticks([]), plt.yticks([])
plt.show()

中值滤波

中值滤波是一种典型的非线性滤波技术,基本思想适用像素点领域灰度值的中值来代替该像素点的灰度值。中值滤波对椒盐噪声来说尤其有用,因为它不依赖于领域内那些与典型值差别很大的值。
cv.medianBlur(src,ksize)
src:输入图像
ksize:卷积核的大小

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 图像读取
img = cv.imread("/Users/dinggongcheng/Downloads/me.png")

# 中值滤波
media = cv.medianBlur(img, 5)

# 图像显示

plt.figure(figsize=(10, 8), dpi=100)
plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title('from')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(media[:, :, ::-1]), plt.title('media')
plt.xticks([]), plt.yticks([])
plt.show()


文章作者: dinggc
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 dinggc !
评论
 上一篇
Spring boot相关知识点 Spring boot相关知识点
Springboot中如何解决跨域问题? 在脚本进行http请求的时候要满足同源协议,即url的协议,域名和端口要相同才能才能发起请求。浏览器在脚本发出跨域请求后,会拦截返回的结果,所以需要配置跨域。 当用户退出或者token过期时,拦截器
2021-03-30
下一篇 
python学习笔记(一) python学习笔记(一)
python学习笔记(一) python函数 print输出函数 id(var) 获取对象的唯一id type(var) 获取对象的类型 var 存储的值 open函数 var3 = open(var1 var2) var1参数值代表输出文
2021-03-27
  目录