图片&视频的加载和显示

机器视觉基础

1.1 机器视觉的应用
  • 物体识别: 人脸识别, 车辆检测
  • 识别图像中的文字(OCR)
  • 图像拼接, 修复, 背景替换

图像视频的加载和显示

2.1 创建和显示窗口
  • namedWindow() 创建命名窗口
  • imshow() 显示窗口
  • destroyAllwindws() 摧毁窗口
2.2 加载显示图片
# 导入opencv包
import cv2
import numpy as np

# cv2.namedWindow('new', cv2.WINDOW_AUTOSIZE)
# WINDOW_NORMAL可以让窗口大小变得可以调节
cv2.namedWindow('new', cv2.WINDOW_NORMAL)
# 修改窗口大小
cv2.resizeWindow('new', 1920, 1080)
cv2.imshow('new', 0)

# 读取图片
img = cv2.imread('./cat.jpeg')

# waitKey方法表示等待按键, 0表示任何按键, 其他整数表示等待按键的时间,单位是毫秒, 超过时间没有发生按键操作窗口会自动关闭.
# 会返回按键的ascii的值
key = **cv2.waitKey**(0)
if key == ord('q'):
	cv2.destroyAllWindows()
2.3 保存图片
  • cv2.imwrite(“./123.png”, img)
2.4 视频采集
  • 视频是由图片组成的, 视频的每一帧就是一幅图片, 一般是30帧, 表示一秒显示30张图片.
  • cv2.VideoCapture可以捕获摄像头, 用数字来表示不同的设备, 比如0, 1.
  • 如果是视频文件, 可以直接指定路径即可.
# 打开视频文件
vc = cv2.VideoCapture('./1.mp4')
# 打开摄像头
vc = cv2.VideoCapture(0)

# 检查是否正常打开
if vc.isOpened():
# 读取视频的一帧.
	open, frame = vc.read()  # cap.read() 返回两个值, 第一个为状态值, 读到帧为True, 第二个值为视频帧.
else:
	open = False

# 循环读取视频每一帧数据
while True:
	# 可以读到内容ret返回True
	ret, frame = vc.read()
	# 读到最后frame就是空
	if frame is None:
		break
	if ret == True:
		cv2.imshow('result', gray)
		# 0xFF == 27表示按esc退出键会退出
		if cv2.waitKey(33) & 0xFF == 27:
			break
