算法工程师10——opencv

1 基本概念

计算机视觉(Computer vision)是一门研究如何使机器“看”的科学,更进一步的说,就是指用摄影机和计算机代替人眼对目标进行识别、跟踪和测量等,用计算机处理成为更适合人眼观察或传送给仪器检测的图像。

计算机视觉,图像处理,图像分析,机器人视觉和机器视觉是彼此紧密关联的学科。

图像处理旨在处理原始图像以应用某种变换。其目标通常是改进图像或将其作为某项特定任务的输入,
机器视觉主要是指工业领域的视觉研究,例如自主机器人的视觉,用于检测和测量的视觉。

1.1专业做视觉的公司

旷视科技、商汤科技、云从科技与依图科技

在这里插入图片描述

1.2 历史

1921年美国科学家发明了Bartlane System,并从伦敦传到纽约传输了第一幅数字图像,其亮度用离散数值表示,将图片编码成5个灰度级,

1963年,Larry Roberts发表了(可能是)CV领域的第一篇专业论文,用以对简单几何体进行边缘提取和三维重建。1966年,麻省理工学院(MIT)发起了一个夏季项目,目标是搭建一个机器视觉系统,完成模式识别(pattern recognition)等工作。

1.3 两大数据集

(1)Everingham等人在2006年至2012年间搭建了一个大型图片数据库,供机器识别和训练,称为PASCAL Visual Object Challenge,该数据库中有20种类别的图片,每种图片数量在一千至一万张不等。
(2)后来Li Fei-fei等人搭建了图像数据库ImageNet,总计两万两千种类别,和一千四百余万张图片。通过训练ImageNet所给出的数据集,识别错误率正逐年下降,并在2015年就已经低于了正常人类的错误率。图中值得注意的是,在2012年,识别错误率突然下降了近10个百分点,这得益于卷积神经网络(CNN,Convolutional Neural Network)的运用,或者更为大家所知晓的概念就是——深度学习(Deep Learning)。CNN在识别错误率上远低于同年的其他模型,这标志着以深度学习为核心的CV时代正式开启。

1.4 四大主要任务

图像分类
目标检测
目标分割
目标追踪

1.5 图像分类

模拟图像和数字图像
在这里插入图片描述

rgb图像就是三维数组

在这里插入图片描述

1.6 OpenCV

OpenCV是一款由Intel公司俄罗斯团队发起并参与和维护的一个计算机视觉处理开源软件库,支持与计算机视觉和机器学习相关的众多算法,并且正在日益扩展。
OpenCV的优势:

编程语言

OpenCV基于C++实现,同时提供python, Ruby, Matlab等语言的接口。OpenCV-Python是OpenCV的Python API,结合了OpenCV C++ API和Python语言的最佳特性。

跨平台

可以在不同的系统平台上使用,包括Windows,Linux,OS X,Android和iOS。基于CUDA和OpenCL的高速GPU操作接口也在积极开发中

活跃的开发团队

丰富的API

完善的传统计算机视觉算法,涵盖主流的机器学习算法,同时添加了对深度学习的支持

1.6.1 OpenCV-Python

OpenCV-Python是一个Python绑定库,旨在解决计算机视觉问题。

Python是一种由Guido van Rossum开发的通用编程语言,它很快就变得非常流行,主要是因为它的简单性和代码可读性。它使程序员能够用更少的代码行表达思想,而不会降低可读性。

与C / C++等语言相比,Python速度较慢。也就是说,Python可以使用C / C++轻松扩展,这使我们可以在C / C++中编写计算密集型代码,并创建可用作Python模块的Python包装器。这给我们带来了两个好处:首先,代码与原始C / C++代码一样快(因为它是在后台工作的实际C++代码),其次,在Python中编写代码比使用C / C++更容易。OpenCV-Python是原始OpenCV C++实现的Python包装器。

OpenCV-Python使用Numpy,这是一个高度优化的数据库操作库,具有MATLAB风格的语法。所有OpenCV数组结构都转换为Numpy数组。这也使得与使用Numpy的其他库(如SciPy和Matplotlib)集成更容易。

windows和linux 系统下安装,他们的安装代码都一样。
pip install opencv-python==4.5.3.56 -
i https://pypi.tuna.tsinghua.edu.cn/simple

2 图像的基本操作

2.1 读取、加减

在这里插入图片描述
在这里插入图片描述
你可以使用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 中的函数。

这其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉。图像混合的计算公式如下:

g(x) = (1−α)f0(x) + αf1(x)

通过修改 α 的值(0 → 1),可以实现非常炫酷的混合。

2.2 几何变换(有好多操作都是两步走,先创建变换矩阵,再完成变换)

2.2.1 图像缩放

缩放是对图像的大小进行调整,即使图像放大或缩小。

API

cv2.resize(src,dsize,fx=0,fy=0,interpolation=cv2.INTER_LINEAR)
参数:

src : 输入图像

dsize: 绝对尺寸,直接指定调整后图像的大小

fx,fy: 相对尺寸,将dsize设置为None,然后将fx和fy设置为比例因子即可

interpolation:插值方法,

2.2.2 图像平移

图像平移将图像按照指定方向和距离,移动到相应的位置。

API
cv.warpAffine(img,M,dsize)
参数:

在这里插入图片描述

2.2.3图像旋转

图像旋转是指图像按照某个位置转动一定角度的过程,旋转中图像仍保持这原始尺寸。图像旋转后图像的水平对称轴、垂直对称轴及中心坐标原点都可能会发生变换,因此需要对图像旋转中的坐标进行相应转换。

两步
在OpenCV中图像旋转首先根据旋转角度和旋转中心获取旋转矩阵,然后根据旋转矩阵进行变换,即可实现任意角度和任意中心的旋转效果。

2.2.4 仿射变换

图像的仿射变换涉及到图像的形状位置角度的变化,是深度学习预处理中常到的功能,仿射变换主要是对图像的缩放,旋转,翻转和平移等操作的组合。

那什么是图像的仿射变换,如下图所示,图1中的点1, 2 和 3 与图二中三个点一一映射, 仍然形成三角形, 但形状已经大大改变,通过这样两组三点(感兴趣点)求出仿射变换, 接下来我们就能把仿射变换应用到图像中所有的点中,就完成了图像的仿射变换。

在这里插入图片描述

2.2.5透射变换

透射变换是视角变化的结果,是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,仍能保持承影面上投影几何图形不变的变换。

在这里插入图片描述

2.2.6图像金字塔

图像金字塔是图像多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。

