基于python的opencv视觉基础知识及例程操作代码【视觉入门看这一篇就够了】

极具画面感的计算机视觉追踪识别!

我个人比较喜欢的近年计算机视觉领域代表论文
He, Kaiming, et al. “Deep residual learning for image recognition.” Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2016.
Liu, Wei, et al. “SSD: Single shot multibox detector.” European Conference on Computer Vision. Springer International Publishing, 2016.
Szegedy, Christian, et al. “Going deeper with convolutions.” Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015.
Ren, Shaoqing, et al. “Faster r-cnn: Towards real-time object detection with region proposal networks.” Advances in neural information processing systems. 2015.
Simonyan, Karen, and Andrew Zisserman. “Very deep convolutional networks for large-scale image recognition.” arXiv preprint arXiv:1409.1556 (2014).
Krizhevsky, Alex, Ilya Sutskever, and Geoffrey E. Hinton. “Imagenet classification with deep convolutional neural networks.” Advances in neural information processing systems. 2012.

1. 计算机视觉入门及Opencv基础知识

1.1 视觉预热知识

  • 8 bits(位值)-> 256 levels(分辨率)
  • 灰度图像:0黑色-255白色,将灰色分成256级,一层
  • 全彩图像RGB:颜色通道(红、绿、蓝),三层,每层的0-255代表该层颜色的亮度,opencv里是BGR
  • HSV:色调(H),饱和度(S),明度(V)(增加黑色V减小,增加白色S减小)
  • H 0-180 ,S 0-255 ,V 0-255
  • 像素:VGA:640480、HD:1280720、FHD:19201080、4K:38402160
  • Opencv中最常用的两种颜色空间转换:BGR<->GRAY,BGR<->HSV
  • bgr先要变换成hsv再目标检测
  • uint8:8位无符号整型

1.2 Opencv安装与基本知识点

OpenCV 是一个的跨平台计算机视觉库,可以运行在 Linux、Windows 和 Mac OS 操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时也提供了 Python 接口,实现了图像处理和计算机视觉方面的很多通用算法。在本文中,将介绍 OpenCV 库,包括它的主要模块和典型应用场景。

(1) 在Python上配置OpenCV
对于 LinuxWindows 操作系统,首需要在 shellcmd 中运行以下命令安装 NumPy:

pip install numpy

然后再安装 OpenCV,可以选择两种不同版本:

  1. 仅安装主模块包
pip install opencv-python
  1. 安装完整包(包括主模块和附加模块)
pip install opencv-contrib-python

(2)OpenCV各主要模块的作用

模块 介绍
core 核心模块,是定义基本数据结构的模块,也包括库中所有其他模块使用的基本函数
imgproc 图像处理模块,包括图像滤波、几何图像变换、颜色空间变换和直方图
imgcodecs 图像文件读写
highgui 高级GUI,提供UI功能的接口,可以执行以下操作:创建和操作可以显示的窗口、将滑动条添加到窗口、键盘命令和处理鼠标事件等
videoio 视频I/O,视频捕获和视频编解码器的接口
video 视频分析模块,包括背景减法、运动估计和目标跟踪算法
calib3d 摄像机标定和三维重建,包括基本的多视点几何算法、立体匹配算法、目标姿态估计、单摄像机和立体摄像机标定以及三维重建
features2d 二维特征框架,该模块包括特征检测器、描述符和描述符匹配器
objdetect 目标检测,检测预定义类的对象和实例(例如,人脸、眼睛、人和汽车)
dnn 深度神经网络(Deep neural network, DNN)模块,本模块包含以下内容:用于创建新层的API、一组预定义的常用层、从层构造和修改神经网络的API、从不同深度学习框架加载序列化网络模型的功能等
ml 机器学习库(Machine Learning Library, MLL)是一组可用于分类、回归和聚类目的的类和方法
flann 快速近似近邻库(Fast Library for Approximate Nearest Neighbors, FLANN)是一组非常适合快速近邻搜索的算法,用于多维空间中的聚类和搜索
photo 计算摄影,提供一些计算摄影的函数
stitching 图像拼接,实现了一个自动拼接全景图像的拼接流水线
shape 形状距离和匹配模块,可用于形状匹配、检索或比较
superres 超分辨率,包含一组可用于提高分辨率的类和方法
videostab 视频稳定,包含一组用于视频稳定的类和方法
viz 三维可视化工具,用于显示与场景交互的小部件

(3) OpenCV的工业应用
OpenCV 可以应用但不仅限于以下场景:二维和三维特征提取、街景图像拼接、人脸识别系统、手势识别、人机交互、动作识别、物体识别、自动检查和监视、分割与识别、医学图像分析、运动跟踪、增强现实、视频/图像搜索与检索、机器人与无人驾驶汽车导航与控制、驾驶员疲劳驾驶检测等。

1.2 OpenCV中像素关系

(1)坐标系
为了更好的展示 OpenCV 中的坐标系以及如何访问各个像素,查看以下低分辨率图像为例:

这个图片的尺寸是 32×41 像素,也就是说,这个图像有 1312 个像素。为了进一步说明,我们可以在每个轴上添加像素计数,如下图所示:

现在,我们来看看 ( x , y ) (x, y)(x,y) 形式的像素索引。请注意,像素索引起始值为零,这意味着左上角位于 ( 0 , 0 ) (0, 0)(0,0),而不是 ( 1 , 1 ) (1, 1)(1,1)。下面的图像,索引了 4 个单独的像素,图像的左上角是原点的坐标:

单个像素的信息可以从图像中提取,方法与 Python 中引用数组的单个元素相同。

(2)通道顺序
在 OpenCV 使用中,使用的颜色通道顺序为 BGR 颜色格式而不是 RGB 格式。可以在下图中看到三个通道的顺序:

BGR 图像的像素结构如下图所示,作为演示,图示详细说明了如何访问pixel(y=n, x=1):

Tips:OpenCV 的最初开发人员选择了 BGR 颜色格式(而不是 RGB 格式),是因为当时 BGR 颜色格式在软件供应商和相机制造商中非常流行,因此选择 BGR 是出于历史原因。
此外,也有其他 Python 包使用的是 RGB 颜色格式(例如,Matplotlib 使用 RGB 颜色格式,Matplotlib 是最流行的 2D Python 绘图库,提供多种绘图方法,可以查看 Python-Matplotlib 可视化获取更多详细信息)。因此,我们需要知道如何将图像从一种格式转换为另一种格式。

