文章目录
- 一、OpenCV简介
- 1.1 OpenCV是什么
- 1.2 安装及使用
- 二、图像的基础
- 2.1 成像原理
- 2.2 图像格式
- 2.3 颜色空间
- 三、OpenCV基础操作
- 3.1 图像的读取、显示、保存
- 3.2 通道转换
- 三、OpenCV常见图像处理
- 3.1 在图像上绘制几何图像及添加文字
- 3.2 图像的几何变换
- 3.3 图像滤波
- 3.4 图像增强
- 3.5 形态学变换
一、OpenCV简介
1.1 OpenCV是什么
OpenCV是一种开源的计算机视觉库,提供了广泛的图像处理和计算机视觉算法的实现。它最初是由英特尔开发的,现在已经成为计算机视觉领域最流行和广泛使用的开源库之一。OpenCV支持多种编程语言,包括C++、Python和Java等。它的主要特点是它提供了许多预先实现的算法,包括特征检测、图像处理、目标跟踪、人脸识别、运动估计、3D重建和深度学习等领域。
1.2 安装及使用
- python 3.x
- Jupyter
pip install jupyter
- opencv-python
pip install opencv-python #或opencv-contrib-python
# opencv-python包含基本的opencv
# opencv-contrib-python是高配版,带一些收费或者专利的算法,还有一些比较新的算法的高级版本,这些算法稳定之后会加入opencv-python。
已经安装opencv,查看opencv库的安装路径
- 方法一:用
__file__
属性
import cv2
cv2.__file__
# 'XXX\\Python\\Python310\\lib\\site-packages\\cv2\\__init__.py'
- 方法二:用
pip show opencv-python
C:\Users\Administrator> pip show opencv-python
# 输出示例:
# Name: opencv-python
# Version: 4.7.0.72
# Summary: Wrapper package for OpenCV python bindings.
# Home-page: https://github.com/opencv/opencv-python
# Author:
# Author-email:
# License: Apache 2.0
# Location: xxx\python310\lib\site-packages // 此处即为所求安装路径
# Requires: numpy, numpy, numpy, numpy
# Required-by:
源码github地址:this
使用OpenCV进行图像处理的接口源地址:here
二、图像的基础
2.1 成像原理
以电磁波谱辐射为基础的图像我们最为熟悉,某个物体发出电磁波被其他物体所接受从而形成图像,常见的由X射线和可见光波段的图像。
- 伽马射线【Gamma rays】:是从原子核内部发出来的,穿透力很强,对生物的破坏力很大。
- X射线【X-rays】
- 应用:CT影像
- 原理:利用不同密度对X射线的吸收率不一样,从而得到不同的衰减以成像。
- 紫外线波段成像【Ultraviolet】有显著的化学效应和荧光效应
- 可见光波段成像【Visible】
- 人类能看到的所有物体都是可见光波段成像,原理是:光线照射到物体上,反射到人眼中从而形成图像。
- 红外线波段成像【Infrared】
- 自然界中,一切物体都可以辐射红外线。
- 利用探测仪测量目标本身与背景间的红外线差可以得到不同的红外图像。
- 微波波段成像【Microwaves】
- 应用:雷达
- 无线电波段成像【Radio waves】
- 应用1:电视、手机、无线电广播等
- 应用2:磁共振成像(MRI)
2.2 图像格式
- BMP:位图图像
- JPEG:互联网上常用,压缩较大
- GIF:可以是动图
- PNG:支持Alpha通道调整图像的透明度
- TIFF:信息丰富,有利于原稿的复制
2.3 颜色空间
颜色空间又称为彩色模型,在某些标准下对彩色加以说明,常见的颜色空间有:
- RGB,主要用于计算机图形学中,根据人眼识别的颜色进行创建
- HSV[色调、饱和度、明度],根据颜色的直观特性创建
- HSI【色调、饱和度、强度】,反应人感知颜色的基本属性,与人感知颜色的结果一一对应
- CMYK【青色、品红、黄色、黑色】,应用于印刷业
三、OpenCV基础操作
3.1 图像的读取、显示、保存
- 读取图像
import cv2
img = cv2.imread("图像路径", "读取方式")
# cv2.IMREAD_COLOR: 默认值,加载一张彩色图像,忽视透明度,数字表示1
# cv2.IMREAD_GRAYSCALE: 加载一张灰度图,数字表示0
# cv2.IMREAD_UNCHANGED: 加载图像,包括它的Alpha通道,数字表示-1
print(img.shape) # img按照BGR的格式进行存储
- 显示图像
cv2.imshow("窗口名", img)
# cv2.waitKey()是一个键盘绑定函数,单位是毫秒,0代表等待键盘输入
k = cv2.waitKey(0)
if k == 27: # 输入ESC键退出
cv2.destroyAllWindows()
- 保存图像
cv2.imwrite("保存路径+名称", img)
3.2 通道转换
图像分辨率,每英寸图像内的像素点数,分辨率越高,像素点密度越高,图像越清晰。
图像的位深度[8位、24位、32位],是指描述图像每个像素点数值所占的二进制位数。如8bit只能表示灰度图像,每个点的值的范围为0-255【 2 8 2^8 28】,24bit可以表示RGB三通道的图像,32bit可以表示RGB+Alpha四通道的图像。也就是说,位深度越大则图像能表示的颜色数就越多,色彩越丰富逼真。
- 通道转换
# 3==>1: GRAY = R * 0.114 + G * 0.587 + R * 0.299
# 1==>3: R = G = B = GRAY, A = 0
cv2.cvtColor(img, flag)
# img为待转换的图像,flag为转换模式
# cv2.COLOR_BGR2GRAY,彩色转灰度
# cv2.COLOR_GRAY2BGR,灰度转彩色
# cv2.COLOR_BGR2RGB, BGR格式转为RGB格式,opencv读入的图像是BGR格式的
# 注意:matplotlib.pyplot中使用的是RGB格式,需要进行转换后再使用
import matplotlib.pyplot as plt
img = cv2.imread("test.png", cv2.IMREAD_COLOR)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.subplot(1, 2, 1)
plt.imshow(img) # 会发现此图像有色差
plt.subplot(1, 2, 2)
plt.imshow(img_rgb) # 正常
- 通道分离
将彩色图像,分成b, g, r
三个单通道图像。
import cv2
img = cv2.imread("orig.png")
b, g, r = cv2.split(img)
- 通道合并
可是使用split
对图像进行通道分离后,对单独通道进行修改,然后再合并为彩色图像。
import cv2
import numpy as np
img = cv2.imread("orig.png")
b, g, r = cv2.split(img)
b[:] = 0
img_merge = cv2.merge([b, g, r])
zeros = np.zeros(image.shape, dtype="uint8")
cv2.imshow("GREEN", cv2.merge([zeros, g, zeros]))
- 图像直方图
图像直方图(Image Histogram)用来表示数字图像中亮度分布的直方图,描述的是每个亮度值的像素数,能够反映图像亮度的分布情况。直方图常被用于图像的二值化。
import cv2
img = cv2.imread("test.png")
# cv2.calcHist([img], channels, mask, histSize, ranges)
hist = cv2.calcHist([img, [0], None, [256], [0, 255]])
# channels: 待计算的通道
# histSize:表示直方图分成多少份
三、OpenCV常见图像处理
3.1 在图像上绘制几何图像及添加文字
import cv2
img = cv2.imread("test.png")
# 绘制线段
cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 5, cv2.LINE_AA)
# 待绘制的图像,起点,终点,线段颜色,线宽, linetype线条的类型
# 矩形绘制
# cv2.rectangle(待绘制图像, 左上角坐标, 右下角坐标,颜色,线宽,线型)
cv2.rectangle(img, (384, 0), (510, 128), (0, 255, 255), -1)
# 线宽为-1表示区域填充
# 圆绘制
# cv2.circle(待绘制图像, 圆心,半径,颜色,线宽,线型)
cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)
# 椭圆绘制
# cv2.ellipse(待绘制图像,中心点坐标,(长轴长度、短轴长度), 旋转角, 起始角度,终止角,颜色、线宽、线型)
cv2.ellipse(img, (256, 256), (100, 50), 0, 0, 360, (255, 0, 0), -1)
# 起始角和终止角控制了,是画一整个椭圆,还是椭圆的一部分
# 多边形绘制
# cv2.polylines(img, 点对,线段是否闭合,颜色,线宽、线型)
pts = np.array([[10, 5], [50, 10], [70, 20], [20, 30]])
pts = pts.reshape((-1, 1, 2)) # 将点对转换为1行两列
cv2.polylines(img, [pts], True, (0, 255, 255))
# 添加文字
# cv2.putText(img, 要添加的文本, 文字的起始坐标[左下角的起点], 字体,文字缩放比例,颜色,线宽,线型)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, "OpenCV", (50, 200), font, 3, (0, 255, 255), 5, cv2.LINE_AA)
3.2 图像的几何变换
关于图像几何变换的接口的官方说明,点这里。
图像的几何变换包括平移、缩放、旋转、镜像、仿射变换、透视变换等。
# 仿射变换函数
cv2.warpAffine(img, M, dsize, flags, borderMode, borderValue)
# 输入图像,变换矩阵,输出图像尺寸,插值方法,边界像素模式,边界填充值
# 插值方法有四种:
# cv2.INTER_NEAREST(最近邻插值,默认,速度最快)、
# cv2.LINEAR(线性插值)
# cv2.INTER_AREA(区域插值)
# cv2.INTER_CUBIC(三次样条插值)
# cv2.INTER_LANCZOS4(Lancozos插值)
平移:将图像上所有的点按照指定的平移量水平或垂直移动。
x 1 = x 0 + t x x_1 = x_0 + t_x x1=x0+tx
y 1 = y 0 + t y y_1 = y_0 + t_y y1=y0+ty
import cv2
import numpy as np
img = cv2.imread("test.png")
# 构造移动变换矩阵
# 在x方向移动50,y方向移动25
H = np.float32([[1, 0, 50], [0, 1, 25]])
rows, cols = img.shape[:2]
res = cv2.warpAffine(img, H, (cols, rows))
# 注意,这里的dsize是先列后行
缩放:缩小图像称为下采样【down-Sampling】,放大图像称为上采样【up-Sampling】
import cv2
img = cv2.imread("test.png")
# cv2.resize(src, dsize=None, fx, fy, interpolation)
# 待缩放图像,输出图像尺寸[与比例因子二选一],fx沿水平轴的比例因子,fy沿y轴的比例因子,插值方法
cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
旋转:以某点为中心,旋转一定的角度,也就是说将图像上所有像素点旋转一个相同的角度。
---- 用旋转来扩充数据集,因为图像具有旋转不变性,旋转前后类别一致。
假设原来的坐标为:
x 0 = r c o s ( α ) , y 0 = r s i n ( α ) x_0 = r cos(\alpha), y_0 = r sin(\alpha) x0=rcos(α),y0=rsin(α)
旋转后的坐标为:
x = r c o s ( α + θ ) = r c o s α c o s θ − r s i n α s i n θ = x 0 c o s θ − y 0 s i n θ x = rcos(\alpha + \theta) = rcos{\alpha}cos{\theta} - rsin{\alpha}sin{\theta} = x_0cos{\theta} - y_0 sin{\theta} x=rcos(α+θ)=rcosαcosθ−rsinαsinθ=x0cosθ−y0sinθ
y = r s i n ( α + θ ) = r s i n α c o s θ − r c o s α s i n θ = y 0 c o s θ + x 0 s i n θ y = rsin(\alpha + \theta) = rsin{\alpha}cos{\theta} - rcos{\alpha}sin{\theta} = y_0cos{\theta} + x_0 sin{\theta} y=rsin(α+θ)=rsinαcosθ−rcosαsinθ=y0cosθ+x0sinθ
注意:
- 图像旋转之前,为了避免信息丢失,一定要有坐标平移
- 旋转后会有空洞,对这些空洞要进行填充
import cv2
# 旋转矩阵:图像的旋转中心,旋转角度,缩放比例[0.5 正表示逆时针旋转并将结果缩放为原来的0.5]
# M = cv2.getRotationMatrix2D(center, angle, scale)
img = cv2.imread("test.png")
rows, cols = img.shape[:2]
M = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 2)
dst = cv2.warpAffine(img, M, (cols, rows), borderVal=(0, 255, 255))
仿射变换:通过仿射变换对图像进行平移、旋转、缩放、剪切、反射等操作,以达到数据增强的效果。
# 求仿射变换矩阵, pos1表示变换前的位置,pos2表示变换后的位置
# M = cv2.getAffineTransform(pos1, pos2)
import cv2
import numpy as np
img = cv2.imread("test.png")
pos1 = np.float32([[50, 50], [200, 50], [50, 200]])
pos2 = np.float32([[10, 100], [200, 50], [100, 250]])
M = cv2.getAffineTransform(pos1, pos2)
res = cv2.warpAffine(img, M, (cols, rows))
透视变换:本质是将图像投影到一个新的视平面上。
# pos1表示透视变换前的4个点对应的位置
# pos2表示透视变换后的4个点对应的位置
# M = cv2.getPerspectiveTransform(pos1, pos2)
import cv2
import numpy as np
img = cv2.imread("test.png")
pos1 = np.float32([[114, 82], [287, 156], [8, 100], [143, 177]])
pos2 = np.float32([[0, 0], [188, 0], [0, 262], [188, 262]])
M = cv2.getAffineTransform(pos1, pos2)
res = cv2.warpAffine(img, M, (cols, rows))
3.3 图像滤波
关于平滑图像的接口的官方说明。
滤波,就是过滤掉某些信号。在图像处理领域,图像可以看作是一个二维信号,其中像素点的灰度值表示信号的强弱;像素值变化剧烈的地方称为高频区域,像素值变化缓慢、平坦的地方称为低频区域。
根据过滤内容,可以将滤波器分为高通滤波器和低通滤波器,高通滤波器过滤低频信号,通过高频信号,从而可以检测尖锐、变化明显的地方,常用于图像的边缘检测;低通滤波器过滤高频信号,放行低频信号,可以让图像变得平滑,主要用于图像的平滑去噪。
按照滤波器的实现方式,可以将滤波器分为线性滤波器和非线性滤波器。常见的线性滤波器有方框滤波、均值滤波、高斯滤波等;非线性滤波器有中值滤波、双边滤波等。
- 线性滤波:
使用领域内像素点值的加权和计算当前像素点的结果
O ( x , y ) = ∑ f ( x + i , y + j ) ∗ k ( i , j ) O(x, y) = \sum{f(x + i, y + j) * k(i, j)} O(x,y)=∑f(x+i,y+j)∗k(i,j)
方框滤波:KaTeX parse error: Undefined control sequence: \matrix at position 26: …{\alpha}\left[ \̲m̲a̲t̲r̲i̲x̲{ 1&1\cdots&1\\…,