图像金字塔用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。

金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似,层级越高,图像越小,分辨率越低。

在这里插入图片描述

2.3 形态学操作

形态学转换是基于图像形状的一些简单操作。它通常在二进制图像上执行。腐蚀和膨胀是两个基本的形态学运算符。然后它的变体形式如开运算,闭运算,礼帽黑帽等

2.3.1 邻接和连通性

在这里插入图片描述

2.3.2 腐蚀和膨胀

在这里插入图片描述

在这里插入图片描述

2.3.3 开闭运算

在这里插入图片描述

在这里插入图片描述

2.3.4 礼帽和黑帽

在这里插入图片描述

在这里插入图片描述

2.4 图像平滑

图像平滑从信号处理的角度看就是去除其中的高频信息,保留低频信息。因此我们可以对图像实施低通滤波。低通滤波可以去除图像中的噪声,对图像进行平滑。

根据滤波器的不同可分为均值滤波,高斯滤波,中值滤波, 双边滤波。

2.4.1 噪声

在这里插入图片描述

2.4.2 均值、中值、高斯滤波

三种类型的滤波器就是用一个卷积核,根据周围像素点的值进行中心点的值的替换,均值和中值分别用周围像素的平均值和中值替换中心像素点的值,高斯滤波是给周围像素值安高斯分布加一个权重,这样中心点像素值等于周围像素值的加权和。
https://blog.csdn.net/iFlyAI/article/details/109183559?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

2.5 直方图(就是每个像素值区间像元个数的直方图)

2.5.1图像灰度直方图

直方图是对数据进行统计的一种方法,并且将统计值组织到一系列实现定义好的 bin 当中。其中, bin 为直方图中经常用到的一个概念,可以译为 “直条” 或 “组距”,其数值是从数据中计算出的特征统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征。

图像直方图(Image Histogram)是用以表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素个数。这种直方图中,横坐标的左侧为较暗的区域,而右侧为较亮的区域。因此一张较暗图片的直方图中的数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像则相反。