(3)在不同颜色空间中访问和操作OpenCV中的像素
本节将介绍如何使用 OpenCV 访问和读取像素值以及如何修改它们。此外,还将学习如何访问图像属性。如果想一次处理多个像素,则需要创建图像区域 (Region of Image, ROI)。
在 Python 中,图像表示为 NumPy 数组。因此,示例中包含的大多数操作都与 NumPy 相关,建议需要对 NumPy 包一些了解,才能更好明白示例代码的原理,但即使不了解也没关系,必要时会对所用函数进行讲解。

(4) 彩色图像访问和操作OpenCV中的像素
现在,我们来看看如何在 OpenCV 中处理BGR图像。如上所述,OpenCV 加载彩色图像时,蓝色通道是第一个,绿色通道是第二个,红色通道是第三个。
首先,使用 cv2.imread() 函数读取图像。图像应该在工作目录中,或者应该提供图片的完整路径。在本例中,读取 sigonghuiye.jpeg 图像并将其存储在img变量中:

img = cv2.imread('sigonghuiye.jpeg')

图像加载到 img 后,可以获得图像的一些属性。我们要从加载的图像中提取的第一个属性是 shape,它将告诉我们行、列和通道的数量(如果图像是彩色的)。我们将此信息存储在 dimensions 变量中:

dimensions = img.shape

第二个属性是图像的大小(img.size=图像高度 × 图像宽度 × 图像通道数):

total_number_of_elements= img.size

第三个属性是图像数据类型,可以通过 img.dtype 获得。因为像素值在 [0-255] 范围内,所以图像数据类型是 uint8 (unsigned char):

image_dtype = img.dtype

上面示例中,我们已经使用了 cv2.imshow() 函数来在窗口中显示图像,这里我们对其进行更详细的介绍,使用 cv2.imshow() 函数显示图像时,窗口会自动适应图像大小。此函数的第一个参数是窗口名,第二个参数是要显示的图像。在这种情况下,由于加载的图像已存储在 img 变量中,因此使用此变量作为第二个参数:

cv2.imshow("original image", img)

显示图像后,我们来介绍下键盘绑定函数——cv2.waitKey(),它为任何键盘事件等待指定的毫秒数。参数是以毫秒为单位的时间。当执行到此函数时,程序将暂停执行,当按下任何键后,程序将继续执行。如果毫秒数为 0 (cv2.waitKey(0)),它将无限期地等待键盘敲击事件:

cv2.waitKey(0)

要访问(读取)某个像素值,我们需要向 img 变量(包含加载的图像)提供所需像素的行和列,例如,要获得 ( x = 40 , y = 6 ) (x=40, y=6)(x=40,y=6) 处的像素值 :

(b, g, r) = img[6, 40]

我们在三个变量 (b, g, r) 中存储了三个像素值。请牢记 OpenCV 对彩色图像使用 BGR 格式。另外,我们可以一次仅访问一个通道。在本例中,我们将使用所需通道的行、列和索引进行索引。例如,要仅获取像素 ( x = 40 , y = 6 ) (x=40, y=6)(x=40,y=6) 处的蓝色值:

b = img[6, 40, 0]

像素值也可以以相同的方式进行修改。例如,要将像素 (x=40, y=6) 处设置为红色:

img[6, 40] = (0, 0, 255)

有时,需要处理某个区域而不是一个像素。在这种情况下,应该提供值的范围(也称切片),而不是单个值。例如,要获取图像的左上角:

top_left_corner = img[0:50, 0:50]

变量 top_left_corner 可以看做是另一个图像(比img小),但是我们可以用同样的方法处理它。
最后,如果想要关闭并释放所有窗口,需要使用 cv2.destroyAllWindows() 函数:

cv2.destroyAllWindows()

(5) 灰度图像访问和操作OpenCV中的像素
灰度图像只有一个通道。因此,在处理这些图像时会引入一些差异。我们将在这里重点介绍这些差异,相同的部分不再赘述。
同样,我们将使用 cv2.imread() 函数来读取图像。在这种情况下,需要第二个参数,因为我们希望以灰度加载图像。第二个参数是一个标志位,指定读取图像的方式。以灰度加载图像所需的值是 cv2.IMREAD_grayscale:

gray_img = cv2.imread('logo.png', cv2.IMREAD_GRAYSCALE)

在这种情况下,我们将图像存储在gray_img变量中。如果我们打印图像的尺寸(使用 gray_img.shape ),只能得到两个值,即行和列。在灰度图像中,不提供通道信息:

dimensions = gray_img.shape

shape将以元组形式返回图像的维度 —— (828, 640)。
像素值可以通过行和列坐标来访问。在灰度图像中,只获得一个值(通常称为像素的强度)。例如,如果我们想得到像素 ( x = 40 , y = 6 ) (x=40, y=6)(x=40,y=6) 处的像素强度:

i = gray_img[6, 40]

图像的像素值也可以以相同的方式修改。例如,如果要将像素 ( x = 40 , y = 6 ) (x=40, y=6)(x=40,y=6) 处的值更改为黑色(强度等于0):

gray_img[6, 40] = 0

1.4 数字图像处理基础

(1) 主要研究目标
我们看可以把图像看作是三维世界的二维视图,那么数字图像作为2D图像,可以使用称为像素的有限数字集进行表示(像素的概念将在像素、颜色、通道、图像和颜色空间部分中详细解释)。我们可以,将计算机视觉的目标定义为将这些2D数据转换为以下内容:

  1. 新的数据表示(例如,新图像)
  2. 决策目标(例如,执行具体决策任务)
  3. 目标结果(例如,图像的分类)
  4. 信息提取(例如,目标检测)
    在进行图像处理时,经常会遇到以下问题:

图像的模糊性,由于受到透视的影响,从而会导致图像视觉外观的变化。例如,从不同的角度看同一个物体会产生不同的图像;
图像通常会受许多自然因素的影响,如光照、天气、反射和运动;
图像中的一部分对象也可能会被其他对象遮挡,使得被遮挡的对象难以检测或分类。随着遮挡程度的增加,图像处理的任务(例如,图像分类)可能非常具有挑战性。
为了更好的解释上述问题,我们假设需要开发一个人脸检测系统。该系统应足够鲁棒,以应对光照或天气条件的变化;此外,该系统应该可以处理头部的运动——用户头部可以在坐标系中每个轴上进行一定程度的动作(抬头、摇头和低头,用户可以离相机稍近或稍远的情况)。而许多人脸检测算法在人脸接近正面时表现出良好的性能,但是,如果一张脸不是正面的(例如,侧面对着镜头),算法就无法检测到它。此外,算法需要即使在用户戴着眼镜或太阳镜时,也可能需要检测面部(即使这会在眼睛区域产生遮挡)。综上所述,当开发一个计算机视觉项目时,我们必须综合考虑到所有这些因素,一个很好的表征方法是有使用大量测试图像来验证算法。我们也可以根据测试图像的不同困难程度来对它们进行分类,以便于检测算法的弱点,提高算法的鲁棒性。

(2) 主要研究方法
完整的图像处理程序通常可以分为以下三个步骤:

读取图像,图像的获取可以有多种不同的来源(相机、视频流、磁盘、在线资源),因此图像的读取可能涉及多个函数,以便可以从不同的来源读取图像;
图像处理,通过应用图像处理技术来处理图像,以实现所需的功能(例如,检测图像中的猫);
显示结果,将图像处理完成后的结果以人类可读的方式进行呈现(例如,在图像中绘制边界框,有时也可能需要将其保存到磁盘)。
此外,上述第2步图像处理可以进一步分为三个不同的处理级别:

低层处理(或者在不引起歧义的情况下可以称为预处理),通常将一个图像作为输入,然后输出另一个图像。可在此步骤中应用的步骤包括但不限于以下方法:噪声消除、图像锐化、光照归一化以及透视校正等;
中层处理:是将预处理后的图像提取其主要特征(例如采用 DNN 模型得到的图像特征),输出某种形式的图像表示,它提取了用于图像进一步处理的主要特征。
高层处理:接受中层处理得到的图像特征并输出最终结果。例如,处理的输出可以是检测到的人脸.
(3) 像素、颜色、通道、图像和颜色空间
在表示图像时,有多种不同的颜色模型,但最常见的是红、绿、蓝 (RGB) 模型。
RGB 模型是一种加法颜色模型,其中原色 (在RGB模型中,原色是红色 R、绿色 G 和蓝色 B) 混合在一起就可以用来表示广泛的颜色范围。
每个原色 (R, G, B) 通常表示一个通道,其取值范围为[0, 255]内的整数值。因此,每个通道有共256个可能的离散值,其对应于用于表示颜色通道值的总比特数 (2 8 = 256 2^8=25628=256)。此外,由于有三个不同的通道,使用 RGB 模型表示的图像称为24位色深图像:

在上图中,可以看到 RGB 颜色空间的“加法颜色”属性:

  1. 红色加绿色会得到黄色
  2. 蓝色加红色会得到品红
  3. 蓝色加绿色会得到青色
  4. 三种原色加在一起得到白色
    因此,如前所述,RGB 颜色模型中,特定颜色可以由红、绿和蓝值分量合成表示,将像素值表示为 RGB 三元组 (r, g, b)。典型的 RGB 颜色选择器如下图所示:

分辨率为 800×1200 的图像是一个包含800列和1200行的网格,每个网格就是称为一个像素,因此其中包含 800×1200=96 万像素。应当注意,图像中有多少像素并不表示其物理尺寸(一个像素不等于一毫米)。相反,像素的大小取决于为该图像设置的每英寸像素数 (Pixels Per Inch, PPI)。图像的 PPI 一般设置在 [200-400] 范围内。
计算PPI的基本公式如下:

  1. PPI=宽度(像素) / 图像宽度(英寸)
  2. PPI=高度(像素) / 图像高度(英寸)
    例如,一个4×6英寸图像,图像分辨率为 800×1200,则PPI是200。

(4) 图像的定义
图像可以描述为2D函数 f ( x , y ) f(x, y)f(x,y),其中 ( x , y ) (x, y)(x,y) 是空间坐标,而 f ( x , y ) f(x, y)f(x,y) 是图像在点 ( x , y ) (x, y)(x,y) 处的亮度或灰度或颜色值。另外,当f(x, y)和(x, y)值都是有限离散量时,该图像也被称为数字图像,此时:

  1. x ∈ [ 0 , h − 1 ] x∈ [0, h-1]x∈[0,h−1],其中 h hh 是图像的高度
  2. y ∈ [ 0 , w − 1 ] y∈ [0, w-1]y∈[0,w−1],其中 w ww 是图像的宽度
  3. f ( x , y ) ∈ [ 0 , L − 1 ] f(x, y)∈ [0,L-1]f(x,y)∈[0,L−1],其中 L = 256 L=256L=256 (对于8位灰度图像)
    彩色图像也可以用同样的方式表示,只是我们需要定义三个函数来分别表示红色、绿色和蓝色值。这三个单独的函数中的每一个都遵循与为灰度图像定义的 f ( x , y ) f(x, y)f(x,y) 函数相同的公式。我们将这三个函数的子索引 R、G 和 B 分别表示为 f R ( x , y ) f_R(x, y)f**R(x,y)、f G ( x , y ) f_G(x, y)f**G(x,y) 和 f B ( x , y ) f_B(x, y)f**B(x,y)。

同样,黑白图像也可以表示为相同的形式,其仅需要一个函数来表示图像,且 f ( x , y ) f(x, y)f(x,y) 只能取两个值。通常,0 表示黑色、1 表示白色。
下图显示了三种不同类型的图像(彩色图像、灰度图像和黑白图像):
数字图像可以看作是真实场景的近似,因为 f ( x , y ) f(x, y)f(x,y) 值是有限的离散量。此外,灰度和黑白图像每个点只对应有一个值,彩色图像每个点需要三个函数对应于图像的红色、绿色和蓝色分量。

(5) 图像文件的类型
尽管在 OpenCV 中处理的图像时,可以将图像看作 RGB 三元组的矩阵(在 RGB 图像模型情况下),但它们不一定是以这种格式创建、存储或传输的。有许多不同的文件格式,如GIF、PNG、位图或JPEG,使用不同形式的压缩(无损或有损)来更有效地表示图像。
下表列示了 OpenCV 支持的文件格式及其关联的文件扩展名:

文件格式 文件扩展名
Windows bitmaps _.bmp和_.dib
JPEG files _.JPEG、_.jpg 和 _.jpe
JPEG 2000 files _.jp2
Portable Network Graphics _.png
Portable image format _.pbm、_.pgm 和 _.ppm
TIFF files _.TIFF 和 _.tif

对图像应用无损或有损压缩算法,可以得到比未压缩图像占据存储空间小的图像。其中,在无损压缩算法中,得到的图像与原始图像等价,也就是说,经过反压缩过程后,得到的图像与原始图像完全等价(相同);而在有损压缩算法中,得到的图像并不等同于原始图像,这意味着图像中的某些细节会丢失,在许多有损压缩算法中,压缩级别是可以调整的。

2. Opencv基础操作代码

2.1 打开照片:

import numpy as np //python的矩阵库
import matplotlib.pyplot //加入窗口的库
import cv2 as cv

img = cv.imread("Picture\love.jpg")
#要在项目工作空间的文件夹里的照片才行

"""img = cv2.imread("Picture\love.jpg",cv2.IMREAD_GRAYSCALE)"""
#后面的第二参数是转化成灰度图

# C:\Users\zhaohaobing\PycharmProjects\python-opencv-project\picture

img = cv.resize(img,None,fx = 0.5,fy = 0.5)
#控制输出图像尺寸(图像,要输出的尺寸大小,长宽各变成几倍)
img_dog = cv2.resize(img_dog, (500, 414))
#输出指定长宽

cv.imshow("love",img)
#照片名字不能用中文的

cv.waitKey(0)
#等待时间,毫米级,0代表任意键才终止
cv.destroyAllWindows()
#任意键关闭
cv.imwrite('picture\ mylove.png',img)
#将照片保存

#res = np.hstack((img1,img2,img3))
#把()里这n张照片放一起

print(img.shape)
#(1200, 1920, 3) h w c(3层还是1层)
print(type(img))
#格式
print(img.size)
#像素点个数
print(img.dtype)
#uint8  数据类型 8位

2.2 读取视频:

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

vc = cv.VideoCapture("video\How do you use your time.mp4")
if vc.isOpened():
    open,frame = vc.read()
#open返回一个True或False,vc.read()是取第一帧第二帧...赋给frame
else:
    open = False

while open:
    ret,frame = vc.read()
    if frame is None:
        break
    if ret == True:
        #gray = cv.cvtColor(frame,cv.COLOR_BGRA2GRAY)
        #灰度处理
        cv.imshow("mytime",frame)
        if cv.waitKey(10) == ord("q"):
            #按q键退出键推出视频
            break
vc.release()
cv.destroyAllWindows()

2.3 打开摄像头:

import numpy as np
import cv2 as cv

cap = cv.VideoCapture(0)
#一般电脑内置摄像头为0,可以通过设置成 1 或者其他的来选择别的摄像头

if not cap.isOpened():
    print("Cannot open camera")
    exit()

while True:
    # Capture frame-by-frame
    ret, frame = cap.read()
    # if frame is read correctly ret is True
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break
    # Our operations on the frame come here
    #gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)#你也可以注释掉这行颜色转换的代码
    # Display the resulting frame
    cv.imshow('myCamera', frame)
    if cv.waitKey(1) == ord('q'):
        break
# When everything done, release the capture
cap.release()
cv.destroyAllWindows()

2.4 保存视频:

#是从摄像头中捕获视频,沿水平方向旋转每一帧并保存它
import numpy as np
import cv2 as cv

cap = cv.VideoCapture(0)
# Define the codec and create VideoWriter object

fourcc = cv.VideoWriter_fourcc(*'XVID')
# ourCC 码以下面的格式传给程序,
# 以 MJPG 为例:cv.VideoWriter_fourcc('M','J','P','G')或者 cv.VideoWriter_fourcc(*'MJPG')。

out = cv.VideoWriter('output.avi', fourcc, 20.0, (640,  480))
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break
    frame = cv.flip(frame, 0)
    # write the flipped frame
    out.write(frame)
    cv.imshow('frame', frame)
    if cv.waitKey(1) == ord('q'):
        break
# Release everything if job is finished
cap.release()
out.release()
cv.destroyAllWindows()

2.5 画线:

import numpy as np
import cv2 as cv

# Create a black image
#((h,w,几层),np采用八进制)
img = np.zeros((512,512,3), np.uint8)

# Draw a diagonal blue line with thickness of 5 px
#(名字,起始点,终止点,颜色(opencv中是BGR),宽度)
cv.line(img,(0,0),(511,511),(255,0,0),5)

cv.imshow('img', img)
cv.waitKey(0)

2.6 画矩形:

import numpy as np
import cv2 as cv
# Create a black image
#((h,w,几层),np采用八进制)
img = np.zeros((512,512,3), np.uint8)

#(名字,左上坐标,右下坐标,颜色(BGR),框线宽度)
#左上角为(0,0)点,向右x正方向,向下y正方向
cv.rectangle(img,(0,0),(100,100),(0,255,0),3)

cv.imshow('img', img)
cv.waitKey(0)

2.7 画圆:

import numpy as np
import cv2 as cv
# Create a black image
#((h,w,几层),np采用八进制)
img = np.zeros((512,512,3), np.uint8)

#(名字,圆心,半径,颜色(BGR),框线厚度(-1及填鸭))
cv.circle(img,(100,100), 66, (0,0,255), -1)

cv.imshow('img', img)
cv.waitKey(0)

2.8 画椭圆:

import numpy as np
import cv2 as cv
# Create a black image
#((h,w,几层),np采用八进制)
img = np.zeros((512,512,3), np.uint8)

#(名字,中心点,长轴短轴长度,整体沿逆时针方向旋转角度,
# 起始角度,终止角度(是不是完成椭圆),颜色,线框宽度
cv.ellipse(img,(256,256),(100,50),0,0,180,255,-1)

cv.imshow('img', img)
cv.waitKey(0)

2.9 画多边形:

import numpy as np
import cv2 as cv
# Create a black image
#((h,w,几层),np采用八进制)
img = np.zeros((512,512,3), np.uint8)

