opencv学习

入门实例

OpenCV-开源计算机视觉和机器学习软件库,由 C 和 C++构成,提供 Python、Java、MatLAB、JS、C++ 语言接口

用于图像和视频处理分析和机器学习领域

  • 图像处理: 图像滤波、边缘检测、颜色空间转换、形态学操作、特征提取等。
  • 视频分析: 视频捕捉、运动分析、物体检测与追踪等。
  • 机器学习与人工智能: OpenCV 集成了深度学习框架,可以进行人脸识别、目标检测、图像分类等。
  • 计算机视觉: 图像匹配、物体识别、立体视觉、深度图计算等。
python 复制代码
pip install opencv-python
# 额外模块,例如contrib
pip install opencv-contrib-python
# 换源
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
# 验证完成
import cv2
print(cv2.__version__)
# conda安装
conda create -n opencv_env python=3.11
conda activate opencv_env
conda install -c conda-forge opencv

pip install moviepy
python 复制代码
#读取并显示一张图片

# 1.导入cv2 别名cv
import cv2 as cv
# 2.读取图片
img=cv.imread("image")
# 如果None退出
if img is None:
    print("没有找到图片")
    exit()

# 3.显示图片
cv.imshow("窗口名称",img)
# 等待按键输入,然后关闭窗口
# 0表示无限等
k=cv.waitKey(0)
if k==27:
    cv.destroyAllWindows()

案例 1-爬取米哈游并单击键盘显示下一张上一张+自动保存

plain 复制代码
import os.path

import cv2 as cv
import numpy as np
import requests
url="https://bbs-api.miyoushe.com/post/wapi/getPostFull?gids=2&post_id=70866259&read=1"
headers={"Cookie":"_MHYUUID=95e0788a-3bc5-431e-9adf-fbcf1c53e133; DEVICEFP_SEED_ID=717756ecda992498; DEVICEFP_SEED_TIME=1758245231322; DEVICEFP=38d810e662a63",
         "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
"Referer": "https://www.miyoushe.com/",
    "x-rpc-client_type": "4",
    "x-rpc-app_version": "2.99.0",
    "Origin": "https://www.miyoushe.com",
         }
response=requests.get(url,headers=headers).json()
import screeninfo

cv.namedWindow("image", cv.WINDOW_NORMAL)
cv.setWindowProperty("image", cv.WND_PROP_FULLSCREEN, cv.WINDOW_FULLSCREEN)
# 如果你想保持原图比例但填满屏幕,可以 resize
screen = screeninfo.get_monitors()[0]
screen_w, screen_h = screen.width, screen.height

images=response["data"]["post"]["post"]["images"]
def get_img(image):
    r = requests.get(image)
    r.raise_for_status()
    img_array = np.frombuffer(r.content, np.uint8)
    return cv.imdecode(img_array, cv.IMREAD_COLOR)
i=0
while True:
    i=i%len(images)
    image_url=images[i]
    image=image_url.split("/")[-1]

    if os.path.exists("images/"+image):
        img=cv.imread("images/"+image)
    else:
        img = get_img(image_url)
        cv.imwrite("images/"+image, img)
    if img is None:
        print("无法解析图片:",image)
        continue
    img_resized = cv.resize(img, (screen_w, screen_h))
    cv.imshow("image",img_resized)
    key=cv.waitKey(0)
    if key==ord("q") or key==27:
        print("退出")
        break
    elif key==ord("n") or key==83:
        i-=1
        continue
    elif key==ord("p") or key==81:
        i+=1
        continue
cv.destroyAllWindows()

案例 2-视频处理之进行只看运动中的画面

  • VideoCapture().read()获取帧
  • 灰度
  • absdiff 找两帧差异
  • 二值化得到运动区域掩码 threshold 并 maxval 为 255 全白 (代表静止部分为黑色 0,运动区域为 255 白色)
  • 掩码转为三通道 merge (运动为彩色,其余为黑色 0False)
  • 原彩色图做按位与 bitwise_and
  • imshow 显示

改进:太闪了

  • <font style="color:rgb(13, 18, 57);">history</font>:背景模型记忆长度,值越大保持运动物体的时间越久。
  • <font style="color:rgb(13, 18, 57);">varThreshold</font>:像素检测阈值,值小更敏感,值大更稳。
  • <font style="color:rgb(13, 18, 57);">iterations</font>:形态学去噪迭代次数,增加会让画面更干净,但可能丢失细节。

改进:都显示了,因为历史:

  • 限制 history 的长度(比如只保留最近5帧)
  • 或者对旧 mask 做衰减
  • 或者直接交给背景建模器(MOG2/KNN)自动处理持久化
python 复制代码
def get_diff_mp4(video_path):
    cap = cv.VideoCapture(video_path)

    # 读取第一帧
    ret, prev_frame = cap.read()
    if not ret:
        print("无法读取视频")
        return

    prev_gray = cv.cvtColor(prev_frame, cv.COLOR_BGR2GRAY)

    while True:
        ret, frame = cap.read()
        if not ret:
            break

        gray_frame = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)

        # 计算当前帧与前一帧的差异
        frame_diff = cv.absdiff(prev_gray, gray_frame)

        # 二值化,得到运动区域的掩码
        _, mask = cv.threshold(frame_diff, 30, 255, cv.THRESH_BINARY)

        # 掩码转成三通道,与原彩色图做按位与
        mask_3ch = cv.merge([mask, mask, mask])
        moving_parts = cv.bitwise_and(frame, mask_3ch)

        # 显示只有运动部分的彩色画面(背景全黑)
        cv.imshow('Moving Only', moving_parts)

        # 更新前一帧
        prev_gray = gray_frame

        if cv.waitKey(25) & 0xFF == ord('q'):
            break

    cap.release()
    cv.destroyAllWindows()

案例 3-提取 mp4 中的音频 并导出有声音的视频

python 复制代码
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from moviepy.editor import VideoFileClip
import subprocess
from moviepy.editor import VideoFileClip
def exert_mp4_audio(out_path = "videos/33708180019-1-192.mp4")
    clip = VideoFileClip(out_path)

    print("时长:", clip.duration)
    print("音轨对象:", clip.audio)

    if clip.audio:
        # 导出音频单独看看
        clip.audio.write_audiofile("test_audio.wav")
    else:
        print("⛔ 这个视频没有音频轨")