注意:直方图是根据灰度图进行绘制的,而不是彩色图像。   假设有一张图像的信息(灰度值 0 - 255,已知数字的范围包含 256 个值,于是可以按一定规律将这个范围分割成子区域(也就是 bins)。如:
\left[0,255\right] = \left[0,15\right]\bigcup\left[16,30\right]\cdots\bigcup\left[240,255\right][0,255]=[0,15]⋃[16,30]⋯⋃[240,255]
  然后再统计每一个 bin(i) 的像素数目。可以得到下图(其中 x 轴表示 bin,y 轴表示各个 bin 中的像素个数):
在这里插入图片描述
直方图的意义:

直方图是图像中像素强度分布的图形表达方式。   
它统计了每一个强度值所具有的像素个数。
不同的图像的直方图可能是相同的
在这里插入图片描述

2.5.2 掩膜

在这里插入图片描述

2.5.3 直方图均衡化

在这里插入图片描述

2.5.4 自适应直方图均衡化

在这里插入图片描述

在这里插入图片描述

两步
先创建一个自适应均衡化的对象,
再应用于图像

2.6 边缘检测

2.6.1原理

边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。边缘的表现形式如下图所示:

在这里插入图片描述
图像边缘检测大幅度地减少了数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性。有许多方法用于边缘检测,它们的绝大部分可以划分为两类:基于搜索和基于零穿越。
在这里插入图片描述

2.6.2 Sobel检测算子

Sobel边缘检测算法比较简单,实际应用中效率比canny边缘检测效率要高,但是边缘不如Canny检测的准确,但是很多实际应用的场合,sobel边缘却是首选,Sobel算子是高斯平滑与微分操作的结合体,所以其抗噪声能力很强,用途较多。尤其是效率要求较高,而对细纹理不太关心的时候。
在这里插入图片描述

2.6.3 Laplacian算子

在这里插入图片描述

2.6.4 Canny边缘检测

Canny 边缘检测算法是一种非常流行的边缘检测算法,是 John F. Canny 于 1986年提出的,被认为是最优的边缘检测算法。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3 图像的进阶操作

3.1 模板匹配

所谓的模板匹配,就是在给定的图片中查找和模板最相似的区域,该算法的输入包括模板和图片,整个任务的思路就是按照滑窗的思路不断的移动模板图片,计算其与图像中对应区域的匹配度,最终将匹配度最高的区域选择为最终的结果

在这里插入图片描述

3.2 霍夫曼线几何等检测

霍夫线检测

原理:将要检测的内容转换到霍夫空间中,利用累加器统计最优解,将检测结果表示处理

API:cv2.HoughLines()

注意:该方法输入是的二值化图像,在进行检测前要将图像进行二值化处理

霍夫圆检测

方法:霍夫梯度法

API:cv.HoughCircles()

3.3 傅里叶变换

这个比较难理解
任何连续周期的信号都可以由一组适当的正弦曲线组合而成。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.4 轮廓检测

主要用来进行图像边缘的一系列操作

图像的轮廓
轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度。轮廓是图像目标的外部特征,这种特征对于我们进行图像分析,目标识别和理解等更深层次的处理都有很重要的意义。
轮廓提取的基本原理:对于一幅背景为黑色、目标为白色的二值图像,如果在图中找到一个白色点,且它的8邻域(或4邻域)也均为白色,则说明该点是目标的内部点,将其置为黑色,视觉上就像内部被掏空一样;否则保持白色不变,该点是目标的轮廓点。一般在寻找轮廓之前,都要将图像进行阈值化或Canny边缘检测,转换为二值化图像。
在这里我们看下边缘提取和轮廓检测的区别:

边缘检测主要是通过一些手段检测数字图像中明暗变化剧烈(即梯度变化比较大)像素点,偏向于图像中像素点的变化。如canny边缘检测,结果通常保存在和源图片一样尺寸和类型的边缘图中。

轮廓检测指检测图像中的对象边界,更偏向于关注上层语义对象。如OpenCV中的findContours()函数, 它会得到每一个轮廓并以点向量方式存储,除此也得到一个图像的拓扑信息,即一个轮廓的后一个轮廓、前一个轮廓等的索引编号。

在这里插入图片描述
图像的矩特征没搞清楚

3.5 图像分割

在这里插入图片描述
分水岭和GrabCut算法好好想想

4 图像特征提取

整体比较难

4.1 角点检测

在这里插入图片描述
如上图所示,蓝色框中的区域是一个平面很难被找到和跟踪。无论向哪个方向移动蓝色框,都是一样的。对于黑色框中的区域,它是一个边缘。如果沿垂直方向移动,它会改变。但是如果沿水平方向移动就不会改变。而红色框中的角点,无论你向那个方向移动,得到的结果都不同,这说明它是唯一的。 所以,我们说角点是一个好的图像特征,也就回答了前面的问题。

角点是图像很重要的特征,对图像图形的理解和分析有很重要的作用。角点在三维场景重建运动估计,目标跟踪、目标识别、图像配准与匹配等计算机视觉领域起着非常重要的作用。在现实世界中,角点对应于物体的拐角,道路的十字路口、丁字路口等

那我们怎样找到这些角点呢?接下来我们使用 OpenCV 中的各种算法来查找图像的特征,并对它们进行描述。

4.2 Harris和Shi-Tomasi角点检测算法

在这里插入图片描述

这两种算法具有旋转不变性,但不具有尺度不变性,

4.3 SIFT/SURF算法

在这里插入图片描述

4.4 Fast和ORB算法

在这里插入图片描述

4.5 LBP和hog算法

hog很好理解
在这里插入图片描述

5 视频操作

在这里插入图片描述

5.1 目标追踪

在这里插入图片描述

代码

1 图像的基本操作


# opencv打开的默认通道是BGR,不是RGB,这只是显示和读取时这样,
# 比如(255,0,0),本来是红色,但是用opencv读取就是蓝色
#  记住无论读取显示怎么变化,里面保存到数组不变,所以opencv和plt显示同一个三维数组出来的颜色不一样
# 但是同样用opencv和plt读取一张照片的时候,读出来是一样的,因为他们会看图像头文件,确定相应的通道

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


# 1 读取
# 读取的时候有图像的头文件,cv会直接根据头文件确定哪个是蓝绿红通道
img = cv.imread("./mao.jpg")
##输出(300, 533, 3)
## 这里的意思是有300行,就是高是300,宽是533,维度是3
print(img.shape)
print(img.dtype)
print(img.size)

print("直接打印img:\n",img)
print("直接打印img.data:\n",img.data)


print("转换后")
img1 = img[0,:,:]
## 输出(533, 3),就是有300个533*3的二维数组,最后一个就是rgb,正好反过来了,而不是3个300*533的二维数组
print(img1.shape)
print(img1)


# 2 显示
cv.imshow("image", img)

# 这里就是对最后一个维度进行左右翻转
plt.imshow(img[:,:,::-1])
plt.title('匹配结果'), plt.xticks([]), plt.yticks([])
plt.show()
plt.imshow(img, cmap=plt.cm.gray)
plt.show()

# key = cv.waitKey(0)

# 3 保存
# cv.imwrite('maomao.jpg',img)

# 4 绘制图形并添加文字
img2 = np.zeros((512,512,3),np.uint8)
#  绘制图形
cv.line(img2, (0,0), (511,511), (255,0,0),5)
cv.rectangle(img2, (384,0), (510,128), (0,255,0), 3)
cv.circle(img2, (447,63),63, (0,0,255), -1)    # -1代表充满
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(img2, "OpenCV", (10,500), font, 4, (255,255,255), 2, cv.LINE_AA)
# 图像展示
plt.imshow(img2)
plt.title('1匹配结果,不转换通道,线条本来在opencv想显示为蓝色的:但是这里显示成红色'), plt.xticks([]), plt.yticks([])
plt.show()
#  转换通道
plt.imshow(img2[:,:,::-1])
plt.title('2匹配结果,不转换通道,线条颜色变成自己想要的蓝色:'), plt.xticks([]), plt.yticks([])
plt.show()

# 5 像素点操作
print("像素点操作:")
px = img2[100,100]
px1 = img2[100,100,0]
print(px,px1)
# 修改像素点的值
# 这里显示一条白色的竖线,说明第一个通道就是指的高,也就是行
img2[10:100,100] = [255,255,255]
cv.imshow("image", img2)

plt.imshow(img2)
plt.show()

# 6 通道的拆分和合并
# 通道拆分
b,g,r = cv.split(img2)
# 通道合并
img3 = cv.merge((b,g,r))

# 7色彩空间变化
plt.imshow(b,cmap=plt.cm.gray)
plt.show()


# 8 图像的加法
img1 = cv.imread("image/view.jpg")
img2 = cv.imread("image/rain.jpg")

#  加法操作
img3 = cv.add(img1,img2) # cv中的加法
img4 = img1+img2 # 直接相加

#  图像显示
fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,8),dpi=100)
axes[0].imshow(img3[:,:,::-1])
axes[0].set_title("cv中的加法")
axes[1].imshow(img4[:,:,::-1])
axes[1].set_title("直接相加")
plt.show()

# 9 图像混合
img5 = cv.addWeighted(img1,0.3,img2,0.7,0)

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


2 图像的几何变换

# 图像的几何变换
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 1. 读取图片
img1 = cv.imread("image/deer.jpeg")
# 2.图像缩放
# 2.1 绝对尺寸
rows,cols = img1.shape[:2]
print(rows,cols)
res = cv.resize(img1,(1000,1000),interpolation=cv.INTER_CUBIC)

# 2.2 相对尺寸
res1 = cv.resize(img1,None,fx=0.5,fy=0.5)

# 3 图像显示
# 3.1 使用opencv显示图像(不推荐)
cv.imshow("orignal",img1)
cv.imshow("enlarge",res)
cv.imshow("shrink)",res1)
# cv.waitKey(0)

# 3.2 使用matplotlib显示图像
fig,axes=plt.subplots(nrows=1,ncols=3,figsize=(10,8),dpi=100)
axes[0].imshow(res[:,:,::-1])
axes[0].set_title("绝对尺度(放大)")
axes[1].imshow(img1[:,:,::-1])
axes[1].set_title("原图")
axes[2].imshow(res1[:,:,::-1])
axes[2].set_title("相对尺度(缩小)")
plt.show()

# 4 图像的平移
M = np.float32([[1,0,100],[0,1,50]])# 平移矩阵
dst = cv.warpAffine(img1,M,(cols,rows))

fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,8),dpi=100)
axes[0].imshow(img1[:,:,::-1])
axes[0].set_title("原图")
axes[1].imshow(dst[:,:,::-1])
axes[1].set_title("平移后结果")
plt.show()

# 5 图像的旋转
#  5.1 生成旋转矩阵
M_xuanzhuan = cv.getRotationMatrix2D((cols/2, rows/2), 90, 1)
#  5.2 进行旋转变换
dst2 = cv.warpAffine(img1, M_xuanzhuan, (rows,cols))

fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10,8), dpi = 100)
axes[0].imshow(img1[:,:,::-1])
axes[0].set_title("原图")
axes[1].imshow(dst2[:,:,::-1])
axes[1].set_title("旋转后结果")
plt.show()

# 6 透射变换
rows,cols = img1.shape[:2]
# 6.1 创建变换矩阵
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)
# 6.2 进行变换
dst = cv.warpPerspective(img1,T,(cols,rows))

#  图像显示
fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,8),dpi=100)
axes[0].imshow(img1[:,:,::-1])
axes[0].set_title("原图")
axes[1].imshow(dst[:,:,::-1])
axes[1].set_title("透射后结果")
plt.show()

# 7 图像金字塔
up_img = cv.pyrUp(img1)  # 上采样操作
img_1 = cv.pyrDown(img1)  # 下采样操作
#  图像显示
cv.imshow('enlarge', up_img)
cv.imshow('original', img1)
cv.imshow('shrink', img_1)
cv.waitKey(0)
cv.destroyAllWindows()

3 图像的形态学变换

# 图像的形态学操作
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 1 读取图像
img = cv.imread("./image/letter.png")

# 2图像腐蚀和膨胀
# 2.1 创建核结构
kernel = np.ones((5, 5), np.uint8)

# 2.2 图像腐蚀和膨胀
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)
axes[0].set_title("原图")
axes[1].imshow(erosion)
axes[1].set_title("腐蚀后结果")
axes[2].imshow(dilate)
axes[2].set_title("膨胀后结果")
plt.show()


# 3 图像的开闭运算

# 3.1 读取图像
img1 = cv.imread("./image/letteropen.png")
img2 = cv.imread("./image/letterclose.png")
# 3.2 创建核结构
kernel = np.ones((10, 10), np.uint8)
# 3。3 图像的开闭运算和礼帽黑帽运算,他们的函数是一样的,就是参数不一样
cvOpen1 = cv.morphologyEx(img1,cv.MORPH_OPEN,kernel) # 开运算
cvClose1 = cv.morphologyEx(img2,cv.MORPH_CLOSE,kernel)# 闭运算
cvOpen2 = cv.morphologyEx(img1,cv.MORPH_TOPHAT,kernel) # 礼帽运算
cvClose2 = cv.morphologyEx(img2,cv.MORPH_BLACKHAT,kernel)# 黑帽运算

# 3.4 图像展示
fig,axes=plt.subplots(nrows=2,ncols=3,figsize=(10,8))
axes[0,0].imshow(img1)
axes[0,0].set_title("原图")
axes[0,1].imshow(cvOpen1)
axes[0,1].set_title("开运算结果")
axes[0,2].imshow(cvOpen2)
axes[0,2].set_title("礼帽结果")

axes[1,0].imshow(img2)
axes[1,0].set_title("原图")
axes[1,1].imshow(cvClose1)
axes[1,1].set_title("闭运算结果")
axes[1,2].imshow(cvClose2)
axes[1,2].set_title("闭运算结果")

plt.show()

4 图像平滑

# 图像平滑

### 1 均值滤波
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 图像读取
img = cv.imread('./image/dogsp.jpeg')
# 2 均值滤波
blur = cv.blur(img,(5,5))
# 3 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur[:,:,::-1]),plt.title('均值滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()


### 2 高斯滤波
# 1 图像读取
img = cv.imread('./image/dogGauss.jpeg')
# 2 高斯滤波
blur = cv.GaussianBlur(img,(3,3),1)
# 3 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur[:,:,::-1]),plt.title('高斯滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()


### 3 中值滤波
# 1 图像读取
img = cv.imread('./image/dogsp.jpeg')
# 2 中值滤波
blur = cv.medianBlur(img,5)
# 3 图像展示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur[:,:,::-1]),plt.title('中值滤波后结果')
plt.xticks([]), plt.yticks([])
plt.show()

5 直方图变换

# 绘制直方图
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 1. 直接以灰度图的方式读入,0代表灰度图
img = cv.imread('./image/cat.jpeg',0)

# 2 统计灰度图
histr = cv.calcHist([img],[0],None,[256],[0,256])
# 3 绘制灰度图
plt.figure(figsize=(10,6),dpi=100)
plt.plot(histr)
plt.grid()
plt.show()



#### 2 用掩膜进行直方图的计算
# 2.2. 创建蒙版
mask = np.zeros(img.shape[:2], np.uint8)
mask[400:650, 200:500] = 255
# 2.3.掩模
masked_img = cv.bitwise_and(img,img,mask = mask)
# 2.4. 统计掩膜后图像的灰度图
mask_histr = cv.calcHist([img],[0],mask,[256],[1,256])
# 2.5. 图像展示
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8))
axes[0,0].imshow(img,cmap=plt.cm.gray)
axes[0,0].set_title("原图")
axes[0,1].imshow(mask,cmap=plt.cm.gray)
axes[0,1].set_title("蒙版数据")
axes[1,0].imshow(masked_img,cmap=plt.cm.gray)
axes[1,0].set_title("掩膜后数据")
axes[1,1].plot(mask_histr)
axes[1,1].grid()
axes[1,1].set_title("灰度直方图")
plt.show()



####  3 直方图均衡化
# 3.2. 均衡化处理
dst = cv.equalizeHist(img)

histr1 = cv.calcHist([dst],[0],None,[256],[0,256])


# 3.3. 结果展示
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8),dpi=100)
axes[0,0].imshow(img,cmap=plt.cm.gray)
axes[0,0].set_title("原图")
axes[0,1].plot(histr)
axes[0,1].grid()


axes[1,0].imshow(dst,cmap=plt.cm.gray)
axes[1,0].set_title("均衡化后结果")
axes[1,1].plot(histr1)
axes[1,1].grid()
plt.show()

####  4 自适应直方图均衡化
# 创建一个自适应均衡化对象
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)

histr2 = cv.calcHist([cl1],[0],None,[256],[0,256])

# 3.3. 结果展示
fig,axes=plt.subplots(nrows=3,ncols=2,figsize=(10,8),dpi=100)
axes[0,0].imshow(img,cmap=plt.cm.gray)
axes[0,0].set_title("原图")
axes[0,1].plot(histr)
axes[0,1].grid()


axes[1,0].imshow(dst,cmap=plt.cm.gray)
axes[1,0].set_title("均衡化后结果")
axes[1,1].plot(histr1)
axes[1,1].grid()