#各个顶点坐标,数据类型int32
pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
pts = pts.reshape((-1,1,2))
cv.polylines(img,[pts],True,(0,255,255))

cv.imshow('img', img)
cv.waitKey(0)

2.10 写字:

import numpy as np
import cv2 as cv
# Create a black image
#((h,w,几层),np采用八进制)
img = np.zeros((500,500,3), np.uint8)

#调用函数,写的字赋给font
font = cv.FONT_HERSHEY_SIMPLEX
#(名字,要写的文字,位值,字,字体大小,颜色,字体笔画宽度
# cv.LINE_AA(字体类型)
cv.putText(img,'OpenCV',(10,500), font, 8,(255,255,255),2,cv.LINE_AA)

cv.imshow('img', img)
cv.waitKey(0)

2.11 图像的基础操作:

import cv2 as cv

img = cv.imread("picture\me.jpg")

#像素的行和列的坐标获取他的像素值
print(img.item(10,10,2))
#修改像素值
img.itemset((10,10,2),100)
print(img.item(10,10,2))
#获取图像属性(行数,列数, 通道数)
print(img.shape)
#图像的像素数目
print(img.size)
#图像的数据类型
print(img.dtype)

2.12 截取选定区域:

import cv2 as cv

img = cv.imread("picture\me.jpg")

#截取选定区域
something = img[0:300, 70:350]
cv.imshow('something',something)
cv.waitKey(0)

2.13 Opencv中常用的颜色空间就三种BGR、HSV、灰度:

Opencv中最常用的两种颜色空间转换:BGR<->GRAY,BGR<->HSV

bgr先要变换成hsv再目标检测

import cv2 as cv

img1 = cv.imread("picture\me.jpg")
img2 = cv.imread("picture\me.jpg")

#BGR↔Gray 的转换
hsv1 = cv.cvtColor(img1, cv.COLOR_BGRA2GRAY)
#BGR↔HSV 的转换
hsv2 = cv.cvtColor(img1, cv.COLOR_BGR2HSV)

cv.imshow("img1",hsv1)
cv.imshow("img2",hsv2)
cv.waitKey(0)

H(色彩/色度)的取值范围是 [0,179], S(饱和度)的取值范围 [0,255],V(亮度)的取值范围 [0,255]。

2.14 颜色跟踪:

在 HSV 颜色空间中要比在 BGR 空间 中更容易表示一个特定颜色。

import cv2 as cv
import numpy as np

cap = cv.VideoCapture(0)

while True :
    ret,frame = cap.read()
    #每一帧先mask处理
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
    #np.array 创建一个数组
    lower_blue = np.array([110,50,50])
    upper_blue = np.array([130,255,255])


    #mask将符合数值区间的黑白提取出来
    #mask掩膜1、创造一个与原图大小相同的全白图(像素全是1),原图中像素在设置区间里的赋为1,其他像素点赋为0,两张图片进行与运算(都为1才为1),则得到mask(全黑图提取部分为白色)
    mask = cv.inRange(hsv,lower_blue,upper_blue)

    #res将提取出来的在还原颜色
    # frame和frame先取’与‘操作,在用其结果和mask取’与‘操作
    # 将mask中白色地方的颜色在前面结果对应地方中显示出来)
    res = cv.bitwise_and(frame,frame,mask = mask)
    cv.imshow('frame', frame)
    cv.imshow('mask', mask)
    cv.imshow('res', res)
    if cv.waitKey(5) & 0xff ==ord("q"):
        break
cv.destroyAllWindows()

2.15 BGR通道分离和合并:

#通道分离
b,g,r = cv.split(frame)
cv.imshow("blue",b)
cv.imshow("green",g)
cv.imshow("red",r)

#第三个通道赋值为零,前面::表示取所有
frame[:,:,2] = 0
#合并
frame = cv.merge([b,g,r])

2.16 程序运行时间:

import cv2 as cv

e1 = cv.getTickCount()
#函数a
e2 = cv.getTickCount()
#可得函数a运行时间
time = (e2 - e1)/cv.getTickFrequency()
print(time)

与& 两个1才为1(黑色是0,白色是1,黑色区域不显示,白色区域显示另一张照片颜色)

and

或| 有1就1 (

not

非~ 0变1 1变0

2.17 数值操作:

#每个像素点都+10
img_cat2= img_cat +10 

#取前五行,所有列,方面后面打印看部分像素值
img_cat[:5,:,0]

2.18 腐蚀操作:

1、先设置滤波器大小

2、设置迭代次数

3、滤波器从左上依次到右下,如果该地方滤波器内像素剧烈变化,对该地方进行腐蚀,即图形信息变细边小,去掉毛毛刺刺

kernel = np.ones((3,3),np.uint8)  #设置he的大小,he越大每次腐蚀的范围就越大
erosion = cv2.erode(img,kernel,iterations = 1) #迭代次数,迭代此时越多腐蚀越多

cv2.imshow('erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.19 膨胀操作:

与腐蚀操作相反,图像变胖

一般先腐蚀去噪,再膨胀恢复

kernel = np.ones((3,3),np.uint8) 
dige_dilate = cv2.dilate(dige_erosion,kernel,iterations = 1)

cv2.imshow('dilate', dige_dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.20 开运算、闭运算、梯度运算、礼帽、黑帽:(腐蚀、膨胀综合操作):

#例如图像

# 开:先腐蚀,再膨胀 (刺没了)
kernel = np.ones((5,5),np.uint8) 
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

# 闭:先膨胀,再腐蚀 (刺变胖了)
kernel = np.ones((5,5),np.uint8) 
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

# 梯度=膨胀-腐蚀,取膨胀和腐蚀中间的部分
gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)

#礼帽 = 原始输入-开运算结果 (只剩刺)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)

#黑帽 = 闭运算-原始输入(只剩刺的轮廓,也可反应主体信息的轮廓)
blackhat  = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT, kernel)

2.21 两照片操作:

import cv2 as cv
import numpy as np

#res = 0.4*cat + 0.6*dog + 0
res = cv2.addWeighted(img_cat, 0.4, img_dog, 0.6, 0)

#两图片相加
def add_demo(m1,m2):
    dst = cv.add(m1,m2)
    cv.imshow("add_demo",dst)
#两图片相减
def subtract_demo(m1,m2):
    dst = cv.subtract(m1,m2)
    cv.imshow("subtract_demo",dst)

#两照片相乘
def multiply_demo(m1,m2):
    dst = cv.multiply(m1,m2)
    cv.imshow("multiply_demo",dst)

#两照片相除
def divide_demo(m1,m2):
    dst = cv.divide(m1,m2)
    cv.imshow("divide_demo",dst)

#
def logic_demo(m1,m2):
    dst = cv.bitwise_and(m1,m2)
    cv.imshow("bitwise_and", dst)



img1 = cv.imread("picture\班徽(中文).jpg")
img2 = cv.imread("picture\班徽En.jpg")
cv.namedWindow('image', cv.WINDOW_NORMAL)

cv.imshow('image1', img1)
cv.imshow('image2', img2)

add_demo(img1,img2)
subtract_demo(img1,img2)
multiply_demo(img1,img2)
divide_demo(img1,img2)


cv.waitKey(0)
cv.destroyAllWindows()

2.22 图像阈值:

"""
语法:ret, dst = cv2.threshold(src, thresh, maxval, type)

- dst: 输出图
- src: 输入图,只能输入单通道图像,通常来说为灰度图
- thresh: 阈值
- maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
- type:二值化操作的类型,包含以下5种类型
"""

#cv2.THRESH_BINARY:超过阈值部分取maxval(最大值),否则取0 (二值化)
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

#cv2.THRESH_BINARY_INV:THRESH_BINARY的反转,超过阈值部分取0,小于部分取最大值
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)