vc.release()  # 循环读取摄像头的每一帧数据
cv2.destroyAllWindows()
2.5 视频录制
  • VideoWriter : 参数一为输出文件, 参数二为多媒体文件格式(VideoWriter_fourcc, 参数三为帧率, 参数四为分辨率.
  • write 编码并写入缓存.
  • release 缓存内容写入磁盘, 并释放资源.
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()
2.6 控制鼠标

OpenCV允许我们对窗口上的鼠标动作做出响应:

  • setMouseCallback(winname, callback, userdata) winname是窗口的名字,callback是回调函数, userdata是给回调函数的参数.
  • callback(event, x, y, flags, userdata)回调函数必须包含这5个参数. event是事件(鼠标移动, 左键, 右键等), x,y是点鼠标的坐标点, flags主要用于组合键, userdata就是上面的setMouseCallback的 userdata.
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()
TrackBar控件(轨迹条)
  • createTrackbar(trackbarname, winname, value, count, onChange) 创建TrackBar控件, value为trackbar的默认值, count为bar的最大值, 最小为0。
  • getTrackbarPos(trackbarname, winname) 获取TrackBar当前值。

OpenCV基础知识和绘制图形

2.1 OpenCV的色彩空间

  • 最常见的色彩空间就是RGB, 人眼也是基于RGB的色彩空间去分辨 颜色的.

  • OpenCV默认使用的是BGR. BGR和RGB色彩空间的区别在于图片在色彩通道上的排列顺序不同。

  • OpenCV用的最多的色彩空间是HSV

  • Hue: 色相, 即色彩、Saturation: 饱和度, 表示颜色接近光谱色的程度、Value: 明度. 明度表示颜色明亮的程度。

色彩空间的转换:

  • cvtColor(img, colorspace): 颜色转换的关键API
import cv2
def callback(value):
	pass
cv2.namedWindow('color', cv2.WINDOW_NORMAL)
cv2.resizeWindow('color', 640, 480)
img = cv2.imread('./cat.jpeg')
# 常见的颜色空间转换
colorspaces = [cv2.COLOR_BGR2RGBA, cv2.COLOR_BGR2BGRA,cv2.COLOR_BGR2GRAY, cv2.COLOR_BGR2HSV,cv2.COLOR_BGR2YUV]
cv2.createTrackbar('curcolor', 'color', 0, 4, callback)  # 0到4的轨迹条
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()

2.2 OpenCV的重要数据结构–Mat

  • Mat是OpenCV在C++语言中用来表示图像数据的一种数据结构.在python中转化为numpy的ndarray.
  • Mat由header和data组成, header中记录了图片的维数, 大小, 数据类型等数据.
  • 在python中Mat数据对应numpy的ndarray, 使用numpy提供的深浅拷贝方法即可实现Mat的拷贝.
  • split(mat)分割图像的通道
  • merge((ch1,ch2, ch3)) 融合多个通道
import cv2
import numpy as np

# 图像的拷贝
img2 = img.view()  #浅拷贝
img[10:100, 10:100] = [0, 0, 255]
img3 = img.copy()  #深拷贝

# 访问图形的属性
# shape属性中包括了三个信息:高度、长度、通道数
print(img.shape)
# 图像占用多大空间:高度 * 长度 * 通道数
print(img.size)
#图像中每个元素的位深
print(img.dtype)

# 通道拆分和合并
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()

2.3 绘制图形

  • 利用OpenCV提供的绘制图形API可以轻松在图像上绘制各种图形, 比如直线, 矩形, 圆, 椭圆等图形.
  • cv2.line(img, pt1, pt2, color, thickness, lineType, shift) 画直线.
    img: 在哪个图像上画线
    pt1, pt2: 开始点, 结束点. 指定线的开始与结束位置
    color: 颜色
    thickness: 线宽
    lineType: 线型.线型为-1, 4, 8, 16, 默认为8
    shift: 坐标缩放比例.
  • cv2.rectangle() 参数同上 画矩形.
  • cv2.circle(img, center, radius, color[, thickness[, lineType[, shift]]]) 中括号内参数表示可选参数. 画圆.
  • cv2.ellipse(img, 中心点, 长宽的一半, 角度, 从哪个角度开始, 从哪个角度结束,…).
  • cv2.putText(img, “Hello OpenCV!”, (10, 400), cv2.FONT_HERSHEY_TRIPLEX, 3,(255,0,0)) ,英文输入图片
  • 绘制中文本身不支持,但是可以借助pillow 进行绘制
# 安装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()

图像的算术与位运算

3.1 图像的算术运算

  • cv2.add() opencv使用add来执行图像的加法运算。
  • 图片就是矩阵, 图片的加法运算就是矩阵的加法运算, 这就要求加法运算的两张图shape必须是相同的.
  • cv2.subtract()
  • opencv使用subtract来执行图像的减法运算, 图像对应位置的元素相减, 如果减完小于0, 统一变成0.
  • 同样的还有乘法, 除法运算. cv2.mutiply, cv2.divide, 原理是类似的.
# 图片加法
import cv2
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')
print(cat.shape, dog.shape)  # 加法要求两个图片大小一致
# 把猫的图片变小,注意坑. opencv中resize中传递新的宽度和高度, 先宽度再高度, 所有是先列后行, 和shape的输出反了.
new_cat = cv2.resize(cat, (dog.shape[:-1][::-1]))
print(new_cat[0:5, 0:5])
print(new_cat[0:5, 0:5] + 100)  # 和单个数字运算, 超过255 会被截断, 相当于 % 256
cv2.imshow('cat_dog', np.hstack((new_cat, dog)))

new_img = cv2.add(new_cat, dog) # 加法, 加法的效果是加起来如果超过255, 统一变成255,原图变亮。
# new_img = cv2.subtract(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()

3.2 图像的融合

  • cv2.addWeighted(src1, alpha, src2, beta, gamma)
  • 图片的融合操作相当于对图片进行线性运算 w1* x1 + w2 * x2 + b. 其中alpha是第一个权重参数,beta是第二个权重参数, gamma是偏差.
import cv2
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')
new_cat = cv2.resize(cat, (dog.shape[:-1][::-1]))
# 相当于res = new_cat * 0.4 + dog * 0.6 + 0
res = cv2.addWeighted(new_cat, 0.4, dog, 0.6, 0)  # 加权重
cv2.imshow('cat_dog', np.hstack((new_cat, dog, res)))
cv2.waitKey(0)
cv2.destroyAllWindows()

3.3 OpenCV的位运算

  • 非操作:cv2.bitwise_not(img) 非操作的效果就相当于是用 255 - img。 # cat_not = cv2.bitwise_not(cat)
  • 与运算:cv2.bitwise_and(img1, img2) 与运算, 图片对应位置元素进行与操作. 表现出来的效果就是黑和黑与还
    是黑, 白和白与还是白。二进制的值进行运算。 # cat_and_dog = cv2.bitwise_and(new_cat, dog)
  • 或和异或:cv2.bitwise_or 或运算 对应元素做或运算、cv2.bitwise_xor 异或运算 对应元素做异或运算。

更多推荐