news 2026/4/18 18:47:54

OpenCV 学习:从光流跟踪到艺术风格迁移

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenCV 学习:从光流跟踪到艺术风格迁移

文章目录

    • 一、光流法运动轨迹跟踪
      • 关键技术分析
    • 二、基于深度学习的艺术风格迁移
      • blobFromImage函数详解
    • 三、实时目标跟踪
      • 跟踪器工作流程
    • 四、多风格实时艺术滤镜
      • 多线程优化策略
      • 性能优化技巧

一、光流法运动轨迹跟踪

光流法是一种通过分析连续帧之间的像素变化来追踪物体运动轨迹的技术。下面的代码展示了如何使用Shi-Tomasi角点检测和Lucas-Kanade光流法实现运动跟踪:

importcv2importnumpyasnp# 读取视频文件cap=cv2.VideoCapture('test.avi')# Shi-Tomasi角点检测参数配置feature_params=dict(maxCorners=100,# 设置检测的最大角点数量qualityLevel=0.3,# 角点质量阈值,值越小检测到的角点越多minDistance=7# 角点间的最小像素距离,避免角点过于密集)# Lucas-Kanade光流法参数配置lk_params=dict(winSize=(15,15),# 搜索窗口大小,较大的窗口能处理更大的运动maxLevel=2# 金字塔层数,用于处理不同尺度下的运动)# 生成随机颜色用于绘制不同轨迹color=np.random.randint(0,255,(100,3))# 读取视频第一帧并转换为灰度图ret,old_frame=cap.read()old_gray=cv2.cvtColor(old_frame,cv2.COLOR_BGR2GRAY)# 检测初始角点作为跟踪起点p0=cv2.goodFeaturesToTrack(old_gray,mask=None,**feature_params)# 创建与视频帧大小相同的黑色画布,用于绘制轨迹mask=np.zeros_like(old_frame)# 主循环:逐帧处理视频whileTrue:ret,frame=cap.read()ifnotret:break# 当前帧转换为灰度图frame_gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)# 计算光流:追踪p0点在当前帧中的新位置p1,st,err=cv2.calcOpticalFlowPyrLK(old_gray,frame_gray,p0,None,**lk_params)# 筛选跟踪成功的点(状态为1表示跟踪成功)good_new=p1[st==1]good_old=p0[st==1]# 绘制运动轨迹fori,(new,old)inenumerate(zip(good_new,good_old)):a,b=new.ravel()# 当前帧中的点坐标c,d=old.ravel()# 上一帧中的点坐标a,b,c,d=int(a),int(b),int(c),int(d)# 在掩模上绘制连接线,显示运动路径mask=cv2.line(mask,(a,b),(c,d),color[i].tolist(),2)# 在当前帧上标记角点位置cv2.circle(frame,(a,b),5,color[i].tolist(),-1)# 将轨迹叠加到当前帧上img=cv2.add(frame,mask)# 显示结果cv2.imshow('frame',img)# 更新前一帧数据和特征点old_gray=frame_gray.copy()p0=good_new.reshape(-1,1,2)# 检测ESC键退出k=cv2.waitKey(150)ifk==27:break# 释放资源cap.release()cv2.destroyAllWindows()

关键技术分析

Shi-Tomasi角点检测

  • maxCorners:控制检测角点的最大数量,平衡精度和性能
  • qualityLevel:决定角点质量的阈值,值越小检测越敏感
  • minDistance:确保角点分布均匀,避免聚集

Lucas-Kanade光流法

  • winSize:搜索窗口大小,影响运动检测的敏感度
  • maxLevel:图像金字塔层数,用于处理多尺度运动

二、基于深度学习的艺术风格迁移

OpenCV的dnn模块支持加载预训练的深度学习模型,实现艺术风格转换:

importcv2# 读取并调整输入图像大小image=cv2.imread(r"picture_1.jpg")image=cv2.resize(image,None,fx=0.5,fy=0.5)# 显示原始图像cv2.imshow('yuan tu',image)cv2.waitKey(0)# 获取图像尺寸(h,w)=image.shape[:2]# 图像预处理:创建神经网络输入格式blob=cv2.dnn.blobFromImage(image,# 输入图像scalefactor=1,# 像素值缩放因子size=(w,h),# 输出blob的尺寸mean=(0,0,0),# 各通道的均值(不进行均值减法)swapRB=False,# 不交换R和B通道(OpenCV使用BGR格式)crop=False# 不进行裁剪)# 加载预训练的艺术风格模型# 支持多种框架格式:Caffe、TensorFlow、PyTorch、Darknet等net=cv2.dnn.readNet(r'model\starry_night.t7')# PyTorch格式的星空风格模型# 设置网络输入net.setInput(blob)# 前向传播:获得风格化输出out=net.forward()# 输出数据处理:四维转三维out_new=out.reshape(out.shape[1],out.shape[2],out.shape[3])# 数据归一化到[0,1]范围cv2.normalize(out_new,out_new,norm_type=cv2.NORM_MINMAX)# 调整维度顺序:CHW → HWCresult=out_new.transpose(1,2,0)# 显示风格化结果cv2.imshow('Stylized Image',result)cv2.waitKey(0)cv2.destroyAllWindows()

