Opencv基本了解、图像读取和绘图

opencv简介:

Opencv的组成

Opencv库有核心模块库Core和扩展模块组成,他们功能如下;

Core 该模块包含 OpenCV 库的基础结构以及基本操作。
Improc 图像处理模块包含基本的图像转换,包括滤波以及类似的卷积操作。

Highgui 在 OpenCV 3.0中,分割为 imcodecs、videoio 以及 highgui 三部分。 这个模块包含可以用来显示图像或者简单的输入的用户交互函数。这可以看作是一个非常轻量级的 Windows UI 工具包。

Video 该模块包含读取和写视频流的函数。

Calib3d 这个模块包括校准单个、双目以及多个相机的算法实现。

Feature2d 这个模块包含用于检测、描述以及匹配特征点的算法。

Objdectect 这个模块包含检测特定目标,比如人脸或者行人的算法。也可以训练检测器并用来检测其他物体。

Ml 机器学习模块本身是一个非常完备的模块,包含大量的机器学习算法实现并且这些算法都能和 OpenCV 的数据类型自然交互。

Flann Flann 的意思是“快速最邻近库”。这个库包含一些你也许不会直接使用的方法,但是其他模块中的函数会调用它在数据集中进行最邻近搜索。

GPU 在 OpenCV 中被分割为多个 cuda* 模块。 GPU 模块主要是函数在 CUDA GPU 上的优化实现,此外,还有一些仅用于 GPU 的功 能。其中一些函数能够返回很好的结果,但是需要足够好的计算资源,如果硬件没有GPU,则不会有什么提升。

Photo 这是一个相当新的模块,包含计算摄影学的一些函数工具。

Stitching 本模块是一个精巧的图像拼接流程实现。这是库中的新功能,但是,就像 Photo 模块一样,这个领域未来预计有很大的增长。

Nonfree OpenCV 包含一些受到专利保护的或者受到使用限制的(比如 SIFT 算法)算法。这些算法被隔离到它们自己的模块中,以表明你需要做一些特殊的工作,才可以在商业产品中使用它们。

Contrib 这个模块包含一些新的、还没有被集成进 OpenCV 库的东西。

Legacy 这个模块包含一些老的尚未被完全取消的东西。

ocl 这是一个较新的模块,可以认为它和 GPU 模块相似,它实现了开放并行编程的 Khronos OpenCL 标准。虽然现在模块的特性比 GPU 模块少很多,但 ocl 模块的目标是提供可以运行在任何 GPU 或者是其他可以搭载 Khronos 的并行设备。这与 GPU 模 块形成了鲜明的对比,后者使用 Nividia CUDA 工具包进行开发,因此只能在 Nividia GPU 设备上工作。

图像读取:

使用函数 cv.imread() 读入图像。这幅图像应该在此程序的工作路径(即相对路径), 或者给函数提供完整路径(绝对路径);

第二个参数是要告诉函数应该如何读取这幅图片:

  • cv.IMREAD_COLOR : 读入一副彩色图像。图像的透明度会被忽略, 这是默认参数,
  • cv.IMREAD_GRAYSCALE :以灰度模式读入图像,
  • cv.IMREAD_UNCHANGED : 读入一幅图像,并且包括图像的 alpha 通道。

这里简单说一下alpha通道,这个通道控制图像的透明度,RGBA 文件(红、绿、蓝、alpha)是 32 位的,具有额外的 8 位 alpha,可以提供 256 个级别的透明度。

opencv contrib各个模块的版本必须要一样么_Desktop


opencv contrib各个模块的版本必须要一样么_ide_02

opencv contrib各个模块的版本必须要一样么_Desktop_03


看来一个RGB三通道的图像,以灰度图的形式打开只有一个通道,以IMREAD_UNCHANGED 形式打开还是只有3个通道,不会添加alpha通道。

图像打开,操作,保存:


图片读取与简单操作

视频读取