axes[2,0].imshow(cl1,cmap=plt.cm.gray)
axes[2,0].set_title("自适应均衡化后结果")
axes[2,1].plot(histr2)
axes[2,1].grid()
plt.show()

6 边缘检测

# 边缘检测

## 1 bobel算子
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 读取图像
img = cv.imread('./image/horse.jpg',0)
# 2 计算Sobel卷积结果
x = cv.Sobel(img, cv.CV_16S, 1, 0)
y = cv.Sobel(img, cv.CV_16S, 0, 1)

# 3 将数据进行转换
Scale_absX = cv.convertScaleAbs(x)  # convert 转换  scale 缩放
Scale_absY = cv.convertScaleAbs(y)
# 4 结果合成
result = cv.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)

## 2 Laplacian算子

# 2.2 laplacian转换
result1 = cv.Laplacian(img,cv.CV_16S)
Scale_abs = cv.convertScaleAbs(result1)


## 3 Canny边缘检测
# 2 Canny边缘检测
lowThreshold = 0
max_lowThreshold = 100
canny = cv.Canny(img, lowThreshold, max_lowThreshold)
# 3 图像展示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(221),plt.imshow(img,cmap=plt.cm.gray),plt.title('原图')
plt.xticks([]), plt.yticks([])

plt.subplot(222),plt.imshow(result,cmap = plt.cm.gray),plt.title('Sobel')
plt.xticks([]), plt.yticks([])

plt.subplot(223),plt.imshow(Scale_abs,cmap = plt.cm.gray),plt.title('Laplacian')
plt.xticks([]), plt.yticks([])

plt.subplot(224),plt.imshow(canny,cmap = plt.cm.gray),plt.title('Canny')
plt.xticks([]), plt.yticks([])
plt.show()


7 模板匹配和霍夫曼检测

###   1模板匹配
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 图像和模板读取
img = cv.imread('./image/wulin.jpeg')
template = cv.imread('./image/bai.jpeg')
h,w,l = template.shape
# 2 模板匹配
# 2.1 模板匹配
res = cv.matchTemplate(img, template, cv.TM_CCORR)
# 2.2 返回图像中最匹配的位置,确定左上角的坐标,并将匹配位置绘制在图像上
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
# 使用平方差时最小值为最佳匹配位置
# top_left = min_loc

# 相关匹配(CV_TM_CCORR):利用模板与图像间的乘法进行匹配,数值越大表示匹配程度较高,越小表示匹配效果差。
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv.rectangle(img, top_left, bottom_right, (0,255,0), 2)
# 3 图像显示
plt.imshow(img[:,:,::-1])
plt.title('匹配结果'), plt.xticks([]), plt.yticks([])
plt.show()


### 2 霍夫曼变换
img1 = cv.imread("image/rili.jpg")

# 变成二值图
gray = cv.cvtColor(img1, cv.COLOR_BGR2GRAY)

# 边缘检测
edges = cv.Canny(gray, 50, 150)
plt.imshow(edges)
plt.show()
# 霍夫曼直线变换
lines = cv.HoughLines(edges, 0.8, np.pi/180, 150)
# 得到28个包含r和角度theta的点
print(lines.shape)

# 将检测的线绘制在图像上
for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * (a))
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * (a))
    cv.line(img1, (x1, y1), (x2, y2), (0, 255, 0))
# 4. 图像显示
plt.figure(figsize=(10, 8), dpi=100)
plt.imshow(img1[:, :, ::-1])
plt.title('霍夫变换线检测')
plt.xticks([]), plt.yticks([])
plt.show()


### 3 霍夫曼圆检测
planets = cv.imread("./image/star.jpeg")
gay_img = cv.cvtColor(planets, cv.COLOR_BGRA2GRAY)
# 2 进行中值模糊,去噪点
img = cv.medianBlur(gay_img, 7)
# 3 霍夫圆检测
circles = cv.HoughCircles(img, cv.HOUGH_GRADIENT, 1, 200, param1=100, param2=30, minRadius=0, maxRadius=100)
# 4 将检测结果绘制在图像上
for i in circles[0, :]:  # 遍历矩阵每一行的数据
    # 绘制圆形
    cv.circle(planets, (i[0], i[1]), i[2], (0, 255, 0), 3)
    # 绘制圆心
    cv.circle(planets, (i[0], i[1]), 2, (0, 0, 255), -1)
# 5 图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.imshow(planets[:,:,::-1]),plt.title('霍夫变换圆检测')
plt.xticks([]), plt.yticks([])
plt.show()


8 傅里叶变换

####  1 傅里叶变换
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
plt.rcParams["font.sans-serif"]="SimHei"

# 1 读取图像
img = cv.imread('./image/deer.jpeg',0)
# 2 傅里叶变换
# 2.1 正变换
dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
# 2.2 频谱中心化
dft_shift = np.fft.fftshift(dft)
# 2.3 计算频谱和相位谱
mag, angle = cv.cartToPolar(dft_shift[:,:,0], dft_shift[:,:,1], angleInDegrees=True)
mag=20*np.log(mag)
# 3 傅里叶逆变换
# 3.1 反变换
img_back = cv.idft(dft)
# 3.2 计算灰度值
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])

# 4 图像显示
plt.figure(figsize=(10,8))
plt.subplot(221),plt.imshow(img, cmap = 'gray')
plt.title('输入图像'), plt.xticks([]), plt.yticks([])
plt.subplot(222),plt.imshow(mag, cmap = 'gray')
plt.title('频谱'), plt.xticks([]), plt.yticks([])
plt.subplot(223),plt.imshow(angle, cmap = 'gray')
plt.title('相位谱'), plt.xticks([]), plt.yticks([])
plt.subplot(224),plt.imshow(img_back, cmap = 'gray')
plt.title('逆变换结果'), plt.xticks([]), plt.yticks([])
plt.show()



####  2 高频滤波器,低频滤波器

### 2.1 高频滤波器
rows,cols = img.shape
mask = np.ones((rows,cols,2),np.uint8)
mask[int(rows/2)-30:int(rows/2)+30,int(cols/2)-30:int(cols/2)+30,:] = 0

# 3 傅里叶变换
# 3.1 正变换
dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
# 3.2 频谱中心化
dft_shift = np.fft.fftshift(dft)
# 3.3 滤波
dft_shift = dft_shift * mask
# 3.4 频谱去中心化
dft_shift = np.fft.fftshift(dft_shift)