#cv2.THRESH_TRUNC:大于阈值部分设为阈值,小于的不变
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)

#cv2.THRESH_TOZERO:大于阈值部分不改变,小于的设为0
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)

#cv2.THRESH_TOZERO_INV:THRESH_TOZERO的反转,大于阈值部分设为0,小于的不变
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)

titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6):
    plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()



- cv2.THRESH_TOZERO_INV  THRESH_TOZERO的反转

3. 滤波操作:

3.1 图像梯度-Sobel算子:

Gx是水平方向上的检测,Gy是竖直方向上的检测,检测点是九宫格的中间点,距离中心点近的数值大,中心点梯度检测的权重大

X:右减左 A3-A1+2A6-2A4+A9-A7 得到的值越大梯度越大

"""
语法:
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
(输入照片、图像深度(一般为-1)、dxdy选择进行哪个方向的检测那个赋1另一个为0,ksize是sobel算子大小)
"""
#x方向检测
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
#对图像深度进行取绝对值,以为sobel运算结果可能为负值,在opencv中取值是0-255,为负值以后就变成0,所有要取决绝对值,把负值的部分也显示出来
sobelx = cv2.convertScaleAbs(sobelx)
cv_show(sobelx,'sobelx')

#Y方向检测
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)  
cv_show(sobely,'sobely')

#再求和,(x,权重,y,权重,0(这里是偏置项,设置为0))
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show(sobelxy,'sobelxy')

3.2 均值滤波:

设置一个单位矩阵(he(滤波器)边长需为奇数)例3*3

该he从图像左上角滑动到右下角做内积(对应点相乘)

he的中心点的像素点变为为he内九个像素点的平均值。

# 均值滤波
# 简单的平均卷积操作
blur = cv2.blur(img, (3, 3))

cv2.imshow('blur', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.3 高斯滤波:

设置一个矩阵(he(滤波器)边长需为奇数)例3*3,中间是1,四种根据远近权重不同

该he从图像左上角滑动到右下角做内积 (对应点相乘)

he的中心点的像素点变为为he内九个像素点的平均值。

# 高斯滤波
# 高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
aussian = cv2.GaussianBlur(img, (5, 5), 1)  

cv2.imshow('aussian', aussian)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.4 中值滤波:

设置一个he(滤波器)边长需为奇数例3*3

该he从图像左上角滑动到右下角

he的中心点的像素点变为为he内九个像素点的平均值。

# 中值滤波
# 相当于用中值代替
median = cv2.medianBlur(img, 5)  # 中值滤波

cv2.imshow('median', median)
cv2.waitKey(0)
cv2.destroyAllWindows()

三种滤波比较:

中值滤波适合处理椒盐噪声;

3.5 模糊处理去噪:

#均值模糊-去随机噪声
def blur_demo(image):
    dst =  cv.blur(image,(15,1))
    #(1,3)定义一个滤波器一行三列,前值控制横方向的模糊,后值控制纵方向的模糊
    dst = cv.resize(dst ,None,fx = 0.5,fy = 0.5)
    #控制输出图像尺寸(图像,要输出的尺寸大小,长宽各变成几倍)
    cv.imshow("blur_demo",dst)

#中值模糊-去噪椒盐噪声(小黑点)
def median_blur_demo(image):
    dst = cv.medianBlur(image,5)
    cv.imshow("median_blur_demo",dst)

#自定义模糊
def custom_blur_demo(image):
    kernel = np.ones([5,5],np.float32)/25
    #ones([5,5]  5*5大小的全是1的矩阵 /25结果除25保证不溢出
    #kernel = np.array([0,-1,0],[-1,5,-1],[0,-1,0],np.float32)
    #锐化,自定义滤波器总和要为奇数,或=1做增强,=0做边缘
    dst = cv.filter2D(image,-1,kernel = kernel)
    cv.imshow("custom_blur_demo",dst)

3.6 Carry边缘检测:

1、去噪,使用高斯滤波器,以平滑图像,滤除噪声。

2、利用sobel算子计算图像中每个像素点的梯度强度和方向。

3、应用非极大值抑制,以消除边缘检测带来的杂散响应。

(非极大值抑制:即一张图像里有多个目标同时目标相互重叠,这时需要进行非极大值抑制保留概率最大的那个)

4、应用双阈值检测来确定真实的和潜在的边缘。

(即进行两次边界检测保证是边界)

5、通过抑制孤立的弱边缘最终完成边缘检测。

img=cv2.imread("lena.jpg",cv2.IMREAD_GRAYSCALE)

#(picture,minVal,maxval) minVal越小、maxVal越小,保留的边界信息越多
v1=cv2.Canny(img,80,150) 
v2=cv2.Canny(img,50,100)

res = np.hstack((v1,v2))
cv_show(res,'res')

3.7 上采样、下采样:

上采样(放大):

下采样(缩小):

#上采样,将照片放大
up=cv2.pyrUp(img)
cv_show(up,'up')
print (up.shape)

#下采样,将照片缩小
down=cv2.pyrDown(img)
cv_show(down,'down')
print (down.shape)

3.8 轮廓检测:

"""
语法:
cv2.findContours(img,mode,method)
mode:轮廓检索模式
-(默认是它)RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;

method:轮廓逼近方法,即画轮廓
- CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
- CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

"""


img = cv2.imread('contours.png')
#先灰度再二值
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
cv_show(thresh,'thresh')

#二值结果,轮廓信息,轮廓层级(传入预处理的图案,检索所有的轮廓,把所有点都画出来)
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变。。。
#把原图像复制过来操作,避免添加了轮廓信息以后原图像被毁
draw_img = img.copy()
#(被画的图像,轮廓信息,默认-1即把所有轮廓都画上来,轮廓颜色,线条宽度)
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
cv_show(res,'res')

轮廓近似:

在一个图形中,任意两点间连一条线,两点间的曲线上距离该线的最远点的距该线的距离,与阈值作比较

最远距离<阈值:则用该直线代替;

最远距离>阈值:取该点为独立点,与上述两点进行连线,该点与上述两点间各种曲线上的点继续执行上述操作

#轮廓近似
img = cv2.imread('contours2.png')

#先灰度后二值
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

#做轮廓
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]

