文章目录
- 1.OpenCV介绍
-
- [1.1 OpenCV-Python](#1.1 OpenCV-Python)
- 2.安装OpenCV
- 3.图像视频的加载和显示
-
- [3.1 创建和显示窗口](#3.1 创建和显示窗口)
-
- [3.1.1 cv2.namedWindow(winname, flags)](#3.1.1 cv2.namedWindow(winname, flags))
- [3.1.2 cv2.imshow(winname, mat)](#3.1.2 cv2.imshow(winname, mat))
- [3.1.3 cv2.resizeWindow(winname, width, height)](#3.1.3 cv2.resizeWindow(winname, width, height))
- [3.1.4 retval = cv2.waitKey(delay)](#3.1.4 retval = cv2.waitKey(delay))
- [3.1.5 destroyAllwindws()](#3.1.5 destroyAllwindws())
- [3.1.6 完整示例](#3.1.6 完整示例)
- [3.2 加载显示图片](#3.2 加载显示图片)
- [3.3 imwrite(path, img):保存图片](#3.3 imwrite(path, img):保存图片)
- [3.4 视频采集](#3.4 视频采集)
-
- [3.4.1 循环读取摄像头的每一帧数据](#3.4.1 循环读取摄像头的每一帧数据)
- [3.4.2 循环读取视频的每一帧数据](#3.4.2 循环读取视频的每一帧数据)
- [3.5 视频录制](#3.5 视频录制)
- [3.6 控制鼠标(OpenCV允许我们对窗口上的鼠标动作做出响应)](#3.6 控制鼠标(OpenCV允许我们对窗口上的鼠标动作做出响应))
- [3.7 TrackBar控件](#3.7 TrackBar控件)
- 4.OpenCV基础知识和绘制图形
-
- [4.1 OpenCV的色彩空间](#4.1 OpenCV的色彩空间)
-
- [4.1.1 RGB和BGR](#4.1.1 RGB和BGR)
- [4.1.2 HSV, HSL和YUV](#4.1.2 HSV, HSL和YUV)
-
- [4.1.2.1 HSV(也叫HSB)](#4.1.2.1 HSV(也叫HSB))
- [4.1.2.2 HSL](#4.1.2.2 HSL)
- [4.1.2.3 YUV](#4.1.2.3 YUV)
- [4.1.3 色彩空间的转换](#4.1.3 色彩空间的转换)
- [4.2 OpenCV的重要数据结构--Mat](#4.2 OpenCV的重要数据结构--Mat)
-
- [4.2.1 Mat介绍](#4.2.1 Mat介绍)
- [4.2.2 Mat拷贝](#4.2.2 Mat拷贝)
- [4.2.3 访问图像(Mat)的属性](#4.2.3 访问图像(Mat)的属性)
- [4.2.4 通道的分离与合并](#4.2.4 通道的分离与合并)
- [4.3 绘制图形](#4.3 绘制图形)
- 5.图像的算术与位运算
-
- [5.1 图像的算术运算](#5.1 图像的算术运算)
-
- [5.1.1 图像的加法运算](#5.1.1 图像的加法运算)
- [5.1.2 图像的减法运算](#5.1.2 图像的减法运算)
- [5.1.3 图像的混合](#5.1.3 图像的混合)
- [6. 图像的基本变换](#6. 图像的基本变换)
-
- [6.1 图像的放大与缩小](#6.1 图像的放大与缩小)
- [6.2 图像的翻转](#6.2 图像的翻转)
- [6.3 图像的旋转](#6.3 图像的旋转)
- [6.4 仿射变换之图像平移](#6.4 仿射变换之图像平移)
- [6.5 仿射变换之获取变换矩阵](#6.5 仿射变换之获取变换矩阵)
- [6.6 透视变换](#6.6 透视变换)
1.OpenCV介绍
(1)OpenCV是一款由Intel公司俄罗斯团队发起并参与和维护的一个计算机视觉处理开源软件库,支持与计算机视觉和机器学习相关的众多算法,并且正在日益扩展。
(2)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.1 OpenCV-Python
(1)OpenCV-Python是一个Python绑定库,旨在解决计算机视觉问题。
(2)Python是一种由Guido van Rossum开发的通用编程语言,它很快就变得非常流行,主要是因为它的简单性和代码可读性。它使程序员能够用更少的代码行表达思想,而不会降低可读性。
(3)与C/C++等语言相比,Python速度较慢。也就是说,Python可以使用C/C++轻松扩展,这使我们可以在C/C++中编写计算密集型代码,并创建可用作Python模块的Python包装器。这给我们带来了两个好处:
①首先,代码与原始C/C++代码一样快(因为它是在后台工作的实际C++代码)
②其次,在Python中编写代码比使用C / C++更容易。OpenCV-Python是原始OpenCV C++实现的Python包装器。
(4)OpenCV-Python使用Numpy,这是一个高度优化的数据库操作库,具有MATLAB风格的语法。所有OpenCV数组结构都转换为Numpy数组。这也使得与使用Numpy的其他库(如SciPy和Matplotlib)集成更容易。
2.安装OpenCV
(1)进入虚拟环境, 执行pip install opencv-python==3.4.1.15, 选择该版本的原因是3.4.2之后有些算法申请了专利,用不了了.
(2)安装opencv扩展包(选装): pip install opencv-contrib-python==3.4.1.15
3.图像视频的加载和显示
3.1 创建和显示窗口
3.1.1 cv2.namedWindow(winname, flags)
(1)功能:创建一个可自定义属性的窗口(非必须,imshow会自动创建)。
(2)常用参数:
①winname:窗口名称(字符串),作为唯一标识。
②flags:窗口属性,可选:
- cv2.WINDOW_NORMAL:窗口大小可手动调整。
- cv2.WINDOW_AUTOSIZE(默认):窗口自动适应图像尺寸,不可调整。
- cv2.WINDOW_FULLSCREEN:全屏窗口。
(3)示例:
python
cv2.namedWindow("Preview", cv2.WINDOW_NORMAL) # 创建可调整大小的窗口
3.1.2 cv2.imshow(winname, mat)
(1)功能:在指定窗口中显示图像。
(2)参数:
①winname:目标窗口名称(需与namedWindow一致)。
②mat:图像数据(NumPy数组),支持:
- 彩色图:shape=(H,W,3)(BGR格式)。
- 灰度图:shape=(H,W)。
(3)示例:
python
import numpy as np
img = np.zeros((400, 600, 3), dtype=np.uint8) # 创建黑色图像
cv2.imshow("Preview", img) # 显示图像
3.1.3 cv2.resizeWindow(winname, width, height)
(1)功能:修改窗口尺寸(仅对WINDOW_NORMAL生效)。
(2)参数:
①width:新宽度(像素)。
②height:新高度(像素)。
(3)示例:
python
cv2.namedWindow("Preview", cv2.WINDOW_NORMAL)
cv2.resizeWindow("Preview", 800, 600) # 调整为800x600
3.1.4 retval = cv2.waitKey(delay)
(1)功能:阻塞等待按键事件,并返回按键的ASCII码。
(2)参数:
①delay:等待时间(毫秒)。
- 0:无限等待,直到按键。
-
0:等待指定毫秒后继续执行。
②retval:按键的ASCII码(无按键时返回-1)。
(3)示例:
python
key = cv2.waitKey(0) # 等待任意按键
if key == ord('q'): # 按q键退出
cv2.destroyAllWindows()
3.1.5 destroyAllwindws()
(1)功能:销毁所有由OpenCV创建的窗口。无参数:
(2)无参数:
python
cv2.destroyAllWindows()
(3) # 关闭指定名称的窗口:
python
cv2.destroyWindow("Preview")
3.1.6 完整示例
python
import cv2
import numpy as np
# 1. 创建窗口
cv2.namedWindow("Demo", cv2.WINDOW_NORMAL)
cv2.resizeWindow("Demo", 800, 600)
# 2. 生成图像
img = np.random.randint(0, 255, (400, 600, 3), dtype=np.uint8) # 随机噪声图
# 3. 显示图像
cv2.imshow("Demo", img)
# 4. 等待按键
key = cv2.waitKey(0)
if key == 27: # ESC键退出
cv2.destroyAllWindows()
3.2 加载显示图片
(1)imread(path, flag): 使用imread可以读取图片, 默认读取的是彩色图片.比如:
python
# 导入opencv包
import cv2
import matplotlib.pyplot as plt
import numpy as np
# 读取图片
img = cv2.imread('./cat.jpeg')
(2)原图长这样:

(2)使用matplotlib显示plt.imshow(img), 长这样:

(3)发现这个猫的样子没变, 但是颜色不太对, 这是因为OpenCV读取的图片颜色通道是按照BGR(蓝绿红)排列的, 一般图片通道都是按照RGB来排列的.为了正常的显示猫的图片, 我们要用OpenCV的图像显示方法:
python
cv2.imshow('cat', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
3.3 imwrite(path, img):保存图片
python
import cv2
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 320, 240)
img = cv2.imread("./cat.jpeg")
# 利用while循环优化退出逻辑
while True:
cv2.imshow('img', img)
key = cv2.waitKey(0)
if(key & 0xFF == ord('q')):
break
elif(key & 0xFF == ord('s')):
cv2.imwrite("./123.png", img)
else:
print(key)
cv2.destroyAllWindows()
3.4 视频采集
(1)视频本质由一幅幅图片组成的, 视频的每一帧就是一幅图片, 一般是30帧, 表示一秒显示30张图片。帧数越高看的越流畅
(2) cv2.VideoCapture可以捕获摄像头, 用数字来表示不同的设备, 比如0, 1
①cv2.VideoCapture(0):访问系统默认的第一个摄像头(通常是内置摄像头或第一个被识别的外接摄像头)。
适用场景:笔记本电脑内置摄像头、默认USB摄像头。
②cv2.VideoCapture(1):访问第二个摄像头(如果有)。
适用场景:外接第二个USB摄像头、多摄像头系统中的副摄像头。
(3)
python
# 打开视频文件
vc = cv2.VideoCapture('./1.mp4')
# 打开摄像头
vc = cv2.VideoCapture(0)
3.4.1 循环读取摄像头的每一帧数据
python
import cv2
# 如果打不开,不会报错
cap = cv2.VideoCapture(0)
while cap.isOpened():
# 读一帧数据,返回标记(True表示读到了数据,False表示没读到数据)和这一帧数据
ret,frame = cap.read()
if not ret:
break
# 显示数据
cv2.imshow('video',frame)
key = cv2.waitKey(10)
if key == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
3.4.2 循环读取视频的每一帧数据
python
import cv2
# 如果打不开,不会报错
# 打开视频文件
cap= cv2.VideoCapture('./1.mp4')
while cap.isOpened():
# 读一帧数据,返回标记(True表示读到了数据,False表示没读到数据)和这一帧数据
ret,frame = cap.read()
if not ret:
break
# 显示数据
cv2.imshow('video',frame)
key = cv2.waitKey(10)
if key == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
3.5 视频录制
(1)VideoWriter : 参数一为输出文件, 参数二为多媒体文件格式VideoWriter_fourcc, 参数三为帧率, 参数四为分辨率.
(2)write 编码并写入缓存
(3)release 缓存内容写入磁盘, 并释放资源
python
cap = cv2.VideoCapture(0)
# *mp4v就是解包操作 等同于 'm', 'p', '4', 'v'
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
# (640, 480)表示摄像头拍视频, 这个大小搞错了也不行.
# 主要是这个分辨率.
vw = cv2.VideoWriter('output.mp4', fourcc, 20, (640, 480))
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print('can not recive frame, Exiting...')
break
vw.write(frame)
cv2.imshow('frame', frame)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
#释放VideoWriter
vw.release()
cv2.destroyAllWindows()
3.6 控制鼠标(OpenCV允许我们对窗口上的鼠标动作做出响应)
-
setMouseCallback(winname, callback, userdata) winname是窗口的名字, callback是回调函数, userdata是给回调函数的参数.
-
callback(event, x, y, flags, userdata)回调函数必须包含这5个参数. event是事件(鼠标移动, 左键, 右键等), x,y是点鼠标的坐标点, flags主要用于组合键, userdata就是上面的setMouseCallback的userdata
鼠标事件:
- EVENT_MOUSEMOVE 0 鼠标移动
- EVENT_LBUTTONDOWN 1 按下鼠标左键
- EVENT_RBUTTONDOWN 2 按下鼠标右键
- EVENT_MBUTTONDOWN 3 按下鼠标中键
- EVENT_LBUTTONUP 4 左键释放
- EVENT_RBUTTONUP 5 右键释放
- EVENT_MBUTTONUP 6 中键释放
- EVENT_LBUTTONDBLCLK 7 左键双击
- EVENT_RBUTTONDBLCLK 8 右键双击
- EVENT_MBUTTONDBLCLK 9 中键双击
- EVENT_MOUSEWHEEL 10 鼠标滚轮上下滚动
- EVENT_MOUSEHWHEEL 11 鼠标左右滚动
flags:
- EVENT_FLAG_LBUTTON 1 按下左键
- EVENT_FLAG_RBUTTON 2 按下右键
- EVENT_FLAG_MBUTTON 4 按下中键
- EVENT_FLAG_CRTLKEY 8 按下ctrl键
- EVENT_FLAG_SHIFTKEY 16 按下shift键
- EVENT_FLAG_ALTKEY 32 按下alt键
python
import cv2
import numpy as np
def mouse_callback(event, x, y, flags, userdata):
print(event, x, y, flags, userdata)
# 创建窗口
cv2.namedWindow('mouse', cv2.WINDOW_NORMAL)
cv2.resizeWindow('mouse', 640, 360)
# 设置鼠标回调函数
cv2.setMouseCallback('mouse', mouse_callback, '123')
# 显示窗口和背景
# 生成全黑的图片
img = np.zeros((360, 640, 3), np.uint8)
while True:
cv2.imshow('mouse', img)
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
3.7 TrackBar控件

- createTrackbar(trackbarname, winname, value, count, onChange) 创建TrackBar控件, value为trackbar的默认值, count为bar的最大值, 最小为0
- getTrackbarPos(trackbarname, winname) 获取TrackBar当前值
python
import cv2
import numpy as np
# 创建窗口
cv2.namedWindow('trackbar', cv2.WINDOW_NORMAL)
cv2.resizeWindow('trackbar', 640, 480)
# 定义回调函数
def callback(value):
print(value)
# 创建trackbar
cv2.createTrackbar('R', 'trackbar', 0, 255, callback)
cv2.createTrackbar('G', 'trackbar', 0, 255, callback)
cv2.createTrackbar('B', 'trackbar', 0, 255, callback)
# 创建一个背景图片
img = np.zeros((480, 640, 3), np.uint8)
while True:
# 获取当前trackbar的值
r = cv2.getTrackbarPos('R', 'trackbar')
g = cv2.getTrackbarPos('G', 'trackbar')
b = cv2.getTrackbarPos('B', 'trackbar')
# 改变背景图颜色
img[:] = [b, g, r]
cv2.imshow('trackbar', img)
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
4.OpenCV基础知识和绘制图形
4.1 OpenCV的色彩空间
4.1.1 RGB和BGR
(1)最常见的色彩空间就是RGB, 人眼也是基于RGB的色彩空间去分辨 颜色的.
(2)OpenCV默认使用的是BGR. BGR和RGB色彩空间的区别在于图片在色彩通道上的排列顺序不同.

(3)显示图片的时候需要注意适配图片的色彩空间和显示环境的色彩空间.比如传入的图片是BGR色彩空间, 显示环境是RBG空间, 就会出现颜色混乱的情况
4.1.2 HSV, HSL和YUV
4.1.2.1 HSV(也叫HSB)
(1)OpenCV用的最多的色彩空间是HSV.
①Hue: 色相, 即色彩, 如红色, 蓝色. 用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°
②Saturation: 饱和度, 表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。
③Value: 明度. 明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
(2)为什么要使用HSV?
方便OpenCV做图像处理.比如根据hue的值就可以判断背景颜色.
4.1.2.2 HSL
(1)HSL和HSV差不多
①Hue: 色相
②Saturation: 饱和度
③Lightness: 亮度
(2)HSL在顶部是纯白的, 不管是什么颜色

(3)HSV和HSL的区别:

①HSL中的S:稀释
就像10ml纯红色液体,饱和度100%。加入1L纯净水,颜色就没那么红了,那么饱和度也下降了。
②HSV中的S:混合
就像10ml纯红色液体,饱和度100%。加入白色的液体,混合在一起
4.1.2.3 YUV
(1)YUV是一种颜色编码方法。常使用在各个视频处理组件中。 YUV在对照片或视频编码时,考虑到人类的感知能力,允许降低色度的带宽。
①"Y"表示明亮度(Luminance或Luma),也就是灰阶值
②"U"和"V"表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
(2)Y'UV的发明是由于彩色电视与黑白电视的过渡时期。
(3)Y'UV最大的优点在于只需占用极少的带宽。
- 4:4:4表示完全取样。
- 4:2:2表示2:1的水平取样,垂直完全采样。
- 4:2:0表示2:1的水平取样,垂直2:1采样。
- 4:1:1表示4:1的水平取样,垂直完全采样。
4.1.3 色彩空间的转换
cvtColor(img, colorspace): 颜色转换的关键API
python
import cv2
def callback(value):
pass
cv2.namedWindow('color', cv2.WINDOW_NORMAL)
cv2.resizeWindow('color', 640, 480)
img = cv2.imread('./photo/001.jpg')
# 常见的颜色空间转换 2=to
colorspaces = [cv2.COLOR_BGR2RGBA, cv2.COLOR_BGR2BGRA,
cv2.COLOR_BGR2GRAY, cv2.COLOR_BGR2HSV,
cv2.COLOR_BGR2YUV]
cv2.createTrackbar('curcolor', 'color', 0, 4, callback)
while True:
index = cv2.getTrackbarPos('curcolor', 'color')
#颜色空间转换API
cvt_img = cv2.cvtColor(img, colorspaces[index])
cv2.imshow('color', cvt_img)
key = cv2.waitKey(10)
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
4.2 OpenCV的重要数据结构--Mat
4.2.1 Mat介绍
(1)Mat是OpenCV在C++语言中用来表示图像数据的一种数据结构.在python中转化为numpy的ndarray.
(2)Mat由header和data组成, header中记录了图片的维数, 大小, 数据类型等数据.
(3)在c++中的存储:

4.2.2 Mat拷贝
python
import cv2
import numpy as np
img = cv2.imread('./cat.jpeg')
#浅拷贝
img2 = img.view()
#深拷贝
img3 = img.copy()
img[10:100, 10:100] = [0, 0, 255]
cv2.imshow('img', img)
cv2.imshow('img2', img2)
cv2.imshow('img3', img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.2.3 访问图像(Mat)的属性
python
import cv2
import numpy as np
img = cv2.imread('cat.jpeg')
#shape属性中包括了三个信息
#高度,长度 和 通道数
print(img.shape)
#图像占用多大空间
#高度 * 长度 * 通道数
print(img.size)
#图像中每个元素的位深
print(img.dtype)
4.2.4 通道的分离与合并
(1)split(mat)分割图像的通道
(2)merge((ch1,ch2, ch3)) 融合多个通道
python
import cv2
import numpy as np
img = np.zeros((480, 640, 3), np.uint8)
b,g,r = cv2.split(img)
b[10:100, 10:100] = 255
g[10:100, 10:100] = 255
img2 = cv2.merge((b, g, r))
cv2.imshow('img', img)
cv2.imshow('b', b)
cv2.imshow('g', g)
cv2.imshow('img2', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.3 绘制图形
(1)line(img, pt1, pt2, color, thickness, lineType, shift) 画直线
- img: 在哪个图像上画线
- pt1, pt2: 开始点, 结束点. 指定线的开始与结束位置
- color: 颜色
- thickness: 线宽
- lineType: 线型.线型为-1, 4, 8, 16, 默认为8
- shift: 坐标缩放比例
(2)rectangle() 参数同上,画矩形
(3)circle(img, center, radius, color, thickness\[, lineType\[, shift]]) 中括号内参数表示可选参数. 画圆
python
cv2.circle(
img, # 输入图像(NumPy数组)
center, # 圆心坐标 (x, y)
radius, # 圆的半径(像素)
color, # 圆的颜色(BGR格式,如 (255,0,0) 表示红色)
thickness=1, # 线条粗细(像素),-1 表示填充圆
lineType=8, # 线条类型(默认8连通,可选cv2.LINE_AA抗锯齿)
shift=0 # 坐标小数位数(一般用0)
)
(4)ellipse(img, 中心点, 长宽的一半, 角度, 从哪个角度开始, 从哪个角度结束,...)画椭圆
python
cv2.ellipse(
img, # 输入图像(NumPy数组)
center, # 椭圆中心 (x, y)
axes, # 长轴和短轴长度的一半 (width, height)
angle, # 旋转角度(顺时针,单位:度)
startAngle, # 起始角度(0表示右侧水平方向)
endAngle, # 结束角度(360表示完整椭圆)
color, # 颜色(BGR格式)
thickness=1, # 线条粗细(-1表示填充)
lineType=8, # 线条类型(默认8连通,可选LINE_AA抗锯齿)
shift=0 # 坐标小数位数(通常为0)
)
(5)polylines(img, pts, isClosed, color, thickness\[, lineType\[, shift]]) 画多边形
python
cv2.polylines(
img, # 输入图像(NumPy数组)
pts, # 多边形顶点坐标列表(格式见下文)
isClosed, # 是否闭合(True/False)
color, # 线条颜色(BGR格式)
thickness=1, # 线条粗细(像素)
lineType=8, # 线条类型(默认8连通,可选LINE_AA抗锯齿)
shift=0 # 坐标小数位数(通常为0)
)
(6)fillPoly:填充多边形
python
cv2.fillPoly(
img, # 输入图像(NumPy数组)
pts, # 多边形顶点坐标列表(格式见下文)
color, # 填充颜色(BGR格式)
lineType=8, # 线条类型(默认8连通,可选LINE_AA抗锯齿)
shift=0, # 坐标小数位数(通常为0)
offset=None # 偏移量(可选,(dx, dy))
)
(7)putText(img, text, org, fontFace, fontScale, color, thickness\[, lineType\[, bottomLeftOrigin]]) 绘制文本
- text 要绘制的文本
- org 文本在图片中的左下角坐标
- fontFace 字体类型即字体
- fontScale 字体大小
注意:绘制中文 opencv本身不支持, 因为没有中文字体.我们可以借助pillow来实现绘制中文
python
# 安装pillow
import cv2
import numpy as np
from PIL import ImageFont, ImageDraw, Image
img = np.full((200, 200, 3), fill_value=255, dtype=np.uint8)
# 导入字体文件.
font_path = 'msyhbd.ttc'
font = ImageFont.truetype(font_path, 15)
img_pil = Image.fromarray(img)
draw = ImageDraw.Draw(img_pil)
draw.text((10, 150), '绘制中文', font=font, fill=(0, 255, 0, 0))
img = np.array(img_pil)
# 中文会显示问号
cv2.putText(img, '中文', (10, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 1)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
(8)示例
python
import cv2
import numpy as np
img = np.zeros((480, 640, 3), np.uint8)
# cv2.line(img, (10, 20), (300, 400), (0, 0, 255), 5, 4)
# cv2.line(img, (80, 100), (380, 480), (0, 0, 255), 5, 16)
# 画矩形
# cv2.rectangle(img, (10,10), (100, 100), (0, 0, 255), -1)
# 画圆
# cv2.circle(img, (320, 240), 100, (0, 0, 255))
# cv2.circle(img, (320, 240), 5, (0, 0, 255), -1)
# 画椭圆
# cv2.ellipse(img, (320, 240), (100, 50), 15, 0, 360, (0, 0, 255), -1)
#画多边形
# pts = np.array([(300, 10), (150, 100), (450, 100)], np.int32)
# cv2.polylines(img, [pts], True, (0, 0, 255))
#填充多边形
# cv2.fillPoly(img, [pts], (255, 255, 0))
# 绘制文本
cv2.putText(img, "Hello OpenCV!", (10, 400), cv2.FONT_HERSHEY_TRIPLEX, 3, (255,0,0))
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
5.图像的算术与位运算
5.1 图像的算术运算
5.1.1 图像的加法运算
(1)opencv使用add来执行图像的加法运算
(2)图片就是矩阵, 图片的加法运算就是矩阵的加法运算, 这就要求加法运算的两张图shape必须是相同的
python
# 图片加法
import cv2
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')
# 加法要求两个图片大小一致
print(cat.shape)
print(dog.shape)
# 把猫的图片变小
# 注意坑. opencv中resize中传递新的宽度和高度, 先宽度再高度, 所有是先列后行, 和shape的输出反了.
new_cat = cv2.resize(cat, (dog.shape[:-1][::-1]))
# 和单个数字运算, 超过255 会被截断, 相当于 % 256
print(new_cat[0:5, 0:5])
print(new_cat[0:5, 0:5] + 100)
cv2.imshow('cat_dog', np.hstack((new_cat, dog)))
# add的规则就是两个图对应位置的元素相加,如果超过255, 统一变成255
new_img = cv2.add(new_cat, dog)
print(new_img[0:5, 0:5])
cv2.imshow('cat_dog', np.hstack((new_cat, dog, new_img)))
cv2.waitKey(0)
cv2.destroyAllWindows()
5.1.2 图像的减法运算
opencv使用subtract来执行图像的减法运算, 图像对应位置的元素相减, 如果减完小于0, 统一变成0.
python
# 图片减法
import cv2
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')
# 加法要求两个图片大小一致
print(cat.shape)
print(dog.shape)
# 把猫的图片变小
# 注意坑. opencv中resize中传递新的宽度和高度, 先宽度再高度, 所有是先列后行, 和shape的输出反了.
new_cat = cv2.resize(cat, (dog.shape[:-1][::-1]))
# 减法
new_img = cv2.subtract(new_cat, dog)
print(new_cat[0:5, 0:5], dog[0:5, 0:5])
print(new_img[0:5, 0:5])
cv2.imshow('cat_dog', np.hstack((new_cat, dog, new_img)))
cv2.waitKey(0)
cv2.destroyAllWindows()
5.1.3 图像的混合
(1)图像加法:将两幅图像加载一起cv.add(),图像的混合cv.addweight():将两幅图像按照不同的比例进行混合。图像混合的计算公式如下:通过修改 α 的值(0 → 1),可以实现非常炫酷的混合

(2)现在我们把两幅图混合在一起。第一幅图的权重是0.7,第二幅图的权重是0.3。函数cv2.addWeighted()可以按下面的公式对图片进行混合操作。
dst = α⋅img1 + β⋅img2 + γ(γ是一个亮度调节值,通常设为0)
(3)参考以下代码:
python
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 1 读取图像
img1 = cv.imread("view.jpg")
img2 = cv.imread("rain.jpg")
# 2 图像混合
img3 = cv.addWeighted(img1,0.7,img2,0.3,0)
# 3 图像显示
plt.figure(figsize=(8,8))
plt.imshow(img3[:,:,::-1])
plt.show()
6. 图像的基本变换
6.1 图像的放大与缩小
-
resize(src, dsize, dst\[, fx\[, fy\[, interpolation]]])
- src: 要缩放的图片
- dsize: 缩放之后的图片大小, 元组和列表表示均可.
- dst: 可选参数, 缩放之后的输出图片
- fx, fy: x轴和y轴的缩放比, 即宽度和高度的缩放比.
- interpolation: 插值算法, 主要有以下几种:
- INTER_NEAREST, 邻近插值, 速度快, 效果差.
- INTER_LINEAR, 双线性插值, 使用原图中的4个点进行插值. 默认.
- INTER_CUBIC, 三次插值, 原图中的16个点.
- INTER_AREA, 区域插值, 效果最好, 计算时间最长.
pythonimport cv2 import numpy as np #导入图片 dog = cv2.imread('./dog.jpeg') # x,y放大一倍 new_dog = cv2.resize(dog,dsize=(800, 800), interpolation=cv2.INTER_NEAREST) cv2.imshow('dog', new_dog) cv2.waitKey(0) cv2.destroyAllWindows()
6.2 图像的翻转
- flip(src, flipCode)
- flipCode =0 表示上下翻转
- flipCode >0 表示左右翻转
- flipCode <0 上下 + 左右
python
# 翻转
import cv2
import numpy as np
#导入图片
dog = cv2.imread('./dog.jpeg')
new_dog = cv2.flip(dog, flipCode=-1)
cv2.imshow('dog', new_dog)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.3 图像的旋转
- rotate(img, rotateCode)
- ROTATE_90_CLOCKWISE 90度顺时针
- ROTATE_180 180度
- ROTATE_90_COUNTERCLOCKWISE 90度逆时针
python
# 旋转
import cv2
import numpy as np
#导入图片
dog = cv2.imread('./dog.jpeg')
new_dog = cv2.rotate(dog, rotateCode=cv2.cv2.ROTATE_90_COUNTERCLOCKWISE)
cv2.imshow('dog', new_dog)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.4 仿射变换之图像平移
- 仿射变换是图像旋转, 缩放, 平移的总称.具体的做法是通过一个矩阵和和原图片坐标进行计算, 得到新的坐标, 完成变换. 所以关键就是这个矩阵.
- warpAffine(src, M, dsize, flags, mode, value)
- M:变换矩阵
- dsize: 输出图片大小,先宽度后高度
- flag: 与resize中的插值算法一致
- mode: 边界外推法标志
- value: 填充边界值
- 平移矩阵
- 矩阵中的每个像素由(x,y)组成,(x, y)表示这个像素的坐标. 假设沿x轴平移 t x t_x tx, 沿y轴平移 t y t_y ty, 那么最后得到的坐标为 ( x ^ , y ^ ) = ( x + t x , y + t y ) (\hat x, \hat y) = (x + t_x, y + t_y) (x^,y^)=(x+tx,y+ty), 用矩阵表示就是:

x ^ = 1 ∗ x + 0 ∗ y + y + 1 ∗ t x \hat x = 1*x + 0*y+ y + 1*t_x x^=1∗x+0∗y+y+1∗tx
y ^ = 0 ∗ x + 1 ∗ y + 1 ∗ t y \hat y = 0*x + 1*y + 1*t_y y^=0∗x+1∗y+1∗ty
- 矩阵中的每个像素由(x,y)组成,(x, y)表示这个像素的坐标. 假设沿x轴平移 t x t_x tx, 沿y轴平移 t y t_y ty, 那么最后得到的坐标为 ( x ^ , y ^ ) = ( x + t x , y + t y ) (\hat x, \hat y) = (x + t_x, y + t_y) (x^,y^)=(x+tx,y+ty), 用矩阵表示就是:
python
# 仿射变换之平移
import cv2
import numpy as np
#导入图片
dog = cv2.imread('./dog.jpeg')
h, w, ch = dog.shape
# 往右平移100
M = np.float32([[1, 0, 100], [0, 1, 0]])
# 注意opencv中是先宽度, 再高度
new = cv2.warpAffine(dog, M, (w, h))
cv2.imshow('new', new)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.5 仿射变换之获取变换矩阵
仿射变换的难点就是计算变换矩阵, OpenCV提供了计算变换矩阵的API
- getRotationMatrix2D(center, angle, scale)
- center 中心点 , 以图片的哪个点作为旋转时的中心点.
- angle 角度: 旋转的角度, 按照逆时针旋转.
- scale 缩放比例: 想把图片进行什么样的缩放.
python
# 仿射变换之平移
import cv2
import numpy as np
#导入图片
dog = cv2.imread('./dog.jpeg')
h, w, ch = dog.shape
# M = np.float32([[1, 0, 100], [0, 1, 0]])
# 注意旋转的角度为逆时针.
# M = cv2.getRotationMatrix2D((100, 100), 15, 1.0)
# 以图像中心点旋转
M = cv2.getRotationMatrix2D((w/2, h/2), 15, 1.0)
# 注意opencv中是先宽度, 再高度
new = cv2.warpAffine(dog, M, (w, h))
cv2.imshow('new', new)
cv2.waitKey(0)
cv2.destroyAllWindows()
getAffineTransform(src\[\], dst\[\]) 通过三点可以确定变换后的位置, 相当于解方程, 3个点对应三个方程, 能解出偏移的参数和旋转的角度.
- src原目标的三个点
- dst对应变换后的三个点
python
# 通过三个点来确定M
# 仿射变换之平移
import cv2
import numpy as np
#导入图片
dog = cv2.imread('./dog.jpeg')
h, w, ch = dog.shape
# 一般是横向和纵向的点, 所以一定会有2个点横坐标相同, 2个点纵坐标相同
src = np.float32([[200, 100], [300, 100], [200, 300]])
dst = np.float32([[100, 150], [360, 200], [280, 120]])
# 需要原始图片的三个点坐标,和变换之后三个对应的坐标
M = cv2.getAffineTransform(src, dst)
# 注意opencv中是先宽度, 再高度
new = cv2.warpAffine(dog, M, (w, h))
cv2.imshow('new', new)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.6 透视变换
透视变换就是将一种坐标系变换成另一种坐标系. 简单来说可以把一张"斜"的图变"正".

- warpPerspective(img, M, dsize,...)
- 对于透视变换来说, M是一个3 * 3 的矩阵.
- getPerspectiveTransform(src, dst) 获取透视变换的变换矩阵, 需要4个点, 即图片的4个角.
python
import cv2
import numpy as np
#导入图片
img = cv2.imread('./123.png')
print(img.shape)
# src是原图的4个坐标
src = np.float32([[100, 1100], [2100, 1100], [0, 4000], [2500, 3900]])
dst = np.float32([[0, 0], [2300, 0], [0, 3000], [2300, 3000]])
M = cv2.getPerspectiveTransform(src, dst)
# 透视变换
new = cv2.warpPerspective(img, M, (2300, 3000))
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 640, 480)
cv2.namedWindow('new', cv2.WINDOW_NORMAL)
cv2.resizeWindow('new', 640, 480)
cv2.imshow('img', img)
cv2.imshow('new', new)
cv2.waitKey(0)
cv2.destroyAllWindows()