# 3 傅里叶逆变换
# 3.1 反变换
img_back = cv.idft(dft_shift)
# 3.2 计算灰度值
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])



## 2.2 低频滤波器
mask0 = np.zeros((rows,cols,2),np.uint8)
mask0[int(rows/2)-30:int(rows/2)+30,int(cols/2)-30:int(cols/2)+30,:] = 1

# 3 傅里叶变换
# 3.1 正变换
dft0 = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
# 3.2 频谱中心化
dft_shift0 = np.fft.fftshift(dft0)
# 3.3 滤波
dft_shift0 = dft_shift0 * mask0
# 3.4 频谱去中心化
dft_shift0 = np.fft.fftshift(dft_shift0)

# 3 傅里叶逆变换
# 3.1 反变换
img_back0 = cv.idft(dft_shift0)
# 3.2 计算灰度值
img_back0 = cv.magnitude(img_back0[:,:,0],img_back0[:,:,1])


plt.subplot(221),plt.imshow(img, cmap = 'gray')
plt.title('输入图像'), plt.xticks([]), plt.yticks([])

plt.subplot(222),plt.imshow(img_back, cmap = 'gray')
plt.title('高通滤波结果'), plt.xticks([]), plt.yticks([])

plt.subplot(223),plt.imshow(img, cmap = 'gray')
plt.title('输入图像'), plt.xticks([]), plt.yticks([])

plt.subplot(224),plt.imshow(img_back0, cmap = 'gray')
plt.title('低通滤波结果'), plt.xticks([]), plt.yticks([])

plt.show()


#####  3 带通和带阻滤波器

rows,cols = img.shape
mask1 = np.ones((rows,cols,2),np.uint8)
mask1[int(rows/2)-8:int(rows/2)+8,int(cols/2)-8:int(cols/2)+8] = 0
mask2 = np.zeros((rows,cols,2),np.uint8)
mask2[int(rows/2)-80:int(rows/2)+80,int(cols/2)-80:int(cols/2)+80] = 1
mask3 = mask1*mask2

# 3 傅里叶变换
# 3.1 正变换
dft0 = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
# 3.2 频谱中心化
dft_shift0 = np.fft.fftshift(dft0)
# 3.3 滤波
dft_shift0 = dft_shift0 * mask3
# 3.4 频谱去中心化
dft_shift0 = np.fft.fftshift(dft_shift0)

# 3 傅里叶逆变换
# 3.1 反变换
img_back0 = cv.idft(dft_shift0)
# 3.2 计算灰度值
img_back0 = cv.magnitude(img_back0[:,:,0],img_back0[:,:,1])


plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('输入图像'), plt.xticks([]), plt.yticks([])

plt.subplot(132),plt.imshow(mask3[:,:,1], cmap = 'gray')
plt.title('带通'), plt.xticks([]), plt.yticks([])

plt.subplot(133),plt.imshow(img_back0, cmap = 'gray')
plt.title('带通滤波结果'), plt.xticks([]), plt.yticks([])

plt.show()


## 3.2 带阻滤波器减弱

mask = np.ones((rows,cols,2),np.uint8)
mask[int(rows/2)+80:int(rows/2)+150,int(cols/2)-150:int(cols/2)+150] = 0
mask[int(rows/2)-150:int(rows/2)-80,int(cols/2)-150:int(cols/2)+150] = 0
mask[int(rows/2)-150:int(rows/2)+150,int(cols/2)+80:int(cols/2)+150] = 0
mask[int(rows/2)-150:int(rows/2)+150,int(cols/2)-150:int(cols/2)-80] = 0

# 3 傅里叶变换
# 3.1 正变换
dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
# 3.2 频谱中心化
dft_shift = np.fft.fftshift(dft)
# 3.3 滤波
dft_shift = dft_shift * mask
# 3.4 频谱去中心化
dft_shift = np.fft.fftshift(dft_shift)

# 3 傅里叶逆变换
# 3.1 反变换
img_back = cv.idft(dft_shift)
# 3.2 计算灰度值
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])



plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('输入图像'), plt.xticks([]), plt.yticks([])

plt.subplot(132),plt.imshow(mask[:,:,1], cmap = 'gray')
plt.title('带通'), plt.xticks([]), plt.yticks([])

plt.subplot(133),plt.imshow(img_back, cmap = 'gray')
plt.title('带阻滤波结果'), plt.xticks([]), plt.yticks([])

plt.show()


9 边缘检测

# 边缘检测

## 1 bobel算子
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1 读取图像
img = cv.imread('./image/horse.jpg',0)
# 2 计算Sobel卷积结果
x = cv.Sobel(img, cv.CV_16S, 1, 0)
y = cv.Sobel(img, cv.CV_16S, 0, 1)

# 3 将数据进行转换
Scale_absX = cv.convertScaleAbs(x)  # convert 转换  scale 缩放
Scale_absY = cv.convertScaleAbs(y)
# 4 结果合成
result = cv.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)

## 2 Laplacian算子

# 2.2 laplacian转换
result1 = cv.Laplacian(img,cv.CV_16S)
Scale_abs = cv.convertScaleAbs(result1)


## 3 Canny边缘检测
# 2 Canny边缘检测
lowThreshold = 0
max_lowThreshold = 100
canny = cv.Canny(img, lowThreshold, max_lowThreshold)
# 3 图像展示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(221),plt.imshow(img,cmap=plt.cm.gray),plt.title('原图')
plt.xticks([]), plt.yticks([])

plt.subplot(222),plt.imshow(result,cmap = plt.cm.gray),plt.title('Sobel')
plt.xticks([]), plt.yticks([])

plt.subplot(223),plt.imshow(Scale_abs,cmap = plt.cm.gray),plt.title('Laplacian')
plt.xticks([]), plt.yticks([])

plt.subplot(224),plt.imshow(canny,cmap = plt.cm.gray),plt.title('Canny')
plt.xticks([]), plt.yticks([])
plt.show()

10 图像分割

# 图像分割

import cv2 as cv
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"]="SimHei"
import numpy as np


###### 1 全阈值分割
# 1.读取图像
img = cv.imread('./image/gradient.jpg', 0)
# 2. 阈值分割
ret, th1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
ret, th2 = cv.threshold(img, 127, 255, cv.THRESH_BINARY_INV)
ret, th3 = cv.threshold(img, 127, 255, cv.THRESH_TRUNC)
ret, th4 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO)
ret, th5 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO_INV)

