一、OpenCV-python 之 图像/视频/绘图

1、图像部分

(1)图像读取

cv.imread(filepath, model)
filepath:图片路径
model:cv.IMREAD_COLOR				# 读取3通道BGR图像,默认参数
	   cv.IMREAD_GRAYSCALE			# 读取灰度图
       cv.IMREAD_UNCHANGED			# 读取4通道rgba图像

(1)读取方式是根据文件的编码内容,而不是根据文件名后缀
(2)对于彩色图像,默认读取顺序是:B G R

(2)图像显示

cv.imshow(
	windowsname,		# 窗口名称(保证与其他窗口不同)
    image				# 读取的图像变量
)
cv.waitKey(0)			# 指定显示等待的时间,如果参数值为0则一直显示直到(在图像窗口)按下任何键
cv.destroyAllWindows()	# 销毁窗口

如果图像类型不正确(例如通道顺序),需要通过cv.convertTo、cv.cvtColor等方式去转换。如果图像的数据类型不正确(一般要求 uint8),OpenCV会进行默认处理,这有可能会使得我们看不到想要的结果,具体如下:

  • 如果是 8位无符号,那么照常显示;
  • 如果是 16位无符号/32位整型,那么会除以256(如果像素值偏小,会得到几乎全为黑色的结果);
  • 如果是 32/64位浮点型,那么会乘以255(如果像素值较小,会得到偏白色的结果);

(3)图像保存

cv.imwrite(
    filename,			# 保存位置
    img,				# 图像数据
    params
)

理论上只能保存8位的单通道、3通道BGR图像,但是也有特殊情况(这里包括保存为不同的格式):保存为 .jpg 后缀文件时,数据会有损失;如果是保存为 .png 格式,则是无损保存,保存前后所有位置的像素值都不会改变。

  • 之所以保存为 .jpg 格式会改变数据,是由于 JPG 格式自身存在数据压缩(丢掉一部分不重要的重复数据),也就是说如果一直重复“保存-读取-保存-读取-…”这种操作,数据会不断丢失、图像会不断变小;
  • 虽然可以通过 imwrite 的第三个参数来设置压缩率,但是对于 .jpg 格式来说,即便设置为 100(最大),也还是会有些许损失,无法避免;
  • BMP:这是一种具有深度的图像格式,不采用任何压缩,但是占用文件空间会很大;
  • PNG:这是一种无损压缩格式(有压缩,但是无损),占用空间比 .jpg 大(同样一张图PNG大概比JPG大2-3倍)。

(4)matplotlib的简单使用

img = cv2.imread('messi4.jpg')			# OpenCV读取图像, BGR格式
img2 = img[:, :, ::-1]					# 转换为 RGB 格式
plt.subplot(121);plt.imshow(img)		# plt 显示 BGR 图像
plt.subplot(122);plt.imshow(img2)		# plt 显示 RGB 图像(正常的图像)
plt.show()

OpenCV可以和matplotlib混用,但是OpenCV读取的图像内容按照 BGR 顺序,而matplotlib则是按照 RGB 顺序处理图像,在混用时需要注意顺序的转换

2、视频部分

(1)打开摄像头

cap = cv.VideoCapture(0)
while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()							# 返回第一个参数为bool,读取成功为True

    # Our operations on the frame come here
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)

    # Display the resulting frame
    cv.imshow('frame', frame)
    if cv.waitKey(1) & 0xFF == ord('q'):			# 注意这里waitKey的参数是 1,表示 1 ms刷新
        break

# When everything done, release the capture
cap.release()
cv.destroyAllWindows()

cap.get可以获取视频窗口的参数,cap.set可以设置视频窗口的参数

(2)读取本地视频

cap = cv.VideoCapture('test.avi')		# 将参数改成视频名称即可,后续步骤相同

(3)保存视频

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 ret==True:
        frame = cv.flip(frame,0)

        # write the flipped frame
        out.write(frame)

        cv.imshow('frame',frame)
        if cv.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# Release everything if job is finished
cap.release()
out.release()
cv.destroyAllWindows()

这里需要注意的几个参数:
fourcc:这个需要根据系统类型、系统配置来,一般情况下 XVID 都会适用于Windows,所以保存为 .avi 格式居多;但是在 OSX 中往往是 MJPG/x264 居多。
尺寸大小:要以所存图像的大小为依据,如果错了会导致视频无法播放;而且这个尺寸以 tuple 形式传入,格式是 (width, height),这跟 image.shape 返回的格式刚好相反(OpenCV 中图像数据的类型是 numpy.array,相当于是一个数组,所以它返回的 shape 就是数组的形状(h,w,c))。