blobFromImage函数详解

cv2.dnn.blobFromImage()是将图像转换为神经网络输入格式的关键函数:

  • scalefactor:每个像素值的缩放倍数,常用于数据归一化
  • size:指定输出blob的宽度和高度,通常与网络输入层匹配
  • mean:各通道的均值,用于均值减法(数据标准化)
  • swapRB:OpenCV使用BGR格式,而大多数模型使用RGB,此参数控制是否交换通道
  • crop:是否在调整大小后进行中心裁剪

三、实时目标跟踪

OpenCV提供多种跟踪算法,CSRT跟踪器在准确性和速度之间取得良好平衡:

importcv2# 创建CSRT跟踪器实例tracker=cv2.TrackerCSRT_create()# 跟踪状态标志tracking=False# 打开摄像头cap=cv2.VideoCapture(0)whileTrue:# 读取摄像头帧ret,frame=cap.read()ifnotret:break# 按下's'键开始跟踪,选择ROI区域ifcv2.waitKey(1)==ord('s'):tracking=True# 交互式选择跟踪区域roi=cv2.selectROI('Tracking',frame,showCrosshair=False)# 初始化跟踪器tracker.init(frame,roi)# 如果正在跟踪,更新跟踪器位置iftracking:success,box=tracker.update(frame)ifsuccess:# 提取边界框坐标x,y,w,h=[int(v)forvinbox]# 绘制跟踪框cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)# 显示跟踪结果cv2.imshow('Tracking',frame)# 按下ESC键退出ifcv2.waitKey(1)==27:break# 释放资源cap.release()cv2.destroyAllWindows()

跟踪器工作流程

  1. 初始化阶段:用户通过鼠标选择感兴趣区域(ROI)
  2. 跟踪阶段:跟踪器根据目标的纹理、颜色等特征在后续帧中定位目标
  3. 更新阶段tracker.update()返回跟踪状态和边界框坐标

四、多风格实时艺术滤镜

将摄像头画面分割为四个区域,分别应用不同的艺术风格:

importcv2importnumpyasnpimportthreadingfromqueueimportQueue# 加载四种不同的艺术风格模型defload_models():models=[cv2.dnn.readNet(r'model\starry_night.t7'),# 梵高星空风格cv2.dnn.readNet(r'model\candy.t7'),# 糖果风格cv2.dnn.readNet(r'model\composition_vii.t7'),# 康定斯基风格cv2.dnn.readNet(r'model\la_muse.t7')# 缪斯风格]returnmodels# 对单个图像块应用风格迁移defapply_style(image_block,model):(h,w)=image_block.shape[:2]# 图像预处理blob=cv2.dnn.blobFromImage(image_block,scalefactor=1.0,size=(w,h),mean=(0,0,0),swapRB=False,crop=False)# 模型推理model.setInput(blob)out=model.forward()# 后处理out_new=out.reshape(out.shape[1],out.shape[2],out.shape[3])cv2.normalize(out_new,out_new,norm_type=cv2.NORM_MINMAX)result=out_new.transpose(1,2,0)result=np.uint8(result*255)# 转换为8位图像returnresult# 并行处理器类:使用多线程加速处理classStyleProcessor:def__init__(self,models):self.models=models self.results=[None]*4defprocess_block(self,block_idx,block,model):result=apply_style(block,model)self.results[block_idx]=resultdefprocess_all_blocks(self,blocks):threads=[]foriinrange(4):# 为每个区域创建独立线程thread=threading.Thread(target=self.process_block,args=(i,blocks[i],self.models[i]))threads.append(thread)thread.start()# 等待所有线程完成forthreadinthreads:thread.join()returnself.results# 主函数(优化版本)defmain_optimized():# 初始化模型和处理器models=load_models()processor=StyleProcessor(models)# 设置摄像头cap=cv2.VideoCapture(0)cap.set(cv2.CAP_PROP_FRAME_WIDTH,640)cap.set(cv2.CAP_PROP_FRAME_HEIGHT,480)print("按ESC键退出程序...")whileTrue:ret,frame=cap.read()ifnotret:break# 统一图像尺寸frame=cv2.resize(frame,(640,480))height,width=frame.shape[:2]# 计算分割点mid_h,mid_w=height//2,width//2# 将画面分割为四个区域blocks=[frame[0:mid_h,0:mid_w],# 左上区域frame[0:mid_h,mid_w:width],# 右上区域frame[mid_h:height,0:mid_w],# 左下区域frame[mid_h:height,mid_w:width]# 右下区域]# 并行处理四个区域styled_blocks=processor.process_all_blocks(blocks)# 创建输出画布output_frame=np.zeros_like(frame)# 拼接处理后的区域output_frame[0:mid_h,0:mid_w]=styled_blocks[0]output_frame[0:mid_h,mid_w:width]=styled_blocks[1]output_frame[mid_h:height,0:mid_w]=styled_blocks[2]output_frame[mid_h:height,mid_w:width]=styled_blocks[3]# 绘制区域分割线cv2.line(output_frame,(mid_w,0),(mid_w,height),(255,255,255),2)cv2.line(output_frame,(0,mid_h),(width,mid_h),(255,255,255),2)# 显示多风格画面cv2.imshow('Multi-Style Camera View',output_frame)ifcv2.waitKey(1)&0xFF==27:break# 清理资源cap.release()cv2.destroyAllWindows()if__name__=="__main__":main_optimized()