# 3. 图像显示
titles = ['原图', '阈值二值化', '阈值反二值化', '截断', '阈值取零', '阈值反取零']
images = [img, th1, th2, th3, th4, th5]
plt.figure(figsize=(10,6))
# 使用Matplotlib显示
for i in range(6):
    plt.subplot(2, 3, i + 1)
    plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])  # 隐藏坐标轴
plt.show()


###### 2 自适应阈值
# 1. 图像读取
img = cv.imread('image/fruit.jpeg', 0)

# 2.固定阈值
ret, th1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
# 3.自适应阈值
# 3.1 邻域内求均值
th2 = cv.adaptiveThreshold(
    img, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 11, 4)
# 3.2 邻域内高斯加权
th3 = cv.adaptiveThreshold(
    img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 17, 6)
# 4 结果绘制
titles = ['原图', '全局阈值(v = 127)', '自适应阈值(求均值)', '自适应阈值(高斯加权)']
images = [img, th1, th2, th3]
plt.figure(figsize=(10,6))
for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()


######  3 大律法
# 1. 图像读取
img = cv.imread('image/littledog.jpeg', 0)

# 2.固定阈值
ret, th1 = cv.threshold(img, 12, 255, cv.THRESH_BINARY)
# 3. OSTU阈值
ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)

# 4. 结果绘制
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(131),plt.imshow(img,'gray'),plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(th1,'gray'),plt.title('全阈值分割')
plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(th2,'gray'),plt.title('OStu分割')
plt.xticks([]), plt.yticks([])
plt.show()


####  4 分水岭发
#1.读入图片
img = cv.imread('image/dili.jpg')
gray_img = cv.cvtColor(img,cv.COLOR_BGR2GRAY)

#2.canny边缘检测
canny = cv.Canny(gray_img,80,150)

#3.轮廓检测并设置标记图像
#寻找图像轮廓 返回修改后的图像 图像的轮廓  以及它们的层次
canny,contours,hierarchy = cv.findContours(canny,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
#32位有符号整数类型,
marks = np.zeros(img.shape[:2],np.int32)
#findContours检测到的轮廓
imageContours = np.zeros(img.shape[:2],np.uint8)

#轮廓颜色
compCount = 0
index = 0
#绘制每一个轮廓
for index in range(len(contours)):
    #对marks进行标记,对不同区域的轮廓使用不同的亮度绘制,相当于设置注水点,有多少个轮廓,就有多少个轮廓
    #图像上不同线条的灰度值是不同的,底部略暗,越往上灰度越高
    marks = cv.drawContours(marks,contours,index,(index,index,index),1,8,hierarchy)
    #绘制轮廓,亮度一样
    imageContours = cv.drawContours(imageContours,contours,index,(255,255,255),1,8,hierarchy)


#4 使用分水岭算法,并给不同的区域随机填色
marks = cv.watershed(img,marks)
afterWatershed = cv.convertScaleAbs(marks)

#生成随机颜色
colorTab = np.zeros((np.max(marks)+1,3))
#生成0~255之间的随机数
for i in range(len(colorTab)):
    aa = np.random.uniform(0,255)
    bb = np.random.uniform(0,255)
    cc = np.random.uniform(0,255)
    colorTab[i] = np.array([aa,bb,cc],np.uint8)

bgrImage = np.zeros(img.shape,np.uint8)

#遍历marks每一个元素值,对每一个区域进行颜色填充
for i in range(marks.shape[0]):
    for j in range(marks.shape[1]):
        #index值一样的像素表示在一个区域
        index = marks[i][j]
        #判断是不是区域与区域之间的分界,如果是边界(-1),则使用白色显示
        if index == -1:
            bgrImage[i][j] = np.array([255,255,255])
        else:
            bgrImage[i][j]  = colorTab[index]
# 5 图像显示
plt.imshow(img)
plt.show()

plt.imshow(bgrImage[:,:,::-1])
plt.title('图像分割结果')
plt.xticks([]), plt.yticks([])
plt.show()


####  5 grabCut分割

#1. 读取图片
img = cv.imread('image/ballon.jpeg')
#2. 掩码图像
mask = np.zeros(img.shape[:2],np.uint8)

#3.矩形窗口(x,y,w,h);
rect = [140,45,330,335]

#4.物体分割
cv.grabCut(img,mask,tuple(rect),None,None,5,cv.GC_INIT_WITH_RECT)

#5.抠取图像
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img_show = img*mask2[:,:,np.newaxis]
# 将矩形框绘制在图像上
cv.rectangle(img,(140,45),(470,380),(0,255,0),3)

#6.图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('矩形框选位置')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_show[:,:,::-1]),plt.title('抠取结果')
plt.xticks([]), plt.yticks([])
plt.show()

11 图像特征提取

## 图像特征提取


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

plt.rcParams["font.sans-serif"] = "SimHei"

####### 1 Harris角点检测
## 1.1 读取图像
img_row = cv.imread("image/chessboard.jpg")
img = img_row.copy()
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
## 1.2 角点检测,图像必须是32位浮点型

gray = np.float32(gray)

## 最后一个参数位0.04-0.05
dst = cv.cornerHarris(gray,2,3,0.04)

## 1.3 设置阈值,将角点绘制出来
img[dst>0.001*dst.max()] = [0,0,255]

# 图像显示
plt.figure(figsize=(10,8), dpi=100)
plt.subplot(121),plt.imshow(img_row[:,:,::-1]),plt.title('原图')
plt.subplot(122),plt.imshow(img[:,:,::-1]),plt.title('角点检测:')
plt.show()

###### 2 Shi-Tomasi算法
img = cv.imread('./image/tv.jpg')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 2 角点检测
corners = cv.goodFeaturesToTrack(gray,1000,0.01,10)
# 3 绘制角点
for i in corners:
    x,y = i.ravel()
    cv.circle(img,(x,y),2,(0,0,255),-1)
# 4 图像展示
plt.figure(figsize=(10,8),dpi=100)
plt.imshow(img[:,:,::-1]),plt.title('shi-tomasi角点检测')
plt.xticks([]), plt.yticks([])
plt.show()


####### 3 sift检测图像关键点
# 1 读取图像
img = cv.imread('./image/tv.jpg')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 2 sift关键点检测
# 2.1 实例化sift对象
sift = cv.xfeatures2d.SIFT_create()

# 2.2 关键点检测:kp关键点信息包括方向,尺度,位置信息,des是关键点的描述符
kp,des=sift.detectAndCompute(gray,None)
# 2.3 在图像上绘制关键点的检测结果
cv.drawKeypoints(img,kp,img,flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# 3 图像显示
plt.figure(figsize=(8,6),dpi=100)
plt.imshow(img[:,:,::-1]),plt.title('sift检测')
plt.xticks([]), plt.yticks([])
plt.show()

###### 4 fast算法
# 1 读取图像
img = cv.imread('./image/tv.jpg')
# 2 Fast角点检测
# 2.1 创建一个Fast对象,传入阈值,注意:可以处理彩色空间图像
fast = cv.FastFeatureDetector_create(threshold=30)

# 2.2 检测图像上的关键点
kp = fast.detect(img,None)
# 2.3 在图像上绘制关键点
img2 = cv.drawKeypoints(img, kp, None, color=(0,0,255))

# 2.4 输出默认参数
print( "Threshold: {}".format(fast.getThreshold()) )
print( "nonmaxSuppression:{}".format(fast.getNonmaxSuppression()) )
print( "neighborhood: {}".format(fast.getType()) )
print( "Total Keypoints with nonmaxSuppression: {}".format(len(kp)) )


# 2.5 关闭非极大值抑制
fast.setNonmaxSuppression(0)
kp = fast.detect(img,None)

print( "Total Keypoints without nonmaxSuppression: {}".format(len(kp)) )
# 2.6 绘制为进行非极大值抑制的结果
img3 = cv.drawKeypoints(img, kp, None, color=(0,0,255))

# 3 绘制图像
fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,8),dpi=100)
axes[0].imshow(img2[:,:,::-1])
axes[0].set_title("加入非极大值抑制")
axes[1].imshow(img3[:,:,::-1])
axes[1].set_title("未加入非极大值抑制")
plt.show()