(4)视频参数

cap = cv.VideoCapture(v_path)
cap.get([option])			# 获取视频的相关参数
cap.set([option], [value])	# 设置视频的相关参数

参数options:
CV_CAP_PROP_FRAME_WIDTH	:视频宽度
CV_CAP_PROP_FRAME_HEIGHT:视频高度
CV_CAP_PROP_FRAME_COUNT	:视频总帧数
CV_CAP_PROP_FPS			:视频帧率
CV_CAP_PROP_POS_FRAMES	:当前帧的索引数(到第几帧了)

e.g:
cap.get(CV_CAP_PROP_FRAME_COUNT)	:获取视频的总帧数
cap.set(CV_CAP_PROP_POS_FRAMES, 10)	:定位到视频的第10

3、绘图部分

具体参数参考官网实例

# 通用参数
pt1/pt2		: tuple 类型,cv.Point,里面必须是整数
center		: tuple 类型,cv.Point,里面必须是整数
color		: tuple 类型,用来设置线条颜色,注意是 BGR 配色
radius		: int 类型,单位是 px
axes		: tuple 类型,用来设置长短轴
angle		: double 类型,旋转角度
org			: tuple 类型,cv.Point,文字的书写位置
fontFace	: int 类型,可设置值有0~7/16,每种都会呈现不同的字体效果(个人一般取5)
fontScale	: double 类型,字体大小
thickness	: int 类型,用来设置线宽,单位是 px,如果是负值表示填充整个区域
linetype	: 用来设置线型,cv.FILLED/cv.LINE_4/cv.LINE_8/cv.LINE_AA
shift		: 座标中的小数位数,默认为0,一般不作处设置

cv.line(img, pt1, pt2, color, thickness, lineType, shift)
cv.circle(img, center, radius, color, thickness, lineType, shift)
cv.rectangle(img, pt1, pt2, color, thickness, lineType, shift)
cv.ellipse(img, center, axes, angle, startAngle, endAngle, color, thickness, lineType, shift)
cv.putText(img, text, org, fontFace, fontScale, color, thickness, lineType, bottomLeftOrigin)

这里重点看一下 OpenCV 如何在图像中书写文字。OpenCV 书写文字的接口 cv.putText 上面展示了,它总共有九种字体,用 0~7、16 分别编号,具体效果如下:
在这里插入图片描述
有时候我们需要给文字添加背景色,那这个背景区域的长宽、位置该如何确定?这实际上取决于文字的长宽、位置,OpenCV 获取文字尺寸的方式:

cv.getTextSize(
	text,			# 需要书写的文本内容,OpenCV默认不支持中文书写
	fontType, 		# 选择哪种字体
	fontScale, 		# 字体缩放比列
	thickness		# 文本书写的线宽
)

return:
	retval:	(w, h),文本区域所需要的宽高
	baseline: 基线相对于最底部文本点的y座标

所以要注意:OpenCV 书写文本的位置参数并不是左上角,而是基线的最左端;同时,英文还有一个 baseline 距离!因此,如果要给文本添加一个背景色,那么背景区域的左上角、右下角就是 pt1=(pos[0],pos[1]-h), pt2=(pos[0]+w,pos[1]+baseline)
在这里插入图片描述
OpenCV 如何书写中文?它需要借助 PIL:

import cv2 as cv
from PIL import Image, ImageDraw, ImageFont

def draw_(img, text_src, pos, rgb_color, font_scale):
	# 将 OpenCV 的BGR图像转换到 Image 的RGB图像
    out_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
    out_img = Image.fromarray(out_img)

	# 新建画笔
    draw = ImageDraw.Draw(out_img)
    # 字体属性设置
    font = ImageFont.truetype("C:\Windows\Fonts\simhei.ttf", font_scale)
    # 书写汉字,书写位置是左上角
    draw.text(pos, text_src, rgb_color, font=font)
    # 转换回 OpenCV 的BGR空间
    out_img = cv.cvtColor(np.array(out_img), cv.COLOR_RGB2BGR)

    return out_img

4、鼠标事件

(后续补充!)

5、进度条控制参数

(后续补充!)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章