def merge_video(processed_video="videos/33708180019-1-192adaptiveThreshold.mp4",
                original_video="videos/33708180019-1-192.mp4",
                output_video="videos/33708180019-1-192adaptiveThreshold_with_audio.mp4"):
    cmd = [
        "ffmpeg", "-y",
        "-i", processed_video,
        "-i", original_video,
        "-c", "copy",
        "-map", "0:v:0",
        "-map", "1:a:0",
        output_video
    ]
subprocess.run(cmd, check=True)
print("✅ 合并完成,必有音轨")

#  MoviePy 写的时候(哪怕 set_audio(audio))如果参数不对,或者源音频和视频长度略有差异,它会直接丢掉音轨 → 导致最终只有视频流。
def merge_but_no_audio_video(video_path="videos/33708180019-1-192adaptiveThreshold.mp4",
                audio_path="videos/33708180019-1-192.mp4",
                output_video="videos/33708180019-1-192adaptiveThreshold_with_audio.mp4"):

    video = VideoFileClip(video_path) # 截取20秒
    # 从原视频提取音频
    audio = VideoFileClip(audio_path).audio

    if audio is None:
        print("无法解析音频:", audio)
        exit()
    # 添加音频
    final_clip=video.set_audio(audio)
    final_clip.write_videofile(output_video,codec="libx264",            # 视频编码
        audio_codec="pcm_s16le")          # 音频编码

基础模块

OpenCV 基础模块

cv2.

  • core:基础(图像数组表示和操作)
  • imgproc:图像处理(滤波、图像变换、形态学操作)
  • highgui:用户界面模块(显示图像和视频)
  • video:视频处理(视频捕捉、视频流)
  • features2d:特征检测与匹配(角点、边缘、关键点检测)
  • ml:机器学习(图像分类、回归、巨雷)
  • calib3d:相机校准和 3D 重建
  • objdetect:目标检测
  • dnn:深度学习

其他模块:

  • flann:快速近似最近邻搜索
  • Photo:图像修复和去躁
  • Stitching:图像拼接
  • Shape:形状匹配和距离计算

模块库

1. Core 模块

功能: 提供 OpenCV 的核心功能,包括基本数据结构、矩阵操作、绘图函数等。

主要类和函数:

  • Mat: OpenCV 中用于存储图像和矩阵的基本数据结构。
  • Scalar: 用于表示颜色或像素值。
  • Point、Size、Rect: 用于表示点、尺寸和矩形。
  • 基本绘图函数: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.line()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.circle()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.rectangle()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.putText()</font> 等。

应用场景:

  • 图像的基本操作(如创建、复制、裁剪)。
  • 绘制几何图形和文本。

2. Imgproc 模块

功能: 提供图像处理功能,包括图像滤波、几何变换、颜色空间转换等。

主要类和函数:

  • 图像滤波: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.blur()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.GaussianBlur()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.medianBlur()</font> 等。
  • 几何变换: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.resize()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.warpAffine()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.warpPerspective()</font> 等。
  • 颜色空间转换: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.cvtColor()</font>(如 BGR 转灰度、BGR 转 HSV)。
  • 阈值处理: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.threshold()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.adaptiveThreshold()</font>
  • 边缘检测: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.Canny()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.Sobel()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.Laplacian()</font>

应用场景:

  • 图像平滑、锐化、边缘检测。
  • 图像缩放、旋转、仿射变换。
  • 图像二值化、颜色空间转换。

3. HighGUI 模块

功能: 提供高层 GUI 和媒体 I/O 功能,用于图像的显示和交互。

主要类和函数:

  • 图像显示: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.imshow()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.waitKey()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.destroyAllWindows()</font>
  • 视频捕获: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.VideoCapture()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.VideoWriter()</font>
  • 鼠标和键盘事件: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.setMouseCallback()</font>

应用场景:

  • 显示图像和视频。
  • 捕获摄像头或视频文件。
  • 处理用户交互(如鼠标点击、键盘输入)。

4. Video 模块

功能: 提供视频分析功能,包括运动检测、目标跟踪等。

主要类和函数:

  • 背景减除: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.createBackgroundSubtractorMOG2()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.createBackgroundSubtractorKNN()</font>
  • 光流法: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.calcOpticalFlowPyrLK()</font>
  • 目标跟踪: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.TrackerKCF_create()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.TrackerMOSSE_create()</font>

应用场景:

  • 视频中的运动检测。
  • 目标跟踪(如行人、车辆跟踪)。

5. Calib3d 模块

功能: 提供相机校准和 3D 重建功能。

主要类和函数:

  • 相机校准: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.calibrateCamera()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.findChessboardCorners()</font>
  • 3D 重建: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.solvePnP()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.reprojectImageTo3D()</font>

应用场景:

  • 相机标定(用于去除镜头畸变)。
  • 3D 重建(如从 2D 图像恢复 3D 信息)。

6. Features2d 模块

功能: 提供特征检测和描述功能。

主要类和函数:

  • 特征检测: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.SIFT_create()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.ORB_create()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.SURF_create()</font>
  • 特征匹配: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.BFMatcher()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.FlannBasedMatcher()</font>
  • 关键点绘制: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.drawKeypoints()</font>

应用场景:

  • 图像特征提取和匹配。
  • 图像拼接、物体识别。

7. Objdetect 模块

功能: 提供目标检测功能。

主要类和函数:

  • Haar 特征分类器: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.CascadeClassifier()</font>(用于人脸检测)。
  • HOG 特征分类器: 用于行人检测。

应用场景:

  • 人脸检测、行人检测。

8. ML 模块

功能: 提供机器学习算法。

主要类和函数:

  • 支持向量机 (SVM): <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.ml.SVM_create()</font>
  • K 均值聚类 (K-Means): <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.kmeans()</font>
  • 神经网络 (ANN): <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.ml.ANN_MLP_create()</font>

应用场景:

  • 图像分类、聚类分析。

9. DNN 模块