import cv2 as cv
import numpy as np
# a=cv.imread(r'C:\Users\19583\Desktop\11.jpg',cv.IMREAD_GRAYSCALE)
# print(a.shape)
cap = cv.VideoCapture(r'C:\Users\19583\Desktop\1.mp4')
while cap.isOpened():
    ret, frame = cap.read()
    # if frame is read correctly ret is True
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break
    cv.imshow('frame',frame)
    if cv.waitKey(100) == ord('q'):#waitKey中数字越大,播放得越慢,然后按q退出
        break

摄像头读取

摄像头读取和视频读取是一样的,摄像头本身从外界读取图像也是有帧数概念的,所有读取摄像头可以看作读取一个无限时长的视频,只不过VideoCapture中放的是具体数值;

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('frame', gray)
    if cv.waitKey(1) == ord('q'):
        break
# When everything done, release the capture
cap.release()
cv.destroyAllWindows()

打开摄像头,转化色彩空间,循环播放图片

保存视频

我们要创建一个 VideoWriter 的对象来保存视频。。我们应该确定一个输出文件 的名字。接下来指定 FourCC 编码(下面会介绍)。播放频率和帧的大小也都 需要确定。最后一个是 isColor 标签。如果是 True,每一帧就是彩色图,否则就是灰度图。

FourCC 就是一个 4 字节码,用来确定视频的编码格式。可用的编码列表 可以从 fourcc.org查到。

FourCC 码以下面的格式传给程序,以 MJPG 为例:cv.VideoWriter_fourcc(‘M’,‘J’,‘P’,‘G’)或者 cv.VideoWriter_fourcc(*‘MJPG’)。

代码如下:

#是从摄像头中捕获视频,沿水平方向旋转每一帧并保存它
import numpy as np
import cv2 as cv
cap = cv.VideoCapture(0)
# Define the codec and create VideoWriter object
fourcc = cv.VideoWriter_fourcc(*'XVID')
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()

绘图:

画线

要画一条线,你只需要告诉函数这条线的起点和终点。我们下面会画一条 从左上方到右下角的蓝色线段。

import numpy as np
import cv2 as cv
# Create a black image
img = np.zeros((512,512,3), np.uint8)
# Draw a diagonal blue line with thickness of 5 px
cv.line(img,(0,0),(511,511),(255,0,0),5)    #opencv中是BGR
cv.imshow('img', img)
cv.waitKey(0)

参数:矩阵,起点,终点,颜色,粗细

画矩形

要画一个矩形,你需要告诉函数的左上角顶点和右下角顶点的坐标。这次 我们会在图像的右上角话一个绿色的矩形;函数 cv.rectangle()

cv.rectangle(img,(384,0),(510,128),(0,255,0),3)

画圆

要画圆的话,只需要指定圆形的中心点坐标和半径大小。我们在上面的矩 形中画一个圆; cv.circle()

cv.circle(img,(447,63), 63, (0,0,255), -1)

画椭圆

画椭圆比较复杂,我们要多输入几个参数。一个参数是中心点的位置坐标。 下一个参数是长轴和短轴的长度。椭圆沿逆时针方向旋转的角度。椭圆弧演 顺时针方向起始的角度和结束角度,如果是 0 到360,就是整个椭圆。查看 cv.ellipse() 可以得到更多信息。下面的例子是在图片的中心绘制半个椭圆。

cv.ellipse(img,(256,256),(100,50),0,0,180,255,-1)

opencv contrib各个模块的版本必须要一样么_OpenCV_04


参数:矩阵,两个点圈定矩形,旋转角度,开始角度,终止角度,颜色,款式

画多边形

画多边形,需要指点每个顶点的坐标。用这些点的坐标构建一个大小等于 行数 X1X2 的数组,行数就是点的数目。这个数组的数据类型必须为 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))

opencv contrib各个模块的版本必须要一样么_opencv_05

添加文字