#轮廓阈值设置 0.15*周长
epsilon = 0.15*cv2.arcLength(cnt,True) 
#轮廓近似 = (输入的轮廓,阈值,true)
approx = cv2.approxPolyDP(cnt,epsilon,True)

draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
cv_show(res,'res')

3.9 高斯模糊:

浮点数计算,耗时耗资源

9*9滤波器 一般拆分成一个横3和一个竖3的两个滤波器,连续处理两次,减少运算量,加快速度

#保证加上噪音后数据还在0-255
def clamp(pv):
    if pv > 255:
        return 255
    if pv < 0:
        return 0
    else :
        return pv


#高斯模糊(均值模糊的拓展)基于权重的

#加噪声
def gaussian_noise(image):
    h,w,c = image.shape
    for row in range(0,h,1):
        #从0开始到h每次加1,(row排)
        for col in range(w):#(col列)
            s = np.random.normal(0,20,3)
            #产生随机数的(从0开始到20产生3个
            b = image[row, col, 0] #blue
            g = image[row, col, 1]
            r = image[row, col, 2]
            image[row, col, 0] = clamp(b + s[0])
            image[row, col, 1] = clamp(b + s[1])
            image[row, col, 2] = clamp(b + s[2])
        cv.imshow("noise_image",src)

gaussian_noise(src)

#高斯处理
dst = cv.GaussianBlur(src,(0,0),15)
#15为高斯公式中的一个参值

cv.imshow("Gaussian",dst)

3.10 边缘保留滤波:(EPF)(美颜)

色彩边缘处,数据差异太大,不参与均值模糊,保留,即高斯双边模糊,差异位值的左右都模糊,差异位值保留

#双边高斯模糊(磨皮效果)
def bi_demo(image):
    dst = cv.bilateralFilter(image,0,100,15)
    #sigmacolor 取大一点,小的差异模糊掉;sigmaspace取小一点,和会小一点,减小计算量
    cv.imshow("bi_demo",dst)

#均值迁移(会有地方过度模糊)(油画效果)
def shift_demo(image):
    dst = cv.pyrMeanShiftFiltering(image,10,50)
    cv.imshow("bi_demo",dst)

3.11 边界填充:

#上下左右填充的多少
top_size,bottom_size,left_size,right_size = (50,50,50,50)


#cv2.copyMakeBorder(图像,上,下,左,右,复制方法)
#BORDER_REPLICATE:复制法,也就是复制最边缘像素
replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)

#BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制例如:fedcba|abcdefgh|hgfedcb  
reflect = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_REFLECT)

#BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)

#BORDER_WRAP:外包装法cdefgh|abcdefgh|abcdefg  
wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)

#BORDER_CONSTANT:常量法,常数值填充
constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_CONSTANT, value=0)


import matplotlib.pyplot as plt
#plt.subplot(列数,行树,本照片在第几个)
plt.subplot(231), plt.imshow(img, 'gray'), plt.title('ORIGINAL')
plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE')
plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT')
plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101')
plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP')
plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT')

plt.show()

3.12 模板匹配:

图img1原图,图img2是img1图中一部分,模板匹配就是看img1图中哪个地方最像B

"""
匹配模式:
TM_SQDIFF_NORMED:归一化平方,计算结果越接近0越相关
TM_CCORR_NORMED:归一化相关性,计算结果越接近1越相关
TM_CCOEFF_NORMED:归一化相关系数,计算结果越接近1越相关
"""

#灰度处理以后
#最后一个输入为匹配模式
#res为2从左上到右下遍历完1以后,每个位置得到的差异值,res长宽分布为 X1-X2+1,Y1-Y2+1
res = cv2.matchTemplate(img1,img2,cv2.TM_SQDIFF_NORMED)

#差异化最小值,差异化最大值,差异化最小值时位置的左上坐标,差异化最大值时位置的左上坐标
min_val,max_val.min__loc,max_loc = cv2.minMaxLoc(res)

匹配多个对象:(1中有多个2)

#灰度处理后进行匹配
res = cv2.matchTemplate(img1,img2,cv2.TM_SQDIFF_NORMED)
#设置阈值,预测结果大于0.8的都留下
threshold = 0.8
loc = np.where(res>=threshold)
for pt in zip(*loc[::-1]):  #*表示可选参数
    bottom right = (pt[0] + w , pt [1]+h)
    cv2.rectangle(img_rgb,pt,bottom_right,(0,0,255),2)
cv2.imshow('img.rgb',img reb)
cv2.waitKey(0)

4. 直方图

bin(横坐标0-255,共256个)

横坐标bin,纵坐标个数,统计图像中不同像素值的个数

#调用包
def plot_demo(image):
    plt.hist(image.ravel(),256,[0,256])
    plt.show()