多线程优化策略

  1. 区域分割:将摄像头画面均匀分为四个独立区域
  2. 并行处理:每个区域使用独立线程应用不同的风格模型
  3. 结果拼接:将处理后的区域重新组合为完整画面

性能优化技巧

  • 降低分辨率:减小处理数据量,提高实时性
  • 多线程处理:充分利用多核CPU并行计算
  • 模型选择:选择轻量级模型或优化模型大小
  • 帧率控制:可适当降低处理帧率,平衡质量和速度

这些代码示例展示了OpenCV在计算机视觉领域的多样化应用,从传统的运动跟踪到基于深度学习的艺术创作,体现了计算机视觉技术的强大功能和广泛应用前景。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 8:41:49

CCMusic音乐风格分类:5分钟搭建你的AI音乐分析平台

CCMusic音乐风格分类:5分钟搭建你的AI音乐分析平台 1. 这不是传统音频分析,而是一次“听觉转视觉”的实验 你有没有想过,让AI“看见”音乐? 不是靠提取MFCC、零交叉率这些抽象数字,而是把一段旋律真正变成一张图——…

作者头像 李华
网站建设 2026/4/18 18:25:27

零基础玩转AI绘画:Z-Image-Turbo极速创作室保姆级使用指南

零基础玩转AI绘画:Z-Image-Turbo极速创作室保姆级使用指南 1. 为什么你不需要懂代码,也能秒出电影级高清图? 你有没有过这样的经历: 想给新项目做个概念图,翻遍图库找不到合适的; 想为朋友圈配一张独一无…

作者头像 李华
网站建设 2026/4/17 19:54:48

离线环境怎么用?Qwen3-0.6B本地化部署指南

离线环境怎么用?Qwen3-0.6B本地化部署指南 你不需要联网、不依赖云服务、不配置复杂API密钥——只要一台能跑GPU的机器,就能把Qwen3-0.6B稳稳装进本地环境,真正实现“开箱即用”的大模型体验。 本文不是讲“如何在云端调用API”,而…

作者头像 李华
网站建设 2026/4/18 4:56:47

虚拟串口创建全过程详解:系统级驱动工作模式解析

以下是对您提供的博文《虚拟串口创建全过程详解:系统级驱动工作模式解析》的 深度润色与结构重构版本 。本次优化严格遵循您的全部要求: ✅ 彻底去除AI痕迹,语言自然、专业、有“人味”——像一位十年嵌入式驱动老手在技术博客里娓娓道来; ✅ 打破模板化章节标题(如“…

作者头像 李华
网站建设 2026/4/19 1:25:07

Qwen3-32B GPU算力优化:Clawdbot网关层KV Cache复用与推理加速实践

Qwen3-32B GPU算力优化:Clawdbot网关层KV Cache复用与推理加速实践 1. 为什么需要在网关层做KV Cache复用? 你有没有遇到过这样的情况:同一个用户连续发几条消息,比如“帮我写一封邮件”“改成正式一点的语气”“再加个落款”&a…

作者头像 李华
网站建设 2026/4/18 7:56:20

开源大模型部署新选择:BAAI/bge-m3 CPU高效运行实操

开源大模型部署新选择:BAAI/bge-m3 CPU高效运行实操 1. 为什么你需要一个“能跑在CPU上”的语义理解引擎? 你有没有遇到过这样的场景: 想快速验证一段中文文案和另一段英文产品描述是否语义一致,却卡在模型太大、显存不够、部署…

作者头像 李华