功能: 提供深度学习功能,支持加载和运行预训练的深度学习模型。

主要类和函数:

  • 模型加载: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.dnn.readNetFromCaffe()</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">cv.dnn.readNetFromTensorflow()</font>
  • 前向传播: <font style="color:rgb(51, 51, 51);background-color:rgb(250, 252, 253);">net.forward()</font>

应用场景:

  • 图像分类、目标检测、语义分割。

图像处理

读取

读取 imread(文件)、显示 imshow、等待 waitKey、关闭 destroyAllWindows、保存 imwrite...

opencv 通过 numpy 的多维数组(uint8(0-255)、float32 或其他) 表示图像数据,每个元素对应图像中的一个像素。

图像尺寸:img.shape

颜色通道:RGB 三通道或灰度图单通道

imread 就是返回一个 numpy 数组,如果图像错误或不存在会返回 None

显示

cv.imshow("窗口名",img) # 显示图像

cv.waitKey(0) # 等待按键输入

cv.destroyAllWindows() # 关闭所有窗口

cv.imwrite("图像名",img) # 保存

图像基本操作

访问和修改像素值

python 复制代码
# 像素点
pixel_value=image[100,100] # 获取行为100列为100的像素值
image[100,100]=[255,255,255] # 修改(100,100)位置的像素值为白色

# 范围 ROI region of interest
roi=image[50:150,50:150]
image[50:150,50:150]=[0,255,0]
# 分离rgb通道和合并
b,g,r=cv.split(image)
merged_image=cv.merge([b,g,r])

