ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

OpenCV与Python图像处理实战:从像素获取到视频帧分析

OpenCV与Python图像处理实战:从像素获取到视频帧分析 1. 项目概述与核心需求解析看到“2019研究生数学建模C题--图片像素获取与视频帧处理”这个标题很多刚接触图像处理的朋友可能会觉得有点发怵感觉又是数学又是编程的门槛不低。但别担心这个题目本质上是一个绝佳的“练手”项目它把图像处理领域里最核心、最基础的两个操作——静态图片的像素级操作和动态视频的逐帧分析——打包在了一起。我当年带学生做类似项目时发现很多人卡壳的地方不在于算法多复杂而在于没理清从“拿到一堆图片和视频”到“输出分析结果”这个完整流程里每一步到底在干什么、为什么要这么干。简单来说这个题目希望你完成两件事一是能从单张图片里精确地“读出”每一个像素点的信息比如颜色、亮度、位置并可能基于这些信息进行一些计算或统计二是能对一个视频文件进行“拆解”把它变成一帧一帧的静态图片然后对每一帧进行类似的处理最后可能还需要把处理后的帧再合成回视频。这听起来像是电影特效或监控分析的基础工作没错其核心思想在安防、医学影像、工业质检等领域都有广泛应用。适合谁来参考这篇内容呢如果你是正在备战数模的研究生这篇能帮你快速搭建技术框架避开初期配置的坑如果你是刚学Python或OpenCV的本科生想找个有明确目标的实战项目这里面的每一步操作都值得亲手敲一遍哪怕你只是个对“电脑怎么认识图片”感到好奇的爱好者跟着走一遍流程也能对数字图像有个直观的理解。咱们不搞虚的直接上干货从环境搭建到代码实现把每个环节的“为什么”和“怎么办”都讲清楚。2. 核心工具选型与环境搭建思路工欲善其事必先利其器。面对图像处理任务工具选型直接决定了后续开发的效率和天花板。题目没有限定语言但从热词“OpenCV, Python”的高频出现以及当前社区生态来看Python OpenCV组合几乎是毋庸置疑的首选。这里我详细拆解一下为什么这么选以及如何搭建一个稳定、高效的工作环境。2.1 为什么是Python和OpenCV首先说Python。它语法简洁像img.shape、img[i,j]这样的操作非常直观接近于我们描述“图片的高度、宽度”和“第i行第j列的像素”的自然语言极大降低了学习成本。更重要的是其庞大的生态系统NumPy库让像素矩阵运算变得和操作普通数组一样简单高效Matplotlib能方便地可视化处理前后的图片对比Pandas可以轻松整理分析出的统计数据。对于数学建模而言快速实现算法原型、进行数据探索和可视化是关键Python在这些方面优势明显。然后是OpenCVOpen Source Computer Vision Library。它是一个专为计算机视觉设计的开源库功能极其强大且全面。对于这个题目我们主要用到它的两大核心功能图片/视频的IO操作一行代码cv2.imread()就能读取上百种格式的图片cv2.VideoCapture()能优雅地打开视频文件并逐帧读取完全不用自己写复杂的文件解析。基础的像素与图像处理获取图像尺寸(.shape)、访问和修改任意像素值、色彩空间转换如BGR转灰度图、图像缩放、旋转、以及更高级的滤波、边缘检测等。它用C优化了底层通过Python接口调用速度有保障。可能有同学会问看到热词里有“matlab图像处理大作业”Matlab不行吗当然可以Matlab的图像处理工具箱也很强大尤其适合做算法仿真和理论研究。但在数模这种短时间、需要快速集成和输出的场景下Python的开源免费、丰富的社区资源遇到问题搜索引擎一搜一大把解决方案以及后续更容易与Web应用或其他系统集成的潜力使其更具吸引力。而且掌握PythonOpenCV这套技能对你未来的科研或就业都更有普适性。2.2 搭建无痛开发环境环境配置是新手的第一道拦路虎经常卡在“ModuleNotFoundError: No module named opencv”这种错误上。下面我提供两种最稳妥的方案请根据你的网络情况选择。方案一使用Anaconda强烈推荐尤其对新手和网络环境复杂的用户Anaconda是一个集成的Python数据科学平台它最大的好处是管理包依赖和环境非常方便能避免不同项目间包版本冲突的问题。安装Anaconda去其官网下载对应你操作系统Windows/macOS/Linux的安装包。安装时注意勾选“Add Anaconda to my PATH environment variable”将Anaconda添加到系统路径这样才可以在命令行直接使用。创建独立环境打开命令行Windows用Anaconda PromptmacOS/Linux用终端执行以下命令创建一个名为cv_project的新环境并指定Python版本3.8是一个兼容性很好的版本conda create -n cv_project python3.8激活环境并安装包conda activate cv_project pip install opencv-python numpy matplotlib这里我建议用pip install而不是conda install来安装OpenCV因为conda通道的版本有时更新不及时。opencv-python这个包包含了OpenCV的主模块。numpy和matplotlib是必装的搭档。方案二使用原生Python pip安装如果你系统里已经有一个干净的Python环境3.6以上或者喜欢更轻量的配置可以直接用pip。确保pip已更新在命令行输入python -m pip install --upgrade pip。安装核心包pip install opencv-python numpy matplotlib注意如果下载速度慢或超时这是因为默认的pip源在国外。可以永久或临时切换为国内镜像源这是提速的关键。例如使用清华源进行安装pip install opencv-python numpy matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple验证安装安装完成后写一个最简单的脚本验证。import cv2 import numpy as np print(fOpenCV版本: {cv2.__version__}) print(fNumPy版本: {np.__version__}) # 尝试创建一个全黑的图片一个100x100像素3通道的零矩阵 img np.zeros((100, 100, 3), dtypenp.uint8) print(f图片形状高度, 宽度, 通道数: {img.shape})运行这个脚本如果没有报错并正确输出版本和形状信息恭喜你环境搭建成功2.3 编辑器选择VSCode的便捷配置写代码需要一个顺手的编辑器。VSCodeVisual Studio Code轻量、免费、插件丰富是很多人的选择。针对我们的Python图像处理项目建议安装以下插件以提升效率Python微软官方出品提供代码补全、调试、语法高亮等核心功能。Jupyter如果你喜欢以笔记本Notebook的形式分块运行和调试代码这个插件必不可少。对于探索性数据分析非常友好。Code Runner可以一键运行当前Python文件。配置Python解释器在VSCode中按F1输入“Python: Select Interpreter”选择我们刚才用conda创建的cv_project环境或者你系统安装Python的路径。这样就能确保代码运行在正确的环境下。3. 静态图片像素获取的深度解析与实操图片在计算机眼里就是一个巨大的数字矩阵。获取像素就是学会如何“阅读”这个矩阵。这部分是视频处理的基础务必打牢。3.1 理解数字图像的矩阵本质一张最常见的彩色图片如JPG、PNG在OpenCV中被读取后会以一个NumPy数组的形式存在。这里有一个关键点OpenCV默认使用BGR颜色通道顺序而不是我们更熟悉的RGB。这一点在显示和操作时要时刻牢记。假设我们有一张名为sample.jpg的图片。import cv2 import numpy as np # 读取图片。第二个参数是标志位常用 cv2.IMREAD_COLOR彩色默认或 cv2.IMREAD_GRAYSCALE灰度 img_bgr cv2.imread(sample.jpg) # 读取为BGR格式 print(f图像类型: {type(img_bgr)}) # 输出: class numpy.ndarray print(f图像形状: {img_bgr.shape}) # 输出: (高度, 宽度, 通道数)例如 (480, 640, 3)shape属性的三个值分别代表图像的高度行数、宽度列数、颜色通道数3代表BGR三通道。这个矩阵img_bgr中每一个元素img_bgr[i, j, k]就代表了第i行、第j列像素点在第k个颜色通道上的强度值范围通常是0-2558位无符号整数。3.2 像素的访问、修改与批量操作单像素访问与修改# 获取(100, 50)坐标处的像素值B, G, R px_bgr img_bgr[100, 50] print(fBGR值: {px_bgr}) # 例如 [255, 0, 0] 表示蓝色 # 修改该像素为绿色 img_bgr[100, 50] [0, 255, 0] # B0, G255, R0 # 仅修改蓝色通道的值 img_bgr[100, 50, 0] 128实操心得直接使用循环如双重for循环遍历每个像素进行修改在Python中效率极低对于稍大的图片就是性能灾难。务必使用NumPy的向量化操作或OpenCV的内置函数。区域ROI, Region of Interest操作 处理图片的某一部分如人脸、车牌非常常见。# 假设我们想截取图片左上角100x100的区域 roi img_bgr[0:100, 0:100] # 将这个区域复制到另一个位置 img_bgr[200:300, 200:300] roi通道分离与合并 有时需要单独处理某个颜色通道。# 将BGR图像拆分成三个单通道图像 b, g, r cv2.split(img_bgr) # 或者使用NumPy索引更高效 b img_bgr[:, :, 0] g img_bgr[:, :, 1] r img_bgr[:, :, 2] # 增强红色通道 r_enhanced cv2.add(r, 50) # 所有红色值增加50注意防止溢出255 # 将处理后的通道合并回去 img_merged cv2.merge((b, g, r_enhanced))3.3 色彩空间转换与灰度图处理很多图像分析如边缘检测在灰度图上进行更简单有效。# 将BGR图像转换为灰度图 img_gray cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY) print(f灰度图形状: {img_gray.shape}) # 输出: (高度, 宽度)通道数为1 # 此时 img_gray[i, j] 就是一个0-255的亮度值。灰度化公式通常是加权平均Gray 0.299*R 0.587*G 0.114*BOpenCV的cvtColor函数帮我们完成了这个计算。3.4 基础统计与特征提取示例数学建模中常需要从图片中提取量化特征。# 计算整张灰度图的平均亮度、标准差 mean_val np.mean(img_gray) std_val np.std(img_gray) print(f平均亮度: {mean_val:.2f}, 标准差: {std_val:.2f}) # 计算图像的直方图了解像素亮度分布 hist cv2.calcHist([img_gray], [0], None, [256], [0, 256]) # hist 是一个256x1的数组hist[i]表示亮度为i的像素个数 # 找出图像中最亮和最暗的像素值及其位置 min_val, max_val, min_loc, max_loc cv2.minMaxLoc(img_gray) print(f最暗值: {min_val} 位于 {min_loc}) print(f最亮值: {max_val} 位于 {max_loc})这些统计量可以作为描述图片整体明暗、对比度特征的简单指标。4. 视频帧处理的完整流程与关键技术视频本质上是按时间顺序排列的图片序列帧。处理视频就是循环处理每一帧图片并处理好帧与帧之间的关系如时间戳、帧率。4.1 视频读取与属性获取使用cv2.VideoCapture对象来操作视频。# 创建VideoCapture对象参数可以是视频文件路径也可以是摄像头索引如0代表默认摄像头 cap cv2.VideoCapture(sample_video.mp4) # 检查视频是否成功打开 if not cap.isOpened(): print(无法打开视频文件) exit() # 获取视频的一些基本属性非所有视频都支持获取这些属性 fps cap.get(cv2.CAP_PROP_FPS) # 帧率每秒多少帧 total_frames int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 总帧数 width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 帧的宽度 height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 帧的高度 duration total_frames / fps if fps 0 else 0 # 视频时长秒 print(f视频信息: {width}x{height}, {fps:.2f} FPS, 共{total_frames}帧时长{duration:.2f}秒)注意事项cap.get()返回的属性值是浮点数且某些属性如总帧数对于某些编码格式的视频可能不准确或返回0。更可靠的方式是在读取循环中计数。4.2 逐帧读取、处理与写入的循环架构这是视频处理的核心骨架。通常我们会一边从输入视频读帧处理一边写入到一个新的输出视频中。# 定义视频编码器和创建VideoWriter对象用于保存处理后的视频 # ‘XVID是MPEG-4编码的一种兼容性好。‘MJPG也是一种常见选择。 fourcc cv2.VideoWriter_fourcc(*XVID) # 参数输出文件名编码器帧率帧大小(宽,高)是否为彩色 out cv2.VideoWriter(output_video.avi, fourcc, fps, (width, height), isColorTrue) frame_count 0 while True: # ret是一个布尔值表示是否成功读取到帧 # frame就是读取到的当前帧图像BGR格式的NumPy数组 ret, frame cap.read() if not ret: print(视频读取完毕或发生错误) break frame_count 1 # --- 在这里对当前帧 frame 进行处理 --- # 示例1转换为灰度图并加一个文本标注 gray_frame cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 将灰度图转回BGR以便用彩色文字标注如果原输出是彩色 gray_frame_bgr cv2.cvtColor(gray_frame, cv2.COLOR_GRAY2BGR) cv2.putText(gray_frame_bgr, fFrame: {frame_count}, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) # 示例2进行边缘检测Canny算法 # edges cv2.Canny(gray_frame, threshold150, threshold2150) # edges_bgr cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR) # 将处理后的帧写入输出视频 out.write(gray_frame_bgr) # 这里写入的是加了标注的灰度图 # 可选实时显示处理效果按‘q键退出显示 cv2.imshow(Processing, gray_frame_bgr) if cv2.waitKey(1) 0xFF ord(q): break # 释放所有资源 cap.release() out.release() cv2.destroyAllWindows() print(f处理完成共处理 {frame_count} 帧)这个循环结构是通用的你只需要在注释--- 在这里对当前帧 frame 进行处理 ---的位置替换成你的核心处理逻辑。4.3 关键帧提取与跳帧处理对于很长的视频或者对实时性要求不高的分析我们可能不需要处理每一帧。# 设置每隔N帧处理一帧 frame_interval 5 # 每5帧处理1帧 processed_frame_count 0 while True: ret, frame cap.read() if not ret: break frame_count 1 # 如果当前帧序號不是我们想要处理的就跳过 if frame_count % frame_interval ! 0: continue # 跳过本次循环的后续处理 processed_frame_count 1 # ... 对frame进行处理 ... print(f正在处理第 {frame_count} 帧提取的第 {processed_frame_count} 个关键帧)这对于背景建模、运动目标检测等需要降低计算量的场景很有用。4.4 时间戳与帧率控制在分析视频时时间信息很重要。# 获取当前帧的时间戳毫秒 current_time_ms cap.get(cv2.CAP_PROP_POS_MSEC) current_time_sec current_time_ms / 1000.0 # 在帧上绘制时间戳 cv2.putText(frame, fTime: {current_time_sec:.2f}s, (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)如果你在处理后需要以不同于原视频的帧率播放或保存可以在创建VideoWriter时指定新的fps。例如慢动作效果可以用更低的fps保存但播放时时间会拉长。5. 面向数学建模的进阶应用场景与算法集成数学建模题目不会只让你读像素和拆视频一定会结合一个具体问题。这里我基于常见题型设想几个可能的方向并给出实现思路。5.1 场景一基于颜色或亮度的目标区域统计题目可能要求统计视频中某个特定颜色区域如红色车辆的面积变化或统计画面中过亮可能为光源或过暗区域的比例随时间的变化。实现思路颜色筛选将每一帧从BGR转换到HSV色彩空间。HSV对颜色更直观H色调S饱和度V明度。通过设定阈值范围来提取特定颜色。hsv_frame cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # 定义红色的HSV范围注意OpenCV中H范围是0-180 lower_red1 np.array([0, 70, 50]) upper_red1 np.array([10, 255, 255]) lower_red2 np.array([170, 70, 50]) # 红色在HSV环上两端 upper_red2 np.array([180, 255, 255]) mask1 cv2.inRange(hsv_frame, lower_red1, upper_red1) mask2 cv2.inRange(hsv_frame, lower_red2, upper_red2) red_mask cv2.bitwise_or(mask1, mask2)亮度筛选如果是灰度图直接设定阈值。_, bright_mask cv2.threshold(gray_frame, 200, 255, cv2.THRESH_BINARY) # 亮度大于200的设为白色区域统计mask是一个二值图白色255区域即目标区域。统计白色像素个数即为区域面积以像素为单位。target_pixel_count np.sum(red_mask 255) total_pixel_count red_mask.shape[0] * red_mask.shape[1] target_ratio target_pixel_count / total_pixel_count时序分析将每一帧计算出的target_ratio或target_pixel_count存入列表或数组结合帧率信息就可以分析其随时间的变化趋势绘制曲线图。这可以用来分析车流量、光源闪烁频率等。5.2 场景二简单运动检测与轨迹分析题目可能要求检测视频中运动物体并粗略估计其运动速度或方向。实现思路基于帧差法背景建模一种简单方法是取视频前N帧的平均作为背景。# 假设我们已经读取了前30帧到一个列表 frames 中 background np.mean(frames, axis0).astype(np.uint8) background_gray cv2.cvtColor(background, cv2.COLOR_BGR2GRAY)计算帧差对于后续每一帧将其转换为灰度图与背景灰度图做差并取绝对值。current_gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) diff cv2.absdiff(background_gray, current_gray)二值化与去噪设定一个阈值将差异明显的区域标记为运动区域。_, motion_mask cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY) # 使用形态学操作开运算去除小噪声点 kernel np.ones((5,5), np.uint8) motion_mask_cleaned cv2.morphologyEx(motion_mask, cv2.MORPH_OPEN, kernel)寻找轮廓找到运动区域的边界。contours, _ cv2.findContours(motion_mask_cleaned, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for contour in contours: if cv2.contourArea(contour) 500: # 忽略太小的区域 x, y, w, h cv2.boundingRect(contour) cv2.rectangle(frame, (x, y), (xw, yh), (0, 255, 0), 2) # 画框 # 可以计算矩形中心点 (xw//2, yh//2) 作为物体位置轨迹与速度记录每一帧中运动物体中心点的坐标。通过连续帧间中心点的位移结合帧间隔时间1/fps秒可以估算瞬时速度速度 像素位移 / (1/fps)。注意这得到的是“像素/秒”的速度要得到真实世界速度需要已知画面中某个参照物的实际长度进行标定。5.3 场景三图像质量评估与增强前后对比题目可能要求对视频的每一帧进行图像清晰度评估或应用一种图像增强算法如直方图均衡化并对比效果。实现思路清晰度评估无参考可以使用拉普拉斯方差法。拉普拉斯算子能突出图像中的边缘清晰的图像边缘更多更锐利其拉普拉斯响应的方差会更大。def estimate_sharpness(image_gray): laplacian_var cv2.Laplacian(image_gray, cv2.CV_64F).var() return laplacian_var sharpness estimate_sharpness(current_gray)遍历视频帧计算每一帧的sharpness值可以找出最模糊或最清晰的帧。图像增强例如使用直方图均衡化来增加对比度尤其适用于整体偏暗或偏亮的视频。# 对灰度图进行全局直方图均衡化 enhanced_gray cv2.equalizeHist(current_gray) # 对于彩色图通常转换到YCrCb空间只对亮度通道Y进行均衡化再转回BGR以避免颜色失真。 img_ycrcb cv2.cvtColor(frame, cv2.COLOR_BGR2YCrCb) img_ycrcb[:,:,0] cv2.equalizeHist(img_ycrcb[:,:,0]) enhanced_color cv2.cvtColor(img_ycrcb, cv2.COLOR_YCrCb2BGR)对比展示与量化将原帧和处理后的帧并排显示并计算一些量化指标如平均亮度、对比度标准差的变化用数据说明增强效果。6. 实战中常见问题排查与性能优化技巧在实际编码和运行过程中你肯定会遇到各种报错和性能瓶颈。这里我总结几个最典型的问题和解决办法。6.1 常见错误与解决方案速查表问题现象可能原因解决方案cv2.error: OpenCV(4.x) ... imread_(image.jpg): cant open/read file1. 文件路径错误。2. 文件名包含中文或特殊字符。3. 文件已被其他程序占用。1. 使用绝对路径或检查相对路径是否正确。print(os.path.exists(image.jpg))验证。2. 尽量使用英文命名或尝试用cv2.imdecode读取。3. 关闭可能占用该文件的程序。AttributeError: module cv2 has no attribute xxx1. 函数名拼写错误OpenCV函数大小写敏感。2. OpenCV版本不同函数名或位置有变化。1. 检查官方文档确认正确函数名如cv2.COLOR_BGR2GRAY。2. 使用print(cv2.__version__)查看版本查阅对应版本文档。视频处理循环卡死或cap.read()一直返回False1. 视频文件损坏或编码格式不被支持。2. 没有在循环中正确释放摄像头或前一个视频流。1. 用主流播放器测试视频能否正常播放。尝试用FFmpeg转换格式如转为MP4 with H.264。2. 确保在循环开始前之前的VideoCapture对象已调用.release()。保存的视频无法播放或只有一帧1.VideoWriter的帧大小、帧率设置与写入的帧不匹配。2. 在循环中没有持续调用out.write()。3. 编码器(fourcc)与文件扩展名不匹配。1. 确保out cv2.VideoWriter(..., (width, height), ...)中的宽高与frame.shape[1]和frame.shape[0]一致。2. 检查循环逻辑确保每一帧都执行了写入。3. 常用组合.avi文件用XVID.mp4文件用mp4v可能需要额外安装编码器。处理速度非常慢1. 在Python循环中逐像素操作。2. 使用了未优化的高级算法或过大尺寸的图片。3. 没有跳过不需要处理的帧。1.绝对避免双重for循环遍历像素。使用NumPy向量化操作或OpenCV内置函数。2. 可尝试将帧缩放(cv2.resize)到更小尺寸进行处理。3. 采用跳帧处理见4.3节。6.2 性能优化心得预处理缩放如果模型或分析不需要原始分辨率在循环开始前统一将帧缩放至较小尺寸能极大提升后续所有操作的速度。scale_percent 50 # 缩放为原来的50% new_width int(width * scale_percent / 100) new_height int(height * scale_percent / 100) dim (new_width, new_height) # 在循环内处理每一帧时 frame_resized cv2.resize(frame, dim, interpolationcv2.INTER_AREA) # 后续对 frame_resized 进行操作活用cv2.bitwise_and/or/not/xor对二值掩膜mask进行区域组合操作时这些位运算函数比用NumPy数组的逻辑运算更快。减少不必要的转换如果一系列操作都可以在灰度图上完成就尽早转为灰度图并避免在灰度与BGR之间来回转换。使用cv2.UMat可选OpenCV的UMat可以利用系统GPU进行加速如果OpenCV编译了GPU支持。简单来说将cv2.imread读到的图像转为UMat后续一些OpenCV操作会更快。但注意不是所有函数都支持UMat。img_umat cv2.UMat(img_bgr) gray_umat cv2.cvtColor(img_umat, cv2.COLOR_BGR2GRAY) # ... 其他操作 gray gray_umat.get() # 如果需要转回普通的NumPy数组6.3 代码健壮性与可复现性异常捕获在文件IO、视频捕获等可能出错的地方使用try...except。try: img cv2.imread(important_pic.jpg) if img is None: raise FileNotFoundError # 手动引发异常 # 正常处理 except Exception as e: print(f读取图片时发生错误: {e}) # 使用一张默认图片或跳过 img np.zeros((500, 500, 3), dtypenp.uint8)参数配置文件将视频路径、处理阈值、跳帧间隔等参数写在配置文件如config.yaml或config.json或脚本开头的变量区而不是硬编码在逻辑中。这样调整参数和他人复现都更方便。结果可视化与中间输出在处理过程中适时使用cv2.imshow()或matplotlib将关键步骤如生成的掩膜、检测到的轮廓显示出来便于调试。也可以将关键帧或统计结果保存为图片或日志文件。走到这里你已经掌握了从图片像素操作到视频帧处理的完整链路。这套流程和代码框架具有很强的通用性你可以像搭积木一样将第三部分介绍的像素访问、第五部分设想的应用算法填充到第四部分的视频处理循环中去解决具体的建模问题。核心在于理解数据图片/视频在程序中的流动形式NumPy数组并熟练运用OpenCV这个工具箱去操作它。剩下的就是结合具体问题去设计和实现你的算法逻辑了。多动手调试遇到问题善用搜索引擎和OpenCV官方文档你一定能搞定这个题目。
返回列表