文章目录
- 前言
- 一、从视频文件读取
- 二、保存摄像头读取到的视频
- 三、图像的8种变换
- 四、灰度直方图
前言
本文为9月9日OpenCV学习笔记——保存摄像头读取到的视频、图像变换、灰度直方图,分为四个章节:
- 从视频文件读取;
- 保存摄像头读取到的视频;
- 图像的8种变换;
- 灰度直方图。
一、从视频文件读取
# 从视频文件读取
import cv2 as cv
import argparse
# 获取参数
parser = argparse.ArgumentParser()
# 添加参数
parser.add_argument("video_path", help="视频文件的路径")
# 解析参数
args = parser.parse_args()
# 加载视频文件
capture = cv.VideoCapture(args.video_path)
# 读取视频
ret, frame = capture.read() # ret: 是否读取到了帧(图片)
while ret:
cv.imshow("video", frame)
ret, frame = capture.read() # 继续读取帧
if cv.waitKey(20) & 0xFF == ord("q"):
break
capture.release()
cv.destroyAllWindows()
二、保存摄像头读取到的视频
- 视频编码:
fourcc = cv2.VideoWriter_fourcc(*'XVID')
; - 灰度写入视频文件:
cv2.VideoWriter(args.video_output, fourcc, int(fps), (int(frame_width), int(frame_height)), False)
.
# 保存从摄像头保存到的视频
import cv2 as cv
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("video_output", help="保存视频的路径")
args = parser.parse_args()
# 捕获摄像头
capture = cv.VideoCapture(0)
# 判断是否打开摄像头
if capture.isOpened() is False:
print("Camera Error!")
# 获取帧的属性:宽、高、FPS
frame_width = capture.get(cv.CAP_PROP_FRAME_WIDTH)
frame_height = capture.get(cv.CAP_PROP_FRAME_HEIGHT)
fps = capture.get(cv.CAP_PROP_FPS)
print("帧的宽度: {}".format(frame_width))
print("帧的高度: {}".format(frame_height))
print("FPS: {}".format(fps))
# 对视频进行编码
fourcc = cv.VideoWriter_fourcc(*"XVID")
output_gray = cv.VideoWriter(args.video_output, fourcc, int(fps), (int(frame_width), int(frame_height)), False)
# 读取摄像头
while capture.isOpened():
ret, frame = capture.read() # 一帧一帧读取
if ret:
# 将读取到的帧转换为灰度
gray_frame = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# 将转换后的帧写入到新的视频文件中
output_gray.write(gray_frame)
# 显示转换后的效果
cv.imshow("gray", gray_frame)
# 等待或按 q 键退出
if cv.waitKey(1) & 0xFF == ord("q"):
break
else:
break
# 释放资源
capture.release()
output_gray.release()
cv.destroyAllWindows()
三、图像的8种变换
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
img = cv.imread("images/blades.png")
plt.imshow(img)
# h, w, c
height, width, channel = img.shape
print(height, width, channel)
>>> 550 865 3
- 图像放大、缩小:
# cv.resize() 放大
resized_img = cv.resize(img, (width*2, height*2), interpolation=cv.INTER_LINEAR)
plt.imshow(resized_img)
# 缩小
small_img = cv.resize(img, None, fx=0.5, fy=0.5, interpolation=cv.INTER_LINEAR)
plt.imshow(small_img)
- 图像平移:
# 平移 transformation cv.warpAffine()
height, width, = img.shape[:2]
M1 = np.float32([[1, 0, 200], [0, 1, 50]]) # 平移矩阵,图像向右移动 200个像素,向下移动 50个像素
move_img = cv.warpAffine(img, M1, (width, height))
plt.imshow(move_img)
M1 = np.float32([[1, 0, -100], [0, 1, -50]]) # 平移矩阵,图像向左移动 200个像素,向上移动 50个像素
move_img2 = cv.warpAffine(img, M1, (width, height))
plt.imshow(move_img2)
- 图像旋转:
height, width = img.shape[:2]
center = (width // 2, height // 2) # 中心点
M3 = cv.getRotationMatrix2D(center, 180, 1) # 正数:逆时针;1:旋转过程中没有缩放
rotation_img = cv.warpAffine(img, M3, (width, height))
plt.imshow(rotation_img)
- 图像仿射变换:
# cv.getAffineTransform(p1, p2)
p1 = np.float32([[120, 35], [215, 45], [135, 120]])
p2 = np.float32([[135, 45], [300, 110], [130, 230]])
M4 = cv.getAffineTransform(p1, p2) # 计算一个变换矩阵
trans_img = cv.warpAffine(img, M4, (width, height))
plt.imshow(trans_img)
- 图像裁剪:
crop_img = img[20:200, 200:300]
plt.imshow(crop_img)
- 图像的位运算(AND, OR, XOR):
# 长方形
rectangle = np.zeros((300, 300), dtype="uint8")
rect_img = cv.rectangle(rectangle, (25, 25), (275, 275), 255, -1)
plt.imshow(rect_img)
# 圆形
rectangle = np.zeros((300, 300), dtype="uint8")
circle_img = cv.circle(rectangle, (150, 150), 150, 255, -1)
plt.imshow(circle_img)
# 与运算 cv.bitwise_and()
and_img = cv.bitwise_and(rect_img, circle_img)
plt.imshow(and_img)
# 或运算
or_img = cv.bitwise_or(rect_img, circle_img)
plt.imshow(or_img)
# 异或运算:两者不相同为 1
xor_img = cv.bitwise_xor(rect_img, circle_img)
plt.imshow(xor_img)
- 图像的分离和融合:
(B, G, R) = cv.split(img) # 分离
# print(B, G, R)
plt.imshow(B)
# 融合
zeros = np.zeros(img.shape[:2], dtype="uint8")
plt.imshow(cv.merge([B, zeros, zeros]))
- 图像的颜色空间:
# 灰度
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
plt.imshow(gray)
# HSV(色度、饱和度、纯度)
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
plt.imshow(hsv)
# Lab
lab = cv.cvtColor(img, cv.COLOR_BGR2LAB)
plt.imshow(lab)
四、灰度直方图
- 定义: 二位统计图表,两个坐标分别是统计样本(图像、视频帧)和样本的某种属性(亮度,像素值,梯度,方向,色彩等等任何特征)。
- 意义:
- 图像中像素强度分布的图形表达方式;
- 统计了每一个强度值所具有的像素个数。
- 特征:
- 不再表征任何的图像纹理信息,而是对图像像素的统计;
- 由于同一物体无论是旋转还是平移在图像中都具有相同的灰度值,因此直方图有平移不变性、放缩不变性等。
- 参数:
cv2.calcHist(images, channels, mask, histSize, range[hest[, accumulate]])
- images:整型类型(uint8和float32)的原图(list形式显示);
- channels : 通道的索引,例如:[0]代表灰度图片,[0],[1],[2]代表多通道;
- mask : 计算图片指定区域的直方图。如果mask为none,那么计算整张图;
- histSize( bins ) : 每个色调值(范围: 0 ~ 255)对应的像素数量。在OpenCV中,用histSize表示bins;
- range : 强度值的范围,[0, 256]。
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 方法:显示图片
def show_image(image, title, pos):
# BGR to RGB
image_RGB = image[:, :, ::-1] # 倒序 channel
# 显示标题
plt.title(title)
plt.subplot(2, 3, pos) # 定位
plt.imshow(image_RGB)
# 方法:显示图片的灰度直方图
def show_histogram(hist, title, pos, color):
# 显示标题
plt.title(title)
plt.subplot(2, 3, pos)
plt.xlabel("Bins")
plt.ylabel("Pixels")
plt.xlim([0, 256]) # 横轴范围
plt.plot(hist, color=color) # 绘制直方图
# 主函数
def main():
# 创建一个画布
plt.figure(figsize=(15, 6)) # 画布大小
plt.suptitle("Gray Image Histogram", fontsize=14, fontweight="bold") # 设置标题形式
# 加载图片
img = cv.imread("images/vonmises.png")
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 计算灰度图的直方图
hist_img = cv.calcHist([img_gray], [0], None, [256], [0, 256])
# 展示灰度直方图
# 灰度图转换成 BGR
img_BGR = cv.cvtColor(img_gray, cv.COLOR_GRAY2BGR)
show_image(img_BGR, "BGR image", 1)
show_histogram(hist_img, "gray image histogram", 4, "m")
plt.show()
if __name__ == '__main__':
main()
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 方法:显示图片
def show_image(image, title, pos):
# BGR to RGB
image_RGB = image[:, :, ::-1] # 倒序 channel
# 显示标题
plt.title(title)
plt.subplot(2, 3, pos) # 定位
plt.imshow(image_RGB)
# 方法:显示图片的灰度直方图
def show_histogram(hist, title, pos, color):
# 显示标题
plt.title(title)
plt.subplot(2, 3, pos)
plt.xlabel("Bins")
plt.ylabel("Pixels")
plt.xlim([0, 256]) # 横轴范围
plt.plot(hist, color=color) # 绘制直方图
# 主函数
def main():
# 创建一个画布
plt.figure(figsize=(15, 6)) # 画布大小
plt.suptitle("Gray Image Histogram", fontsize=14, fontweight="bold") # 设置标题形式
# 加载图片
img = cv.imread("images/vonmises.png")
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 计算灰度图的直方图
hist_img = cv.calcHist([img_gray], [0], None, [256], [0, 256])
# 展示灰度直方图
# 灰度图转换成 BGR
img_BGR = cv.cvtColor(img_gray, cv.COLOR_GRAY2BGR)
show_image(img_BGR, "BGR image", 1)
show_histogram(hist_img, "gray image histogram", 4, "m")
# 对图片中的每个像素值加 50
M = np.ones(img_gray.shape, np.uint8) * 50 # 构建矩阵
added_img = cv.add(img_gray, M)
add_img_hist = cv.calcHist([added_img], [0], None, [256], [0, 256]) # 计算直方图
added_img_BGR = cv.cvtColor(added_img, cv.COLOR_GRAY2BGR)
show_image(added_img_BGR, "added image", 2)
show_histogram(add_img_hist, "added image hist", 5, "m")
# 对图片中的每个像素值减 50
subtract_img = cv.subtract(img_gray, M)
subtract_img_hist = cv.calcHist([subtract_img], [0], None, [256], [0, 256])
subtract_img_BGR = cv.cvtColor(subtract_img, cv.COLOR_GRAY2BGR)
show_image(subtract_img_BGR, "subtracted image", 3)
show_histogram(subtract_img_hist, "subtracted image hist", 6, "m")
plt.show()
if __name__ == '__main__':
main()