# 图像缩放、旋转、平移、翻转
resized_image=cv.resize(image,(new_width,new_height)) # 缩放
(h,w)=img.shape[:2]
center=(w//2,h//2)
center_x=w//2
center_y=h//2
rotation_matrix=cv.getRotationMatrix2D((center_x,center_y),angle,scale) # 沿着(center_x,center_y)旋转angle度,同时缩放scale倍
rotated_image=cv.warpAffine(image,rotation_matrix,(width,height)) #旋转
translation_matrix=np.float32([[1,0,平移的x距离],[0,1,平移的y距离]])
translated_image=cv.warpAffine(image,translation_matrix,(width,height)) # 旋转后的图像平移width和height个像素点
flipped_image=cv.flip(image,flip_code) # 翻转,0垂直翻转 1水平翻转 -1双向翻转

# 算数运算
# 可以两个图像相加、相减、相乘、相除混合
result=cv.add(image1,iamge2)
result=cv.subtract(image1,image2)
result=cv.multiply(image1,image2) # 超过255,自动截断为255
result=cv.divide(image1,iamge2)
result=cv.addWeighted(image1,alpha,image2,beta,gamma)  # alpha和beta是权重,gamma是标量,result = img1 * alpha + img2 * beta + gamma

# 也可以进行***与或非***的位运算(可以实现分割、叠加、反色、差异检测的作用)
result=cv.bitwise_and(img1,img2) # 与操作,可以加密图片进行掩码,自己的拿一个图片作为钥匙,也可以图像分割,单独的白色或黑色
result=cv.bitwise_or(img1,img2) # 或操作,图像叠加
result=cv.bitwise_not(img1,img2) # 图像反色,两个not反过来
result=cv.bitwise_xor(img1,img2) # 图像差异检测
# 图像阈值处理(先灰度再阈值、阈值就是超过thresh的为0,高于的变为maxval,跟锐化一样)
ret,thresholded_image=cv.threshold(image,thresh,maxval,cv.THRESH_BINARY) #thresh是阈值,maxval是最大值
# cv.THRESH_BINARY :大于阈值的为maxval,否则为0,素描画
# cv.THRESH_BINARY_INV :大于阈值为0否则为maxval,跟嫌疑剧情一样
# cv.THRESH_TRUNC:大于阈值,等于阈值,否则不变 :调低亮度和对比度
# cv.THRESH_TOZERO:大于阈值不变,否则0:日本无彩漫画,666
# cv.THRESH_TOZERO_INV:大于阈值为0,否则不变:嫌疑剧


# 自适应阈值处理(nb,最厉害的,跟边缘检测一样)
thersholded_iamge=cv.adaptiveThreshold(image,maxval,cv.APAPTIVE_THRESH_MEAN_C,
                                      cv.THRESH_BINARY,block_size,C) #block_size必须为奇数
# cv.ADAPTIVE_THRESH_MEAN_C:阈值是邻域的平均值减去常数C
# cv.ADAPTIVE_THRESH_GAUSSIAN_C:阈值是邻域的加权平均值减去常数C,权重由高斯函数确定

# Otsu's 二值化(比简单阈值处理优化一点)
ret,thresholded_image=cv.threshold(image,125,255,cv.THRESH_BINARY+cv.THRESH_OTSU) #type通常为cv.THRESH_BINARY/THRESH_BINARY_INV+cv.THRESH_OTSU

# 图像平滑处理
blurred_iamge=cv.blur(image,(kernel_size,kernel_size)) # 均值滤波:(5,5)就是均值模糊,在水平和垂直方向取平均值的范围,用于去除噪声,但也会让图像模糊
blurred_image=cv.GaussianBlur(image,(kernel_size,kernel_size),sigmaX) # (5,5),0就是高斯模糊,sigmaX为高斯核的标准差,为0代表自动,用除图像中的高斯噪声,保留图像边缘信息
blurred_image=cv.medianBlur(image,kernel_size) # 中值模糊,5就是中值模糊,kernel_size必须为奇数,去除图像中的椒盐噪声,保留图像边缘信息
blurred_image=cv.bilateralFilter(image,d,sigmaColor,sigmaSpace) # 双边滤波,去除噪声的同时保留图像的边缘信息,常用于图像美化或预处理,去除过曝

# 颜色空间与转换(灰度、HSV、YUV等)
gray_img=cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 灰度
hsv_img=cv.cvtColor(img,cv.COLOR_BGR2HSV) # 热力图
yuv_img=cv.cvtColor(img,cv.COLOR_BGR2YUV) # 特别像夜魂迸发

# 大小调整和裁剪
resized_img=cv.resize(img,(width,height)) # 调整大小
cropped_img=img[y1:y2,x1:x2] # 裁剪

# 图片边缘检测(边缘为白色,其余为黑色)
edges=cv2.Canny(img,100,200) # 边缘检测,大多数场景
sobel_x=cv.Sobel(image,cv.CV_64F,1,0,ksize=5)# Sobel算子,立体的壁画,水平和垂直边缘
sobel_y=cv.Sobel(image,cv.CV_64F,0,1,ksize=5) # 细微的边缘
laplacian=cv.Laplacian(image,cv.CV_64F)#Laplacian 算子,跟墙壁刻画似的,检测边缘和角点

# 形态学:腐蚀、膨胀、开运算、闭运算,用于二值图像处理,将白色区域收缩、扩展、先收缩再扩展、先扩展再收缩
kernel=cv.getStructuringElement(cv.MORPH_RECT,(5,5))
eroded_img=cv.erode(img,kernel,iterations=1) # 收缩,黑色水笔描边+黑色点点水彩画,前景对象变小,边缘被腐蚀掉,用于去除噪声或分离连接的对象
dilated_img=cv.dilate(img,kernel,iterations=1) # 扩展,高糊+白色边,前景对象变大,边缘被扩展,用于填补前景对像中的空洞或连接断裂的对象
opening_img=cv.morphologyEx(img,cv.MORPH_OPEN,kernel) # 去除小物体,模糊+黑色小边,开运算去除图像中的小噪声,同时保留图像中的主要前景对象
closing_img=cv.morphologyEx(img,cv.MORPH_CLOSE,kernel) # 填补小孔洞,白色点点水彩画+亮度提高,填补前景对象中的小孔,同时保留图像中的主要前景对象
gradient_img=cv.morphologyEx(img,cv.MORPH_GRADIENT,kernel) # 提取前景对象的边缘,用于边缘检测

# 轮廓检测
# 检测轮廓:轮廓是具有相同颜色或强度的连续点的曲线
gray_img=cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 灰度
_,threshold_img=cv.threshold(gray_img,127,255,cv.THRESH_BINARY) # 阈值二值化,低于127为0黑色,高于127为255白色, thresh越大越细节,越好看,thresh小的话直接圈住图画了
contours,_=cv.findContours(threshold_img,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) #提取轮廓,输入为经过阈值处理或边缘检测后的图像
# 检测模式mode: cv.RETER_EXTERNAL :只检测最外层轮廓
# 检测模式mode:cv.RETER_LIST:检测所有,但不建立层次关系
# 轮廓近似方法:cv.CHAIN_APPROX_NONE:存储所有轮廓点
# 轮廓近似方法: cv.CHAIN_APPROX_SIMPLE:只保留端点
# 绘制轮廓
cv.drawContours(img,contours,-1,(0,255,0),3) # 原画上绘制轮廓
cv.imshow("contours",img)
# 轮廓计算
cv.contourArea()# 计算轮廓面积
cv.arcLength() #计算轮廓周长/弧长
cv.boundingRect() #计算轮廓的边界矩形
cv.minAreaRect() #计算轮廓最小外接矩形
cv.minEnclosingCircle() #计算轮廓的最小外接圆
cv.approxPolyDP() # 对轮廓进行多边形近似

# 绘制文本
cv2.putTest(image,text文本,org左下角坐标,fontFace字体类型,fontScale文本缩放,color文本颜色,thickness字宽)
#fontFace:cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, 'Hello, OpenCV!', (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)

案例 2:图片的各种操作并播放灰度、轮廓化的视频

python 复制代码
import cv2 as cv
import numpy as np


def get_gray_mp4(video_path):
    cap = cv.VideoCapture(video_path)
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        gray_frame = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        cv.imshow("showimage", gray_frame)
        # 25毫秒延时,相当于40fps,如果按 q 退出就 break
        if cv.waitKey(25) & 0xFF == ord('q'):
            break
    cap.release()
def get_contours_mp4(video_path):
    cap = cv.VideoCapture(video_path)
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        gray_img = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        _, threshold_img = cv.threshold(gray_img, 200, 255, cv.THRESH_BINARY)
        contours, _ = cv.findContours(threshold_img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

        blank = np.zeros_like(frame)  # 黑色背景
        cv.drawContours(blank, contours, -1, (255, 255, 255), 1)

        cv.imshow("showimage", blank)
        if cv.waitKey(25) & 0xFF == ord('q'):  # q 退出
            break
    cap.release()
def get_adaptiveThreshold_mp4(video_path):
    cap = cv.VideoCapture(video_path)
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        gray_img = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        img_resized = cv.adaptiveThreshold(gray_img, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 11, 2)
        cv.imshow("showimage", img_resized)
        if cv.waitKey(25) & 0xFF == ord('q'):  # q 退出
            break
    cap.release()

if __name__ == '__main__':
    img = cv.imread("images/6a23a8c8c6fd94cac2cc0d6d9b959c9b_8768218066985869315.png")
    if img is None:
        print("无法解析图片:",img)
        exit()
    img_resized = cv.resize(img, (1080, 640))
    cv.imshow("showimage", img_resized)
    ori_img=img_resized
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
    while True:
        key=cv.waitKey(0)
        if key==ord("q") or key==27:
            print("退出")
            break
        elif key==ord("w"):
            img_resized=cv.flip(img_resized,-1)
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("e"):
            img_resized=cv.flip(img_resized,0)
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("r"):
            img_resized=cv.flip(img_resized,1)
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("t"):
            img_resized=cv.rotate(img_resized,cv.ROTATE_90_CLOCKWISE)
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("y"):
            img_resized=cv.rotate(img_resized,cv.ROTATE_90_COUNTERCLOCKWISE)
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("u"):
            img_resized=cv.rotate(img_resized,cv.ROTATE_180)
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("h"):
            img_resized=cv.cvtColor(ori_img, cv.COLOR_BGR2GRAY)  # 转灰度
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("i"):
            ret, img_resized = cv.threshold(img_resized, 125, 255, cv.THRESH_BINARY)  # thresh是阈值,maxval是最大值
            cv.imshow("showimage", img_resized)
        elif key==ord("j"):
            img_resized=cv.adaptiveThreshold(img_resized,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,11,2)
            cv.imshow("showimage", img_resized)
        elif key==ord("k"): # Otsu's二值化
            ret, img_resized = cv.threshold(img_resized, 125, 250, cv.THRESH_BINARY+cv.THRESH_OTSU)
            cv.imshow("showimage", img_resized)
        # 滤波
        elif key==ord("f"):
            img_resized=cv.blur(img_resized,(5,5))
            cv.imshow("showimage", img_resized)
        elif key==ord("g"):
            img_resized=cv.medianBlur(img_resized,5)
            cv.imshow("showimage", img_resized)
        elif key==ord("b"):
            img_resized=cv.bilateralFilter(img_resized,9,75,75)
            cv.imshow("showimage", img_resized)
        elif key==ord("n"):# 高斯滤波
            img_resized=cv.GaussianBlur(img_resized,(5,5),0)
            cv.imshow("showimage", img_resized)
        elif key==ord("z"):
            img_resized=cv.cvtColor(ori_img, cv.COLOR_BGR2HSV)  # hsv
            cv.imshow("showimage", img_resized)
        elif key == ord("x"):
            img_resized = cv.cvtColor(ori_img, cv.COLOR_BGR2YUV)  # yuv
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("c"):
            img_resized=cv.Canny(img_resized,100,100)
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("v"):
            img_resized=cv.Laplacian(img_resized,cv.CV_64F)
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("m"):
            img_resized=cv.Sobel(img_resized,cv.CV_64F,1,0,ksize=3)
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("p"):
            img_resized=cv.Sobel(img_resized,cv.CV_64F,0,1,ksize=1)
            cv.imshow("showimage", img_resized)
            continue
        elif key==ord("o"): #形态学
            img_resized=cv.morphologyEx(img_resized,cv.MORPH_OPEN,kernel)
            cv.imshow("showimage", img_resized)
        elif key==ord("l"):
            img_resized=cv.morphologyEx(img_resized,cv.MORPH_CLOSE,kernel)
            cv.imshow("showimage", img_resized)
        elif key==ord("s"):
            img_resized=cv.erode(img_resized,kernel,iterations=1)
            cv.imshow("showimage", img_resized)
        elif key==ord("a"): #dilate
            img_resized=cv.dilate(img_resized,kernel,iterations=1)
            cv.imshow("showimage", img_resized)
        elif key==ord("d"):
            gray_img = cv.cvtColor(ori_img, cv.COLOR_BGR2GRAY)
            _, threshold_img = cv.threshold(gray_img, 190, 255, cv.THRESH_BINARY) # thresh越大越细节,越好看,thresh小的话直接圈住图画了
            contours, _ = cv.findContours(threshold_img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
            img=cv.drawContours(ori_img, contours, -1, (255, 255, 0), 1)
            cv.imshow("showimage", img)
        elif key== 32: # 空格键
            get_adaptiveThreshold_mp4("videos/33708180019-1-192.mp4")
        elif key==13: # 回车
            get_gray_mp4("videos/33708180019-1-192.mp4")
        elif key== 8: # 删除键
            get_contours_mp4("videos/33708180019-1-192.mp4")
        else:
            img_resized=ori_img
            cv.imshow("showimage",img_resized)

    cv.destroyAllWindows()

边缘检测

Candy

  • 噪声抑制:高斯滤波器对图像进行平滑处理,减少噪声的影响
  • 计算梯度:Sobel 算子计算图像的梯度幅值和方向
  • 非极大值抑制:严梯度方向保留局部梯度最大的像素点,抑制其他像素点
  • 双阈值检测:使用两个阈值(低阈值和高阈值)确定真正的边缘,高于高阈值被认为强边缘,低于第阈值被抑制,之间的如果与强边缘相连就被保留
  • 边缘连接:通过滞后阈值处理,将弱边缘和强边缘连接起来,形成完整的边缘

cv.Candy(image,低阈值,高阈值,Sobel 算子孔径大小默3,是否L2范数(默认 False L1))

Sobel 算子

基于梯度的边缘检测算子,通过计算图像在水平和垂直方向上的梯度来检测边缘

因为结合了高斯平滑和微分操作,因此对噪声具有一定的抑制作用

  • 使用 3x3 计算水平和垂直方向的梯度
    • x 方向:<font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">cv2.</font><font style="color:rgb(0, 85, 170);">Sobel</font><font style="color:olive;">(</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">image</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> cv2.</font><font style="color:rgb(0, 85, 170);">CV_64F</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> </font><font style="color:maroon;">1</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> </font><font style="color:maroon;">0</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> ksize</font><font style="color:gray;">=</font><font style="color:maroon;">3</font><font style="color:olive;">)</font>
    • ++y 方向:++ <u><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">cv2.</font></u><u><font style="color:rgb(0, 85, 170);">Sobel</font></u><u><font style="color:olive;">(</font></u><u><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">image</font></u><u><font style="color:gray;">,</font></u><u><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> cv2.</font></u><u><font style="color:rgb(0, 85, 170);">CV_64F</font></u><u><font style="color:gray;">,</font></u><u><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> </font></u><u><font style="color:maroon;">0</font></u><u><font style="color:gray;">,</font></u><u><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> </font></u><u><font style="color:maroon;">1</font></u><u><font style="color:gray;">,</font></u><u><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> ksize</font></u><u><font style="color:gray;">=</font></u><u><font style="color:maroon;">3</font></u><u><font style="color:olive;">)</font></u>
  • 使用两个方向的梯度计算梯度幅值 G=sqrt(Gx^2+Gy^2)
    • <font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">sobel_combined </font><font style="color:gray;">=</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> np.</font><font style="color:rgb(0, 85, 170);">sqrt</font><font style="color:olive;">(</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">sobel_x**</font><font style="color:maroon;">2</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> + sobel_y**</font><font style="color:maroon;">2</font><font style="color:olive;">)</font>
  • 根据梯度幅值展示