要在图片上绘制文字,你需要设置下列参数:

你要绘制的文字

你要绘制的位置 •

字体类型(通过查看 cv.putText() 的文档找到支持的字体)

字体的大小 • 文字的一般属性如颜色,粗细,线条的类型等。

为了更好看一点推荐使用 linetype=cv2.LINE_AA。

在图像上绘制白色的 OpenCV。

font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv.LINE_AA)

思考题

Opencv库与Matlab、halcon的区别?
详见这里

为什么是import cv2?

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

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

好像没区别,按一下按键后窗口都正常关闭了

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

opencv contrib各个模块的版本必须要一样么_OpenCV_06

练习题:

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

import cv2 as cv
import numpy as np
a=cv.imread(r'C:\Users\19583\Desktop\11.jpg',cv.IMREAD_COLOR)
b=a.copy()
a=cv.resize(a,(800,800))
b=cv.resize(b,(40,40))
cv.namedWindow('a',cv.CV_32S)
cv.namedWindow('b',cv.CV_32S)
cv.imshow('a',a)
cv.imshow('b',b)
cv.waitKey(0)

opencv contrib各个模块的版本必须要一样么_OpenCV_07

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

import cv2 as cv
import numpy as np
cap = cv.VideoCapture(0)
# Define the codec and create VideoWriter object
fourcc = cv.VideoWriter_fourcc(*'XVID')
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
cap.get(??)
# Release everything if job is finished
cap.release()
out.release()
cv.destroyAllWindows()

在??中填入下面的选项就行了,电脑没有摄像头试不了
cv2.CAP_PROP_POS_MSEC 0 视频文件的当前位置(以毫秒为单位)或视频捕获时间戳
cv2.CAP_PROP_POS_FRAMES 1 基于0的索引将被解码/捕获下一帧
cv2.CAP_PROP_POS_AVI_RATIO 2 视频文件的相对位置:0 - 视频的开始,1 - 视频的结束
cv2.CAP_PROP_FRAME_WIDTH 3 帧的宽度
cv2.CAP_PROP_FRAME_HEIGHT 4 帧的高度
cv2.CAP_PROP_FPS 5 帧速
cv2.CAP_PROP_FOURCC 6 4个字符表示的视频编码器格式
cv2.CAP_PROP_FRAME_COUNT 7 帧数
cv2.CAP_PROP_FORMAT 8 byretrieve()返回的Mat对象的格式
cv2.CAP_PROP_MODE 9 指示当前捕获模式的后端特定值
cv2.CAP_PROP_BRIGHTNESS 10 图像的亮度(仅适用于相机)
cv2.CAP_PROP_CONTRAST 11 图像对比度(仅适用于相机)
cv2.CAP_PROP_SATURATION 12 图像的饱和度(仅适用于相机)
cv2.CAP_PROP_HUE 13 图像的色相(仅适用于相机)
cv2.CAP_PROP_GAIN 14 图像的增益(仅适用于相机)
cv2.CAP_PROP_EXPOSURE 15 曝光(仅适用于相机)
cv2.CAP_PROP_CONVERT_RGB 16 表示图像是否应转换为RGB的布尔标志
cv2.CAP_PROP_WHITE_BALANCE 17 目前不支持
cv2.CAP_PROP_RECTIFICATION 18 立体摄像机的整流标志

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

import cv2 as cv
import numpy as np
src=cv.imread(r'C:\Users\19583\Desktop\3.jpg',cv.IMREAD_COLOR)
print(src.shape)
cv.circle(src,(1500,1000),100,(255,0,0),500)
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(src,"carbon 2021  2  5",(1500,2900), font, 4,(255,255,255),15,cv.LINE_AA)
cv.namedWindow('1',cv.CV_32SC3)
cv.imshow('1',src)
cv.waitKey()

opencv contrib各个模块的版本必须要一样么_Desktop_08


电脑没摄像头,就用手机拍了一张