【OpenCV】(二)OpenCV基础知识和绘制图形
opencv用mat这种数据结构来表示图片的C++是用mat来保存图片的,python中把mat转化成了numpy的ndarray2.13-mat的结构2.14-mat的结构的C++定义2.15Mat属性。
系列内容:OpenCV概述与环境配置,OpenCV基础知识和绘制图形,图像的算数与位运算,图像视频的加载和显示,图像基本变换,滤波器,形态学,图像轮廓,图像直方图,车辆统计项目,特征检测和匹配,图像查找和拼接,虚拟计算器项目,信用卡识别项目,图像的分割与修复,人脸检测与车牌识别,目标追踪,答题卡识别判卷与文档ocr扫描识别,光流估计
(一)OpenCV的色彩空间
1.RGB和BGR
最常见的色彩空间就是RGB,人眼也是按照RGB色彩空间分别颜色OpenCV默认使用BGR,BGR与RGB色彩空间的区别在于图片在色彩通道上的排列顺序不同RGB
(1)RGB
RGB如图2.1所示:
(2)BGR
BGR如图2.2所示:
2.HSV,HSL和YUV
(1)HSV(HSB)
OpenCV使用最多的色彩空间,如图2.3所示:
- Hue:色相,圆盘,0°红,120°黄,240°蓝
- Saturation:饱和度,饱和度越高,颜色越鲜艳
- Value(Brighteness):明度,颜色明亮程度,取值为0\%(黑)-100\%(白)
使用原因:便于图像处理,如根据Vue值来判断背景颜色
(2)HSL
概述:
HSL和HSV差不多
- Hue:色相
- Saturation:饱和度
- Lightness:亮度
HSL和HSV对比,如图2.4所示:
(3)YUV
概述:
YUV是一种颜色编码方式,常使用在各个视频处理组件中.
- Y表示明亮度(Luma)
- U和V表示色度(Chroma)
优势:占用少量的带宽
4:4:4表示完全取样
(4)例子
待处理的图片,如图2.5所示:
读取图片:
import cv2 # 导入OpenCV库
# 读取图片文件
dog = cv2.imread('./dog.jpg')
# 显示图片,窗口名称为'dog'
cv2.imshow('dog', dog)
# 等待用户按键,参数0表示无限等待
cv2.waitKey(0)
# 销毁所有OpenCV窗口
cv2.destroyAllWindows()
矩阵表示,如图2.6所示:
选取前两个矩阵,把各列相加,接着比较不重复的颜色值的和,如图2.7所示:
3.色彩空间转换
代码:
import cv2
def callback(value):
pass
cv2.namedWindow('color', cv2.WINDOW_NORMAL)
cv2.resizeWindow('mouse', 640, 480)
img = cv2.imread('./dog.jpg')
# 颜色空间转换表以COLOR开头
# 读取照片,默认读入照片为BGR
# 常见的颜色空间转换 2=to
colorspaces = [
cv2.COLOR_BGR2RGBA, cv2.COLOR_BGR2BGRA,
cv2.COLOR_BGR2GRAY, cv2.COLOR_BGR2HSV,
cv2.COLOR_BGR2YUV
]
# 设置拖动条,4个格子
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()
BGR,如图2.8所示:
RGB,如图2.9所示:
GRAY,如图2.10所示:
HSV,如图2.11所示:
YUV,如图2.12所示:
(二)OpenCV的重要数据结构--Mat
1.Mat介绍
(1)不同语言中的mat:
opencv用mat这种数据结构来表示图片的
C++是用mat来保存图片的,python中把mat转化成了numpy的ndarray
mat的结构,如图2.13所示:
C++定义,如图2.14所示:
Mat属性,如图2.15所示:
(2)ndarray的四种常见属性:
属性:
- img.data;
- img.size;
- img.dtype;
- img.shape;
- img.ndim;
示例(1)如图2.16所示:
示例(2)如图2.17所示:
2. Mat拷贝
(1)Mat共享数据
Mat共享数据,如图2.18所示:
(2)Mat的拷贝
使用numpy提供的深浅拷贝方法即可实现Mat的拷贝:
import cv2
import numpy as np
img = cv2.imread('./dog.jpg')
# 浅拷贝
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()
或者,利用hstack函数堆叠起来对比:
import cv2
import numpy as np
img = cv2.imread('./dog.jpg')
# 浅拷贝
img2 = img.view()
# 深拷贝
img3 = img.copy()
img[10:100, 10:100] = [0, 0, 255]
cv2.imshow('img', np.hstack((img, img2, img3)))
cv2.waitKey(0)
cv2.destroyAllWindows()
浅拷贝与深拷贝结果,如图2.19所示:
3.访问图像(Mat)的属性
OpenCV中的Mat在python中已经转化为ndarray,通过ndarray的属性即可访问Mate图像的属性
import cv2
import numpy as np
# 读取图片
img = cv2.imread('./dog.jpg')
# 浅拷贝
img2 = img.view()
# 深拷贝
img3 = img.copy()
# 修改原图的部分区域
img[10:100, 10:100] = [0, 0, 255]
# 水平堆叠原图、浅拷贝和深拷贝的图像并显示
cv2.imshow('img', np.hstack((img, img2, img3)))
# 等待按键并关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
4.通道的分离与合并
主要方法:
split(mat)分割图像的通道,merge((ch1,ch2,ch3))融合多个通道
(1)将图片b,g分割后融合
import cv2
import numpy as np
# 创建一个全黑的图像,大小为400x640,3通道,数据类型为np.uint8
img = np.zeros((400, 640, 3), np.uint8)
# 将图像分割成蓝、绿、红三个通道
b, g, r = cv2.split(img)
# 修改蓝色和绿色通道的部分区域为255(白色)
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()
将图片b,g分割后融合结果,如图2.20所示:
(2)将img和img2水平放置在一起对比:
import cv2
import numpy as np
# 创建一个全黑的图像,大小为400x640,3通道,数据类型为np.uint8
img = np.zeros((400, 640, 3), np.uint8)
# 将图像分割成蓝、绿、红三个通道
b, g, r = cv2.split(img)
# 打印蓝色通道(初始全0)
print('b', b)
# 修改蓝色和绿色通道的部分区域为255(白色)
b[10:100, 10:100] = 255
g[10:100, 10:100] = 255
# 合并通道
img2 = cv2.merge((b, g, r))
# 显示原图(蓝色和绿色通道水平堆叠)和修改后的图像(原图和合并后的图像水平堆叠)
cv2.imshow('img', np.hstack((b, g)))
cv2.imshow('img2', np.hstack((img, img2)))
# 等待按键并关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
将img和img2水平放置在一起对比,如图2.21所示:
(三)绘制图形
利用OpenCV提供的绘制图形API可以绘制直线,矩形,圆,椭圆等图形:
1.直线
line(img,pt1,pt2,color,thickness,lineType,shift)画直线
参数说明
- 1.img:在哪个图像上画直线
- 2. pt1,pt2:开始点,结束点指定线的开始和结束位置
- 3. color:颜色
- 4. thickness:线宽
- 5. lineType:线型,线形为-1,4,8,16,默认为8
- 6. shift:坐标缩放比例
绘制直线示例:
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, (180, 100), (480, 580), (0, 0, 255), 5, 16)
# 显示图像
cv2.imshow('draw', img)
# 等待按键并关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
绘制直线,如图2.22所示:
2.矩形
rectangle(img,pt1,pt2,color,thickness,lineType,shift)画矩形
import cv2
import numpy as np
# 创建纯黑的背景图
img = np.zeros((480, 640, 3), np.uint8)
# 绘制矩形
cv2.rectangle(img, (80, 100), (380, 380), (0, 255, 0), 5)
# 显示图像
cv2.imshow('draw', img)
# 等待按键并关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
画矩形,如图2.23所示:
3.圆
circle(img,center,radius,color[,thickness[,lineType[,shift]]])中括号内参数表示可选参数,画圆
import cv2
import numpy as np
# 创建纯黑的背景图
img = np.zeros((480, 640, 3), np.uint8)
# 画圆
cv2.circle(img, (320, 240), 50, (0, 0, 255), 5)
# 显示图像
cv2.imshow('draw', img)
# 等待按键并关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
画圆,如图2.24所示:
4.椭圆
ellipse(img,中心点,长宽的一半,角度,从哪个角度出发,从哪个角度结束....),画椭圆
(1)正椭圆
import cv2
import numpy as np
# 创建纯黑的背景图
img = np.zeros((480, 640, 3), np.uint8)
# 画椭圆
cv2.ellipse(img, (320, 240), (100, 50), 0, 0, 360, (0, 0, 255), 5)
# 显示图像
cv2.imshow('draw', img)
# 等待按键并关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
画正椭圆,如图2.25所示:
(2)倾斜15度椭圆
cv2.ellipse(img,(320,240),(100,50),15,0,360,[0,0,255],5,16)
画倾斜15度椭圆,如图2.26所示:
(3)画半椭圆(0-180度)
cv2.ellipse(img,(320,240),(100,50),15,0,180,[0,0,255],5,16)
如图2.27所示:
5.多边形
polylines(img,[pts],isClosed,color[thinckness[,lineType[,shift]])画多边形
(1)闭合多边形
import cv2
import numpy as np
# 创建纯黑的背景图
img = np.zeros((400, 600, 3), np.uint8)
# 绘制多边形
# pts多边形的点集, 必须是int32位
pts = np.array([[250, 100], [150, 300], [50, 280]], np.int32)
# 注意pts是三维的(这里实际是二维点集,在OpenCV中polylines要求点集为三维数组,最后一个维度是点坐标,可理解为形状为(1, n, 2) )
# 更准确的写法如下(将点集reshape为(1, -1, 2) ):
pts = pts.reshape((-1, 1, 2))
# 或者在创建时就写成三维形式,如:pts = np.array([[[250, 100]], [[150, 300]], [[50, 280]]], np.int32)
# 下面按照正确形式绘制
cv2.polylines(img, [pts], True, (0, 0, 255), 5)
# 另一种常见正确写法,直接定义三维点集
# pts = np.array([[[250, 100], [150, 300], [50, 280]]], np.int32)
# cv2.polylines(img, pts, True, (0, 0, 255), 5)
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
画闭合多边形,如图2.28所示:
(2)不闭合多边形
import cv2
import numpy as np
# 创建纯黑的背景图
img = np.zeros((400, 600, 3), np.uint8)
# 绘制多边形(非闭合)
pts = np.array([[250, 100], [150, 300], [50, 280]], np.int32)
# OpenCV 的 polylines 函数要求点集为特定三维格式,这里调整点集格式
pts = pts.reshape((-1, 1, 2))
cv2.polylines(img, [pts], False, (0, 0, 255), 5)
# 显示图像
cv2.imshow('draw', img)
# 等待按键并关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
画不闭合多边形,如图2.29所示:
(3)fillPoly填充多边形
import cv2
import numpy as np
# 创建纯黑的背景图
img = np.zeros((400, 600, 3), np.uint8)
# 定义多边形的顶点坐标
pts = np.array([[250, 100], [150, 300], [50, 280]], np.int32)
# 调整点集格式为OpenCV要求的三维格式 (n, 1, 2)
pts = pts.reshape((-1, 1, 2))
# 填充多边形
cv2.fillPoly(img, [pts], (0, 0, 255))
# 显示图像
cv2.imshow('draw', img)
# 等待按键并关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
fillPoly填充多边形如图2.30所示:
6.绘制文本
putText(img,text,org,fontScale,color[,thickness[,lineType[,bottomLeftOrigin]]])绘制文本
参数说明:
- text 要绘制的文本
- org 文本在图片的左下角坐标
- fontFace 字体类型即字体
- fontScale 字体大小
(1)显示英文
import cv2
import numpy as np
# 创建纯黑的背景图
img = np.zeros((400, 600, 3), np.uint8)
# 绘制文本
cv2.putText(img, 'Hello OpenCV', (50, 100), cv2.FONT_HERSHEY_COMPLEX, 2, (0, 0, 255), 2)
# 显示图像
cv2.imshow('draw', img)
# 等待按键并关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
显示英文,如图2.31所示:
(2)显示中文
导航到C:/Windows/Fonts,复制任何一个字体样式(ttf),粘贴到mven虚拟机的目录下
from PIL import ImageFont, ImageDraw, Image
import numpy as np
import cv2
# 创建纯白图像
img = np.full((500, 500, 3), fill_value=255, dtype=np.uint8)
# 导入字体文件
font = ImageFont.truetype('./方正粗黑宋简体.ttf', 35)
# 创建一个PIL图片
img_pil = Image.fromarray(img)
draw = ImageDraw.Draw(img_pil)
# 利用draw绘制中文
draw.text((100, 150), '你好,我好', font=font, fill=(0, 255, 0, 0))
# 重新变为ndarray
img = np.array(img_pil)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
显示中文,如图2.32所示:
(3)图片中显示文字
from PIL import ImageFont, ImageDraw, Image
import numpy as np
import cv2
# 导入字体文件
font = ImageFont.truetype('./方正粗黑宋简体.ttf', 35)
# 在图片内显示字符
img = cv2.imread('./dog.jpg')
# 创建一个pillow图片
img_pil = Image.fromarray(img)
draw = ImageDraw.Draw(img_pil)
# 利用draw绘制中文
draw.text((100, 150), '你好,我好', font=font, fill=(0, 255, 0, 0))
# 重新变为ndarray
img = np.array(img_pil)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
图片中显示文字,如图2.33所示:
(四)综合练习
练习:监听鼠标运动绘制图形
思路:
- 按下按键比如1,进入绘制直线模式,需要记录起始位置,即按下鼠标左键的那一瞬间的坐标位置
- 左键起来的鼠标坐标为终点,然后绘制
- 按下l,拖动鼠标,绘制直线
- 按下r,拖动鼠标,绘制矩形
- 按下c,拖动鼠标,绘制圆,拖动的长度可以作为半径
示例代码:
import cv2
import numpy as np
# 这是一个全局标志,判断需要画什么类型的图
curshape = 0
startpos = (0, 0)
# 创建背景图
img = np.zeros((480, 640, 3), np.uint8)
# 要监听鼠标的行为,所以必须通过鼠标回调函数实现
def mouse_callback(event, x, y, flags, userdata):
global curshape, startpos
if event == cv2.EVENT_LBUTTONDOWN:
# 记录起始位置
startpos = (x, y)
elif event == cv2.EVENT_LBUTTONUP:
# 判断要画什么类型的图
if curshape == 0:
# 画直线
cv2.line(img, startpos, (x, y), (0, 0, 255), 3)
elif curshape == 1:
# 画矩形
cv2.rectangle(img, startpos, (x, y), (0, 0, 255), 3)
elif curshape == 2:
# 画圆
# 计算半径
a = (x - startpos[0])
b = (y - startpos[1])
# 注意,画圆时,半径必须为整数
r = int((a**2 + b**2) ** 0.5)
cv2.circle(img, startpos, r, (0, 0, 255), 3)
else:
print('暂不支持')
# 创建窗口
cv2.namedWindow('drawshape', cv2.WINDOW_NORMAL)
# 设置鼠标回调函数
cv2.setMouseCallback('drawshape', mouse_callback)
while True:
cv2.imshow('drawshape', img)
# 检测按键
key = cv2.waitKey(1)
if key == ord('q'):
break
elif key == ord('l'):
curshape = 0
elif key == ord('r'):
curshape = 1
elif key == ord('c'):
curshape = 2
cv2.destroyAllWindows()
监听鼠标运动绘制图形,如图2.34所示:
更多推荐

所有评论(0)