<font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">cv2.</font><font style="color:rgb(0, 85, 170);">imshow</font><font style="color:olive;">(</font><font style="color:rgb(170, 17, 17);">'Sobel Combined'</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> sobel_combined</font><font style="color:olive;">)</font>

Laplacian 算子

二阶微分算子,通过计算图像二阶导数检测边缘,对噪声比较敏感,所以需要在使用之前对图像进行高斯平滑处理

卷积核得到的 Laplacian 值较大的区域为边缘

img_resized=cv.Laplacian(img_gray, cv.CV_64F, ksize=9,scale=1,delta=0,borderType=cv.BORDER_DEFAULT)

函数 算法 优点 缺点 适用场景
**<font style="color:rgb(51, 51, 51);">cv2.Canny()</font>** Canny 边缘检测 噪声抑制能力强,边缘检测效果好。 参数调节较为复杂。 通用边缘检测,适合大多数场景。
**<font style="color:rgb(51, 51, 51);">cv2.Sobel()</font>** Sobel 算子 计算简单,适合检测水平和垂直边缘。 对噪声敏感,边缘检测效果一般。 检测水平和垂直边缘。
**<font style="color:rgb(51, 51, 51);">cv2.Scharr()</font>** Scharr 算子 对边缘的响应更强,适合检测细微边缘。 对噪声敏感。 检测细微的边缘。
**<font style="color:rgb(51, 51, 51);">cv2.Laplacian()</font>** Laplacian 算子 可以检测边缘和角点。 对噪声非常敏感。 检测边缘和角点。