#自己写
def image_hist(image):
    color = ('blue','green','red')
    for i,color in enumerate(color):
        hist = cv.calcHist([image],[i],None,[256],[0,256])
        plt.plot(hist, color = color)
        plt.xlim([0,256])
    plt.show()

5. 摄像头相关

CMOS摄像头:集成度高,造价低

CCD摄像头:体积大,造价高

饱和度:颜色鲜艳程度

RGB:最大混合将得到亮度最高的颜色——白色

例:R通道中,黑色代表红色光值是0,白色代表红色光值最强是255,某一通道中,黑白代表有无

当我们拍摄能自主发光的物体时,降低曝光时间可以减少环境光的影响。这时通过阈值处理得到二值图就可以进一步处理

gamma矫正:明度和灰度计算公式

识别红色:红色通道减去蓝色通道

提高Gamma后图像中被提升亮度的部分为灰色,而红色部分的灯条没有明显变化

灰色:R=G=B

Gamma矫正结果:

红蓝通道相减:

Gamma矫正,将像素每个像素点进行幂函数倒数的转化,从曲线中可以看到输入数值较小时输出对数入的比值较大,由此可以提高图像暗处的亮度。

Gamma矫正函数曲线:

由于带宽的限制帧率和分辨率通常互相制约,想要高帧率分辨率就会低。

焦距越大视角越窄。

r期望值,e误差值,y实际值

PID算法:

例:直升机升高10m过程

P:kp比例常数,升力=KP*误差,(误差:还有多少距离)

D:kd微分常数,距离微分即速度,当速度过快时d算法抵消一部分升力,减缓震荡,

I:ki积分常数,累计误差从而慢慢达到我们设置的目标

6. 思考题

6.1 Opencv库与Matlab、halcon的区别?

Opencv开源计算机图像库,科研和商用,侧重计算机视觉领域

Matlab比较慢

halcon收费非开源,侧重机器视觉领域

6.2 为什么是import cv2?

cv2中的‘2’代表的不是OpenCV的版本,OpenCV是基于C/C++的,”cv”表示底层使用的是C API,”cv2”表示使用的是C++API。这主要是一个历史遗留问题,是为了保持向后兼容性。

6.3 在显示完之后,用不用cv.destroyWindow()有什么区别?

终止对话框

6.4 png图片格式和jpg图片格式有什么区别?

jpg是二进制24位,有损压缩,持续压缩画质会变差

gif是二进制8位的,支持动图

png,有24位和8位两种,支持透明格式,无损

6.5 HSV和BGR三原色在图片信息存储的差别在哪?

全彩图像RGB:颜色通道(红、绿、蓝),三层,每层的0-255代表该层颜色的亮度,opencv里是BGR

HSV:色调(H),饱和度(S),明度(V),增加黑色V减小,增加白色S减小

7. 练习题

7.1 同时显示两张不同分辨率的图片,对比他们的大小;

img1 = cv.imread("picture\love.jpg")
img2 = cv.imread("picture\me.jpg")

print(img1.shape)
height = img1.shape[0]
weight = img1.shape[1]
channels = img1.shape[2]
print("weight : %s, height : %s, channel : %s" %(weight, height, channels))
print(img2.shape)
height = img2.shape[0]
weight = img2.shape[1]
channels = img2.shape[2]
print("weight : %s, height : %s, channel : %s" %(weight,height,channels))
cv.waitKey(0)

"""
(1200, 1920, 3)
weight : 1920, height : 1200, channel : 3
(1440, 1920, 3)
weight : 1920, height : 1440, channel : 3

"""

7. 2 使用Opencv,测试一下你电脑摄像头的分辨率和帧率是多少;

import cv2 as cv

cap = cv.VideoCapture(0)

if not cap.isOpened():
    print("Cannot open camera.")

while True:
    ret,frame = cap.read()
    if not ret:
        print("Can't receive frame.")
        break
    cv.imshow("myCamera",frame)
    if cv.waitKey(1) == ord("q"):
        break
print(frame.shape)
cap.release()
cv.destroyAllWindows()

#(480, 640, 3)

7.3 利用电脑摄像头从外界拍摄一幅自己的图像,添加圆(或其他图形)给自己打码,图片右下角添加自己的网名和时间。

import cv2 as cv
import time

cap = cv.VideoCapture(0)

if not cap.isOpened():
    print("Capture is not open.")
    exit(0)
    #退出程序
else:
    ret,frame = cap.read()
    cap.release()
    if not ret:
        print("Can't receive frame.")
        exit(0)
    cv.circle(frame,(100,100),66,(0,0,255),1)
    cv.putText(frame, 'ronaldo '+time.asctime(), (350, 400), cv.LINE_AA, 0.5, (255, 255, 255))
    #cv.putText(frame, 'ronaldo' + time.asctime(time.localtime(time.time())), (350, 450), cv.FONT_HERSHEY_SIMPLEX, 0.5,(255, 255, 255))
    cv.imshow("myPicture", frame)
    cv.waitKey(0)
    cv.destroyAllWindows()

7.4 编写一段程序实现以下功能:代码调用电脑摄像头,寻找视野中任意颜色(自定)并具有一定大小的物体,并用矩形框处,最后显示在图像上;

import cv2 as cv
import numpy as np

cap = cv.VideoCapture(0)

while True :
    ret,frame = cap.read()
    hsv = cv.cvtColor(frame,cv.COLOR_BGR2HSV)
    red_lower = np.array([255,192,203])
    red_upper = np.array([220,20,60])

    mask = cv.inRange(hsv,red_lower,red_upper)

    mask = cv.GaussianBlur(mask, (3, 3), 0)
    (cnt_s, _) = cv.findContours(mask.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    if len(cnt_s) > 0:
        cnt = sorted(cnt_s, key=cv.contourArea, reverse=True)

        for i in cnt:
            if len(i) > 60:
                rect = np.int32(cv.boxPoints(cv.minAreaRect(i)))
                cv.drawContours(frame, [rect], -1, (0, 255, 0), 2)

    res = cv.bitwise_and(frame,frame,mask = mask)
    cv.imshow('frame', frame)
    cv.imshow('mask', mask)
    cv.imshow('res', res)
    if cv.waitKey() == ord("q"):
        break
cv.destroyAllWindows()