###### 5 ORB算法
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 1 图像读取
img = cv.imread('./image/tv.jpg')

# 2 ORB角点检测
# 2.1 实例化ORB对象
orb = cv.ORB_create(nfeatures=500)
# 2.2 检测关键点,并计算特征描述符
kp,des = orb.detectAndCompute(img,None)

print(des.shape)


# 3 将关键点绘制在图像上
img2 = cv.drawKeypoints(img, kp, None, color=(0,0,255), flags=0)

# 4. 绘制图像
plt.figure(figsize=(10,8),dpi=100)
plt.imshow(img2[:,:,::-1])
plt.title('ORB检测')
plt.xticks([]), plt.yticks([])
plt.show()


####### 6 hog特征提取
# 1.读取图像
img = cv.imread('image/xingren.jpeg')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)

# 2.Hog特征提取
# 2.1 参数设置
winSize = (64,128)
blockSize = (16,16)
blockStride = (8,8)
cellSize = (8,8)
nbins = 9

# 2.2 实例化hog对象
hog = cv.HOGDescriptor(winSize,blockSize,blockStride,cellSize,nbins)

# 2.3 计算Hog特征描述符
hogDes = hog.compute(img,winStride=(8,8))

# 2.4 输出描述符的大小
print(hogDes.size)

12 视频操作

# 视频的一些操作
import cv2 as cv
import numpy as np


####  1 读写


# 1. 读取视频
cap = cv.VideoCapture("G:\k.mp4")

# 2. 获取图像的属性(宽和高,),并将其转换为整数
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))

print(frame_width,frame_height)

# 3. 创建保存视频的对象,设置编码格式,帧率,图像的宽高等
out = cv.VideoWriter('out.avi',cv.VideoWriter_fourcc('M','J','P','G'), 10, (frame_width//4,frame_height//4))
while(True):
    # 4.获取视频中的每一帧图像
    ret, frame = cap.read()
    if ret == True:
        # 5.将每一帧图像写入到输出文件中
        out.write(frame)
    else:
        break

# 6.释放资源
cap.release()
out.release()
#cv.destroyAllWindows()

####### 2 显示
# 1.获取视频对象
cap = cv.VideoCapture("out.avi")

for i in range(20):
    print("第{0}个属性:{1}".format(i, cap.get(i)))
# 3.判断是否读取成功

while(cap.isOpened()):
    # 3.获取每一帧图像
    ret, frame = cap.read()
    # 4. 获取成功显示图像
    if ret == True:
        cv.imshow('frame', frame)
    # 5.每一帧间隔为25ms
    if cv.waitKey(1) & 0xFF == ord('q'):
        break
    # 6.释放视频对象
cap.release()
# cv.destoryAllwindows()


##### 3 目标追踪
# 目标追踪
import numpy as np
import cv2 as cv
# 1.获取图像
cap = cv.VideoCapture('image/DOG.wmv')

# 2.获取第一帧图像,并指定目标位置
ret,frame = cap.read()
# 2.1 目标位置(行,高,列,宽)
r,h,c,w = 197,141,0,208
track_window = (c,r,w,h)
# 2.2 指定目标的感兴趣区域
roi = frame[r:r+h, c:c+w]

# 3. 计算直方图
# 3.1 转换色彩空间(HSV)
hsv_roi =  cv.cvtColor(roi, cv.COLOR_BGR2HSV)
# 3.2 去除低亮度的值
# mask = cv.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
# 3.3 计算直方图
roi_hist = cv.calcHist([hsv_roi],[0],None,[180],[0,180])
# 3.4 归一化
cv.normalize(roi_hist,roi_hist,0,255,cv.NORM_MINMAX)

# 4. 目标追踪
# 4.1 设置窗口搜索终止条件:最大迭代次数,窗口中心漂移最小值
term_crit = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 )

while(True):
    # 4.2 获取每一帧图像
    ret ,frame = cap.read()
    if ret == True:
        # 4.3 计算直方图的反向投影
        hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
        dst = cv.calcBackProject([hsv],[0],roi_hist,[0,180],1)

        # 4.4 进行meanshift追踪
        ret, track_window = cv.meanShift(dst, track_window, term_crit)

        # 4.5 将追踪的位置绘制在视频上,并进行显示
        x,y,w,h = track_window
        img2 = cv.rectangle(frame, (x,y), (x+w,y+h), 255,2)
        cv.imshow('frame',img2)

        if cv.waitKey(60) & 0xFF == ord('q'):
            break
    else:
        break
# 5. 资源释放
cap.release()
cv.destroyAllWindows()


"""
 #进行camshift追踪
    ret, track_window = cv.CamShift(dst, track_window, term_crit)

        # 绘制追踪结果
        pts = cv.boxPoints(ret)
        pts = np.int0(pts)
        img2 = cv.polylines(frame,[pts],True, 255,2)
"""
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓码bigdata

如果文章给您带来帮助,感谢打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值