轮廓检测

轮廓就是图像中具有相同颜色或强度的连续点的曲线

  • 轮廓: 图像中物体的边界,由一系列点组成。
  • 轮廓层次结构: 轮廓之间的嵌套关系,例如一个轮廓是否包含另一个轮廓。
  • 轮廓特征: 轮廓的面积、周长、边界矩形、最小外接矩形、最小外接圆等。

步骤:

  • 灰度处理:cvtColor/threshold<font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">_</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> binary </font><font style="color:gray;">=</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> cv2.</font><font style="color:rgb(0, 85, 170);">threshold</font><font style="color:olive;">(</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">image</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> </font><font style="color:maroon;">127</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> </font><font style="color:maroon;">255</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> cv2.</font><font style="color:rgb(0, 85, 170);">THRESH_BINARY</font><font style="color:olive;">)</font>
  • 高斯模糊 <font style="background-color:#ffffff;">img_gray=cv.GaussianBlur(ori_img,(5,5),0)</font>
  • 边缘检测<font style="background-color:#ffffff;">cv.Canny(img_gray, 50, 150, apertureSize=3)</font>
  • 查找轮廓:<font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">contours</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> hierarchy </font><font style="color:gray;">=</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">cv2.</font><font style="color:rgb(0, 85, 170);">findContours</font><font style="color:olive;">(</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);">binary</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> cv2.</font><font style="color:rgb(0, 85, 170);">RETR_TREE</font><font style="color:gray;">,</font><font style="color:rgb(0, 0, 0);background-color:rgb(249, 249, 249);"> cv2.</font><font style="color:rgb(0, 85, 170);">CHAIN_APPROX_SIMPLE</font><font style="color:olive;">)</font>
  • 绘制轮廓:纯色背景或者原图绘制
    * -1 代表所有轮廓都绘制,1 代表 thickness 宽度
    * 还可以设置 lineType 线型、hierarchy 轮廓的层次结构信息、maxLevel 绘制的最大层次深度,offset 轮廓点的偏移量
    • output = np.zeros_like(ori_img)
    • cv.drawContours(ori_img, contours, -1, (255, 255, 0), 1)
    • cv.drawContours(output, contours, -1, (255, 255, 0), 1)
  • 展示
    • <font style="color:#080808;background-color:#ffffff;">cv.imshow("showimage2", output)</font>

官方步骤:

  1. 灰度图 cvtColor
  2. 二值化 threshold
  3. 查找轮廓 findContours
  4. 绘制轮廓 drawContours
  5. 计算面积 contourArea
  6. 计算周长 arcLength
  7. 计算边界矩形 boundingRect
  8. 最小外接矩形 minAreaRect
  9. 最小外接圆 minEnclosingCircle
  10. 多边形逼近 approxPolyDP
函数名称 功能描述
<font style="color:rgb(51, 51, 51);">cv2.findContours(图片,检索模式,近似方法,轮廓列表,层次结构,偏移量)</font> 查找图像中的轮廓
<font style="color:rgb(51, 51, 51);">cv2.drawContours(底图,轮廓集,索引,颜色,厚度,线型,层次结构,最大层次深度,偏移量)</font> 在图像上绘制轮廓
<font style="color:rgb(51, 51, 51);">cv2.contourArea(轮廓集,是否返回符号)</font> 计算轮廓的面积
<font style="color:rgb(51, 51, 51);">cv2.arcLength(轮廓集,是否闭合)</font> 计算轮廓的周长或弧长
<font style="color:rgb(51, 51, 51);">cv2.boundingRect(轮廓集)</font> 计算轮廓的边界矩形
<font style="color:rgb(51, 51, 51);">cv2.minAreaRect(轮廓集)</font> 计算轮廓的最小外接矩形
<font style="color:rgb(51, 51, 51);">cv2.minEnclosingCircle(轮廓集)</font> 计算轮廓的最小外接圆
<font style="color:rgb(51, 51, 51);">cv2.approxPolyDP(轮廓集,近似精度,是否闭合)</font> 对轮廓进行多边形近似
plain 复制代码
img_gray = cv.cvtColor(ori_img, cv.COLOR_BGR2GRAY)
img_gray=cv.GaussianBlur(ori_img,(5,5),0)
# img_resized=cv.Laplacian(img_gray, cv.CV_64F, ksize=9,scale=1,delta=0,borderType=cv.BORDER_DEFAULT)
img_resized=cv.Canny(img_gray, 50, 150, apertureSize=3)
contours,img_resized=cv.findContours(img_resized, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
output = np.zeros_like(ori_img)
cv.drawContours(ori_img, contours, -1, (255, 255, 0), 1)
cv.drawContours(output, contours, -1, (255, 255, 0), 1)
cv.imshow("showimage", ori_img)
cv.imshow("showimage2", output)

人脸追踪

pip install --upgrade opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple

不行的话下载一个:haarcascade_frontalface_default.xml

python 复制代码
def get_HOG_mp4(video_path):
    
    if hasattr(cv, 'data'):
        xml_path = cv.data.haarcascades + "haarcascade_frontalface_default.xml"
    else:
        xml_path = "test.xml"
    face_cascade=cv.CascadeClassifier(xml_path)
    cap=cv.VideoCapture(video_path)
    while True:
        ret, frame = cap.read()

        if not ret:
            break

        # 将帧转换为灰度图像
        gray_frame = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)

        # 检测人脸
        faces = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

        # 在帧上绘制矩形框标记人脸
        for (x, y, w, h) in faces:
            cv.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)

        # 显示带有人脸标记的帧
        cv.imshow('Face Detection', frame)

        if cv.waitKey(25) & 0xFF == ord('q'):
            break

    cap.release()
    cv.destroyAllWindows()

图像直方图

了解图像的像素分布情况,进行图像增强、对比度调整、图像分割等操作

是图像像素强度分布的图形表示,灰度为 0-255 在图像中的频率,彩色是每个通道的直方图

可以看出:如果直方图集中在低灰度区域,说明图像偏暗;分布均匀说明对比度较好

cv.calcHist(images)

  • images:
功能 函数 说明
计算直方图 <font style="color:rgb(51, 51, 51);">cv2.calcHist(输入的图像列表,灰色[0]彩色[0蓝/1绿/2红],掩码,bin数量,通常[256],像素值范围 [0,256],输出的直方图数组,是否累积直方图)</font> 计算图像的直方图。
直方图均衡化 <font style="color:rgb(51, 51, 51);">cv2.equalizeHist(images)</font> 增强图像的对比度。
直方图比较 <font style="color:rgb(51, 51, 51);">cv2.compareHist(hist1,hist2,比较方法 cv.HISTCMP_CORREL)</font> 比较两个直方图的相似度。
绘制直方图 <font style="color:rgb(51, 51, 51);">matplotlib.pyplot.plot()</font> 使用 Matplotlib 绘制直方图。
python 复制代码
import matplotlib.pyplot as plt
# matplotlib设置中文显示
plt.rcParams['font.sans-serif'] = ["STFangsong"]  # ttf后缀
# plt.rcParams['font.sans-serif'] = ["STHeiti"]  # ttf后缀
# plt.rcParams['font.sans-serif'] = ["Hei"]  # ttf后缀
plt.rcParams['axes.unicode_minus'] = False
# .....
elif key==ord("t"):
    img=cv.cvtColor(img_resized,cv.COLOR_BGR2GRAY)
    hist1 = cv.calcHist([img], [0], None, [256], [0, 256])

    # 绘制直方图
    plt.figure(figsize=(10, 4))
    plt.subplot(1, 2, 1)
    plt.plot(hist1)
    plt.title('Grayscale Histogram')
    plt.xlabel('Pixel Value')
    plt.ylabel('Frequency')
    # 均衡化
    img_resized = cv.equalizeHist(img)
    cv.imshow("equalizeHist", img_resized)
    cv.imshow("img", img)
    hist2 = cv.calcHist([img_resized], [0], None, [256], [0, 256])
    # 绘制直方图
    similarity=cv.compareHist(hist1,hist2,cv.HISTCMP_CORREL)
    print("直方图相似度:",similarity)
    plt.subplot(1, 2, 2)
    plt.plot(hist2)
    plt.title('均衡化后的')
    plt.xlabel('强度')
    plt.ylabel('像素个数')
    plt.tight_layout()
    plt.show()
elif key==ord("y"):
    b,g,r=cv.split(ori_img)
    # 每个色相单独equalize
    b_eq=cv.equalizeHist(b)
    g_eq=cv.equalizeHist(g)
    r_eq=cv.equalizeHist(r)
    equalized_image=cv.merge([b_eq,g_eq,r_eq])
    cv.imshow("equalized_image",equalized_image)
    cv.imshow("ori_img",ori_img)
    plt.figure(figsize=(10,4))
    plt.subplot(1, 2, 1)
    color = ('b', 'g', 'r')
    # 每个色相单独calHist
    for i, col in enumerate(color):
        hist = cv.calcHist([ori_img], [i], None, [256], [0, 256])
        plt.plot(hist, color=col)
    plt.title("图像直方图")
    plt.xlabel("强度")
    plt.ylabel("像素个数")
    plt.subplot(1, 2, 2)
    for i, col in enumerate(color):
        hist = cv.calcHist([equalized_image], [i], None, [256], [0, 256])
        plt.plot(hist, color=col)
    plt.tight_layout()
    plt.show()

直方图均衡化

增强图像对比度的方法,通过重新分配像素强度值,使直方图更加均匀

q

matplotlib 中文

只有 ttf 文件后缀才可以

mac

设置打开字体
  • 打开访达后菜单栏点击前往-电脑-mac-系统-资源库-Fonts
  • 打开访达后 shift+command+c-mac-系统-资源库-Fonts


进入字体库
  • Fonts 选择一个字体后 - 单击跳过 - 进入所有字体 - 简体中文 - 右击选择验证
  • 查找 TrueType 类型+ ttf 文件后缀,并复制名称(得试,可能是文件名),在 matplotlib 里面测试


python 复制代码
plt.rcParams['font.sans-serif'] = ["STFangsong"]  # ttf后缀
plt.rcParams['font.sans-serif'] = ["STHeiti"]  # ttf后缀
plt.rcParams['font.sans-serif'] = ["Hei"]  # ttf后缀
plt.rcParams['axes.unicode_minus'] = False

视频处理

常见视频处理+摄像头

视频处理包括:视频读取 VideoCapture - 播放 read+imshow - 帧处理 - 保存 VideoWriter

帧处理:

  • 视频分析:通过视频处理技术,分析视频中的运动、目标、事件等
  • 视频增强:对视频进行去躁、增强、稳定化等处理,提升视频质量
  • 视频编辑:对视频进行剪辑、拼接、添加特效等操作
  • 实时监控:通过摄像头实时监控场景,并进行目标检测、行为分析等

查看摄像头:只需将参数设置为摄像头索引(通常为 0)<font style="color:#080808;background-color:#ffffff;">cap=cv.VideoCapture(0)</font>

python 复制代码
def get_Camera_mp4():
    cap=cv.VideoCapture(0)
    if not cap.isOpened():
        print("无法打开摄像头")
        exit()
    while True:
        ret, frame = cap.read()
        if not ret:
            print("无法获取视频帧")
            break
        cv.imshow("Camera", frame)
        if cv.waitKey(25) & 0xFF == ord('q'):
            break
    cap.release()
    cv.destroyAllWindows()

添加声音

给视频添加声音

  • ffmpeg(命令行)
  • moviepy(python)
python 复制代码
    # 读取无声视频(OpenCV生成的)
    video = moviepy.VideoFileClip(file_name+"adaptiveThreshold"+".mp4")
    # 从原视频提取音频
    audio = moviepy.VideoFileClip(file_name+".mp4").audio
    # 添加音频
    video.write_videofile(file_name+"adaptiveThreshold_video_noaudio.mp4", audio=audio)

边缘检测+合成声音+导出视频

帧的保存需要 VideoWriter(导出路径,fourcc视频编码器,fps帧率,frameSize 窗口大小)

  • fourcc 视频编码器输入ffmpeg -codecs | grep -i video查看是否支持
  • fps、窗口大小

通过 int(cap.get(cv.CAP_PROP_FPS/CAP_PROP_FRAME_WIDTH/CAP_PROP_FRAME_HEIGHT))

plain 复制代码
fps = int(cap.get(cv.CAP_PROP_FPS))
width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
字符串 (fourcc) 编码/作用 输出格式例子
<font style="color:rgb(0, 0, 0);">XVID</font> Xvid MPEG-4 <font style="color:rgb(0, 0, 0);">.avi</font>
<font style="color:rgb(0, 0, 0);">MJPG</font> Motion-JPEG <font style="color:rgb(0, 0, 0);">.avi</font> (每帧独立JPEG)
<font style="color:rgb(0, 0, 0);">MP4V</font> MPEG-4 <font style="color:rgb(0, 0, 0);">.mp4</font><font style="color:rgb(0, 0, 0);">.avi</font>
<font style="color:rgb(0, 0, 0);">H264</font>/ <font style="color:rgb(0, 0, 0);">X264</font> H.264 (AVC) <font style="color:rgb(0, 0, 0);">.mp4</font>
<font style="color:rgb(0, 0, 0);">DIVX</font> DivX MPEG-4 <font style="color:rgb(0, 0, 0);">.avi</font>
<font style="color:rgb(0, 0, 0);">avc1</font> H.264,另一种fourcc写法 <font style="color:rgb(0, 0, 0);">.mp4</font>
<font style="color:rgb(0, 0, 0);">WMV1</font>/ <font style="color:rgb(0, 0, 0);">WMV2</font> Windows Media Video <font style="color:rgb(0, 0, 0);">.wmv</font>
python 复制代码
def merge_video(processed_video="videos/33708180019-1-192adaptiveThreshold.mp4",
                original_video="videos/33708180019-1-192.mp4",
                output_video="videos/33708180019-1-192adaptiveThreshold_with_audio.mp4"):
    cmd = [
        "ffmpeg", "-y",
        "-i", processed_video,
        "-i", original_video,
        "-c", "copy",
        "-map", "0:v:0",
        "-map", "1:a:0",
        output_video
    ]
    subprocess.run(cmd, check=True)
    print("✅ 合并完成,必有音轨")
def get_adaptiveThreshold_mp4(video_path):
    cap = cv.VideoCapture(video_path)
    fps = int(cap.get(cv.CAP_PROP_FPS))
    width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
    file_name=video_path.split(".")[0]+"adaptiveThreshold.mp4"
    fourcc = cv.VideoWriter_fourcc(*'mp4v')
    out=cv.VideoWriter(file_name,fourcc, fps, (width, height))
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        gray_img = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        gray_blur = cv.GaussianBlur(gray_img, (5, 5), 0)# ksize必须是奇数,否则报错
        img_resized = cv.adaptiveThreshold(gray_blur, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 11, 2)
        out.write(cv.cvtColor(img_resized, cv.COLOR_GRAY2BGR)) # write要求三通道,所以需要转为BGR
        cv.imshow("showimage", img_resized)
        if cv.waitKey(25) & 0xFF == ord('q'):  # q 退出
            break
    # 需要先release然后保存
    cap.release()
    out.release()
    print("生成边缘检测文件成功")
    merge_video(output_video="videos/adaptiveThreshold_audio.mp4",original_video=video_path,processed_video=file_name)
    print("保存有音频的边缘检测文件成功完成")
    cv.destroyAllWindows()

视频目标追踪

相关推荐
环黄金线HHJX.几秒前
拼音字母量子编程PQLAiQt架构”这一概念。结合上下文《QuantumTuan ⇆ QT:Qt》
开发语言·人工智能·qt·编辑器·量子计算
sonadorje6 分钟前
谈谈贝叶斯回归
人工智能·数据挖掘·回归
Python极客之家6 分钟前
基于深度学习的刑事案件智能分类系统
人工智能·python·深度学习·机器学习·数据挖掘·毕业设计·情感分析
工藤学编程9 分钟前
零基础学AI大模型之CoT思维链和ReAct推理行动
前端·人工智能·react.js
MARS_AI_9 分钟前
融资加持下的云蝠智能:大模型语音Agent重构企业通信新生态
人工智能·自然语言处理·重构·交互·信息与通信·agi
一棵开花的树,枝芽无限靠近你12 分钟前
【Pytorch】(一)使用 PyTorch 进行深度学习:60 分钟速成
人工智能·pytorch·深度学习
墨染天姬14 分钟前
【AI】OCR开源模型排行
人工智能·开源·ocr
幻云201014 分钟前
Python机器学习:从入门到资深
人工智能·python
泰迪智能科技17 分钟前
分享|企业数据挖掘平台产品功能
人工智能·数据挖掘
奔波霸的伶俐虫18 分钟前
windows docker desktop 安装修改镜像学习
学习·docker·容器