尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

C#基于Emgu.CV的模板匹配与行人检测:从环境配置到实战排错

发布时间:2026/9/28 14:42:43

资讯中心
01
ARTICLE

C#基于Emgu.CV的模板匹配与行人检测:从环境配置到实战排错

C#基于Emgu.CV的模板匹配与行人检测:从环境配置到实战排错
简介这是一份面向C#开发者的计算机视觉实践资源围绕Emgu.CV库演示模板匹配、行人检测与特征点识别等经典任务适合希望用.NET技术栈实现OpenCV功能的初中级学习者也可作为智能监控、图像检索类项目的起步参考。压缩包共35个文件以jpg/jpeg图片样本、cs源码、xaml界面及config配置为主整体仅1.01MB结构紧凑包含EmguCV解决方案与多个可运行项目。已有399人浏览下载。资源中可见TemplateMatching示例、Haar级联行人检测代码、SIFT/SURF特征点匹配实现并附带项目配置文件与界面资源读者可直接打开sln工程结合样例图片理解匹配流程与检测参数再按需修改扩展。对于想快速体验C#版OpenCV、理解模板匹配和行人检测落地方式的学习者这套源码是较为直观的参考。1. 基于Emgu.CV的C#模板匹配与行人检测先搞清楚这个zip里装的到底是什么拿到这类“人工智能-项目实践-C#-基于Emgu.CV的模板匹配、行人检测等.zip”压缩包很多人的第一反应是解压、打开.sln、按F5然后对着满屏的红叉发呆。这个zip里装的东西本质上是一个用C#封装的OpenCV工具箱模板匹配解决“在画面里找特定小图”的定位问题行人检测解决“在画面里找移动的人”的目标识别问题。两者都是典型的计算机视觉入门项目常见于C#上位机交互、人工智能大作业和本科毕设。如果你是写C#的工控工程师、刚接触视觉的软件开发者或者正在为课程项目找代码做二次开发这套东西值得花一周时间跑通并理解它而不是只拿来做演示。2. 把Emgu.CV环境搭起来从NuGet包、x64到第一帧灰度图2.1 为什么在C#里选Emgu.CV而不是直接调OpenCV C很多做C#上位机的人纠结过这个问题OpenCV是C写的C#要调用它方案无非是OpenCvSharp、Emgu.CV或者自己写P/Invoke。Emgu.CV是OpenCV的.NET封装API和原生OpenCV几乎一一对应你在网上搜到的OpenCV Python或C教程翻译成Emgu.CV调用通常只需要改类名和参数类型。它和我们自己用DllImport去调opencv_world.dll那种做法相比最大的价值是帮你省掉了手动处理指针、内存释放和类型转换的工作C#这边拿到的直接就是Mat、ImageTColor,TDepth这些托管对象。同时Emgu.CV的社区活跃度和示例数量在.NET生态里仍然是最高的。做工业视觉项目时模版匹配、边缘检测、轮廓查找这些基础算法基本都能在Emgu.CV里找到对应封装。但要注意它的短板版本迭代太快原生DLL体积大而且4.x之后OpenCV换成了C11实现运行时必须带上对应的runtime包。这也是很多初学者环境没搭好就翻车的第一步。2.2 最小化跑通创建项目、安装三个NuGet包、输出一张灰度图我建议从控制台应用程序开始先把环境跑通再接摄像头和界面。用Visual Studio新建一个.NET 6/8控制台项目或者经典的.NET Framework 4.7.2都可以然后通过NuGet安装下面三个包Install-Package Emgu.CV Install-Package Emgu.CV.Bitmap Install-Package Emgu.CV.runtime.windows第一个是托管代码主包第二个提供Bitmap和Image,之间的互转第三个是OpenCV原生DLL的Windows运行时。第三个最容易漏漏了会直接导致运行时找不到opencv_core450.dll之类的报错。装完包之后写一个最简单的环境验证程序using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; class Program { static void Main() { // 用ImreadModes.Color读入彩色图Emgu.CV会把它封装成Mat对象 using Mat color new Mat(test.jpg, ImreadModes.Color); using Mat gray new Mat(); // BGR转灰度这是后面模板匹配和HOG检测的公共前置步骤 CvInvoke.CvtColor(color, gray, ColorConversion.BgrToGray); gray.Save(gray_test.jpg); System.Console.WriteLine($Emgu.CV环境OK, 灰度图尺寸: {gray.Width} x {gray.Height}); } }这段代码里的using声明很重要。Mat在Emgu.CV里虽然是有托管外壳的原生对象但底层挂在非托管内存上用using声明可以在作用域结束时释放。如果你在循环里反复new Mat()又不释放很快会看到内存涨到几百MB。2.3 三个必设项目参数以及Image和Mat的内存习惯环境能跑通还不够有三个设置直接影响后面会不会踩坑。第一项目生成目标必须设为x64Visual Studio里右键项目 - 属性 - 生成 - 平台目标选x64同时取消“首选32位”勾选。Emgu.CV的runtime包里同时带了x86和x64两套DLL如果平台目标不匹配有时能编译过运行时给你弹DllNotFoundException这种错最容易误导人。第二如果用的是.NET Framework建议目标框架不低于4.7.2否则部分图像编码和解码API不可用。第三项目目录不要放在带中文或空格的路径下进行调试OpenCV原生层对路径解析在某些版本上有兼容问题这个虽然有点玄学但在Windows环境下确实能减少莫名报错。接下来要养成一个习惯图像对象用完立即显式释放。ImageGray, byte和Mat都实现了IDisposable。我在做C#上位机的时候见过很多老代码每帧图像都new ImageGray,byte却不Dispose最后程序跑一个小时后GC频繁、界面卡顿、摄像头画面延迟越来越大。正确的做法是复用同一个Mat对象或者把每帧处理后临时创建的Image用using包住。3. 模板匹配实战从匹配原理到多目标定位3.1 模板匹配在看什么滑动窗口、相似度度量和六种匹配方法模板匹配是最朴素的视觉定位算法思路很直白把模板小图当作卷积核在待搜索的大图上从左到右、从上到下地滑动每到一个位置就算一次模板与对应区域的相似度最后得到一张和搜索图尺寸相近的相似度图。相似度最高的点就是模板最可能存在的位置。它不像深度学习目标检测那样需要训练只要你手里有一张模板图几十行代码就能跑起来。Emgu.CV的CvInvoke.MatchTemplate支持六种匹配方法关键是先理解它们的分工。SqDiff系列计算的是差值的平方和值越小越匹配。Ccorr系列计算的是相关值值越大越匹配。Ccoeff系列先做了均值归一化再计算相关对光照变化相对不敏感。实际做工业定位时我一般优先选CcoeffNormed因为它把结果归一化到-1到1之间阈值设置直观而且在光照稍微变化时比SqDiff系列抗造。下面这个表是选型时用的方法匹配值含义优点缺点SqDiff / SqDiffNormed越小越匹配对精确灰度匹配敏感对光照变化极敏感Ccorr / CcorrNormed越大越匹配计算快亮度偏移会影响结果Ccoeff / CcoeffNormed越大越匹配抗光照变化结果归一化比Ccorr稍慢模板匹配解决的是“平移”问题也就是说目标物体的大小和旋转角度必须和模板基本一致。如果目标在画面里变大变小了就需要配合多尺度缩放这个放到后面的小节说。3.2 用CvInvoke.MatchTemplate跑通单目标匹配最小代码先写一个最小可用的单目标匹配。场景是这样的你有一张产品图scene.png从里面抠出一个元件做模板template.png程序要算出元件在场景里的像素坐标。using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; using System.Drawing; class TemplateMatchDemo { static void Main() { // 模板和搜索图都转到灰度匹配结果更稳定 using ImageGray, byte source new ImageGray, byte(scene.png); using ImageGray, byte template new ImageGray, byte(template.png); // result的尺寸 源图 - 模板 1 using ImageGray, float result new ImageGray, float(source.Width - template.Width 1, source.Height - template.Height 1); // CcoeffNormed是归一化相关系数值越接近1越像 CvInvoke.MatchTemplate(source, template, result, TemplateMatchingType.CcoeffNormed); // 找到相似度最大和最小值的位置 CvInvoke.MinMaxLoc(result, out double minVal, out double maxVal, out Point minLoc, out Point maxLoc); if (maxVal 0.8) { // maxLoc是模板左上角在源图中的位置 Rectangle box new Rectangle(maxLoc, template.Size); CvInvoke.Rectangle(source, box, new Bgr(Color.Red).MCvScalar, 2); source.Save(result.png); } } }这里有一个关键点result图比源图小宽和高都少了template - 1个像素。因为模板在滑到最右侧和最下侧时没有足够的空间继续滑动。MinMaxLoc返回的maxLoc是在result坐标系里的坐标而它恰好也是模板左上角在源图里的位置。所以画框时直接用maxLoc当左上角宽度和高度用template.Size不需要做任何偏移换算这也是很多第一次写的人忽略的。阈值0.8不是固定的。CcoeffNormed的输出虽然被归一化但实际数值受纹理丰富程度影响。场景复杂时0.8可能误检很多纹理单一且光照稳定时0.5也可能没问题。我的习惯是先收集50张左右的现场图统计正常匹配分数都在什么区间再把阈值设在最低正常分数以下0.05左右。3.3 多目标匹配与NMS一张图里找多个相同元件单目标匹配只取相似度最高的那一个点。但很多实际场景要求在一张图里找到所有符合条件的元件比如一块PCB板上有6个相同的电容。这时不能用MinMaxLoc只取一个点而是要遍历result的所有像素把分数大于阈值的点都当作候选框。ListRectangle candidates new ListRectangle(); Listdouble scores new Listdouble(); for (int y 0; y result.Height; y) { for (int x 0; x result.Width; x) { float score result[y, x].Intensity; // 取出该像素的匹配分数 if (score 0.8) { candidates.Add(new Rectangle(x, y, template.Width, template.Height)); scores.Add(score); } } }这里直接用一个ImageGray,float的索引取值方式比Mat.GetData()更直观。跑完之后会得到一堆彼此重叠的候选框同一个目标往往有十几个框靠NMS非极大值抑制合并。NMS的做法是按分数从高到低排序每次保留当前最高分框去掉和它重叠度过高的其他框再处理下一个。static double CalcIoU(Rectangle a, Rectangle b) { Rectangle inter Rectangle.Intersect(a, b); int interArea inter.Width * inter.Height; int unionArea a.Width * a.Height b.Width * b.Height - interArea; return interArea / (double)unionArea; } static ListRectangle NMS(ListRectangle boxes, Listdouble scores, double overlapThresh) { var idx Enumerable.Range(0, scores.Count) .OrderByDescending(i scores[i]) .ToList(); bool[] suppressed new bool[boxes.Count]; ListRectangle kept new ListRectangle(); for (int i 0; i idx.Count; i) { if (suppressed[idx[i]]) continue; kept.Add(boxes[idx[i]]); for (int j i 1; j idx.Count; j) { if (suppressed[idx[j]]) continue; if (CalcIoU(boxes[idx[i]], boxes[idx[j]]) overlapThresh) suppressed[idx[j]] true; } } return kept; }这个NMS函数可以原样搬进项目里。overlapThresh取值一般用0.3到0.5如果两个框是同一个目标IoU往往在0.8以上如果目标是紧挨着的多个同类物体IoU可能在0.3以下所以0.3到0.5是个不错的中间区间。多目标匹配的性能瓶颈在遍历像素那一段一张1920x1080的图生成的结果图有约200万个像素点用循环逐个判断会比较慢后续可以用CvInvoke.Threshold配合FindContours来加速不过对学习项目来说先跑通再优化。3.4 多尺度模板匹配目标变大变小时怎么办模板匹配对尺度敏感同一个模板在搜索图里放大了1.2倍直接匹配分数可能掉到0.3以下。解决思路是固定模板尺寸把搜索图按不同比例缩放后分别匹配再把结果换算回原始坐标。using ImageGray, byte source new ImageGray, byte(scene.png); using ImageGray, byte template new ImageGray, byte(template.png); double minScale 0.8, maxScale 1.2, step 0.05; double bestScore -1; Rectangle bestBox Rectangle.Empty; double bestScale 1.0; for (double scale minScale; scale maxScale; scale step) { using ImageGray, byte scaled source.Resize(scale, Inter.Linear); if (scaled.Width template.Width || scaled.Height template.Height) continue; using ImageGray, float result new ImageGray, float(scaled.Width - template.Width 1, scaled.Height - template.Height 1); CvInvoke.MatchTemplate(scaled, template, result, TemplateMatchingType.CcoeffNormed); CvInvoke.MinMaxLoc(result, out double minVal, out double maxVal, out Point minLoc, out Point maxLoc); if (maxVal bestScore) { bestScore maxVal; bestScale scale; // 注意坐标和框尺寸都要还原回原图尺度 bestBox new Rectangle((int)(maxLoc.X / scale), (int)(maxLoc.Y / scale), template.Width, template.Height); } result.Dispose(); } Console.WriteLine($最佳尺度: {bestScale:F2}, 最佳分数: {bestScore:F3});中间有一个容易忽略的细节模板始终保持原始大小不变缩放的是源图。缩放源图相当于把目标“缩小”或“放大”到和模板一样的尺度这样匹配才能生效。最终得到的maxLoc是在缩放后的图里的坐标还原成原图坐标需要除以scale。框的宽高不需要乘scale因为框的尺寸基于模板而模板没有缩放。尺度的步长step很关键。step太大可能错过最佳匹配尺度比如目标实际放大了1.13倍step设0.1会直接从1.0跳到1.1再跳到1.2匹配分数可能不是最优。step太小又会成倍增加匹配次数实时性变差。一般先粗扫一遍确定大致区间再在区间内用更小的step精扫。对工业检测场景0.05的步长加0.8到1.2的范围通常够用。4. 行人检测实战Emgu.CV里的HOGSVM通道4.1 HOG特征为什么适合行人64x128窗口、细胞块与方向直方图模板匹配找的是“已知长什么样的物体”行人检测面对的是“不知道穿什么衣服、什么姿势”的目标不能直接用模板。Emgu.CV内置的行人检测走的是传统机器学习路线HOG特征加SVM分类器。HOG全称方向梯度直方图核心思想是把图像分成小格子统计每个格子里边缘方向分布的直方图。行人这种目标有一个明显特点身体的轮廓和四肢会产生大量纵向边缘这些纵向梯度的分布规律在统计上是稳定的再加上SVM分类器训练就能把“人”和“非人”区分开。HOG的经典参数是OpenCV从INRIA行人数据集上训练出来的默认模型里带的那一套检测窗口64x128像素细胞单元8x8块16x16块步长8x8方向直方图9个bin。这套参数对应的就是站立、全身可见的行人姿态也就是说它对半身、坐姿、骑自行车的人效果会明显下降。理解了这一点就不会对默认模型的误检和漏检大惊小怪。在Emgu.CV里这些参数已经封装在HOGDescriptor里。你不需要自己写HOG特征提取的代码只需要创建默认描述符并加载默认的SVM检测器。using Emgu.CV; using Emgu.CV.Structure; using System.Drawing; HOGDescriptor hog new HOGDescriptor(); hog.SetSVMDetector(HOGDescriptor.GetDefaultPeopleDetector());这里千万不能用new HOGDescriptor(new Size(...))然后直接Detect那样等于没有加载训练好的SVM模型跑出来的结果没有任何意义。GetDefaultPeopleDetector返回的是OpenCV官方在行人检测数据集上训练好的系数向量加载它才是真正的“行人检测”。4.2 让DetectMultiScale跑起来参数含义和第一次检测DetectMultiScale是HOG检测的入口它负责在整张图上按不同尺度滑动窗口并做SVM分类。先给一组能直接用的代码using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; using System.Drawing; class PeopleDetection { static void Main() { using Mat frame new Mat(street.png, ImreadModes.Color); HOGDescriptor hog new HOGDescriptor(); hog.SetSVMDetector(HOGDescriptor.GetDefaultPeopleDetector()); // winStride8x8, padding0, scale1.05, groupThreshold2 MCvObjectDetection[] detections hog.DetectMultiScale( frame, 0.0, new Size(8, 8), new Size(0, 0), 1.05, 2, false); foreach (MCvObjectDetection det in detections) { CvInvoke.Rectangle(frame, det.Rect, new Bgr(Color.Red).MCvScalar, 3); } frame.Save(detected.png); Console.WriteLine($检测到行人数量: {detections.Length}); } }参数说明要从实际效果去理解。hitThreshold设为0表示SVM分类的判决阈值调低会检测出更多候选但误检增加调高会减少误检但漏检增加这个值看起来像个黑匣子实际调试时我一般先在0附近固定通过其他参数控制误检。winStride是滑动窗口的步长它越小检测越精细但计算量成倍增加8像素是速度与精度的平衡点。scale是金字塔缩放比例1.05表示每层缩小5%越大层与层之间跨度越大检测越快但可能漏掉中间尺度的行人越小检测越细致但速度越慢。groupThreshold用于合并重叠检测框值为2表示至少两个检测框重叠才合并越大越倾向于合并能有效减少同一人多框的情况。最后一个参数useMeanshiftGrouping用均值漂移做合并设为false即可。4.3 视频流与摄像头连续检测时如何不掉帧把上面的代码接进视频流是这类项目最常见的扩展。Emgu.CV的VideoCapture同时支持摄像头和视频文件构造传入0表示默认摄像头。连续检测时要提前意识到一个问题HOG检测一张1920x1080的图在纯CPU机器上可能要数百毫秒而摄像头的帧间隔只有33毫秒每帧都做HOG注定完不成。实际项目里常用的做法是抽帧检测比如每隔5帧检测一次或者把画面缩小到640x480再检测。using VideoCapture capture new VideoCapture(0); capture.Set(CapProp.FrameWidth, 640); capture.Set(CapProp.FrameHeight, 480); HOGDescriptor hog new HOGDescriptor(); hog.SetSVMDetector(HOGDescriptor.GetDefaultPeopleDetector()); using Mat frame new Mat(); int frameCount 0; while (capture.Read(frame)) { frameCount; if (frameCount % 5 ! 0) continue; // 每5帧才做一次检测 MCvObjectDetection[] detections hog.DetectMultiScale( frame, 0.0, new Size(8, 8), new Size(0, 0), 1.05, 2, false); foreach (MCvObjectDetection det in detections) { CvInvoke.Rectangle(frame, det.Rect, new Bgr(Color.Red).MCvScalar, 2); } // CvInvoke.Imshow(people, frame); // WinForms/WPF项目里用PictureBox显示更合适 }使用VideoCapture时的坑也不少。Read返回的Mat在下一帧读取时会被覆盖如果你要把这帧保存下来或者放到队列里一定要frame.Clone()否则后续操作的实际是已经被覆盖的数据。另外摄像头打开失败时Read会一直返回false代码里要加一个计数器连续读取失败多次就主动退出循环避免界面假死。这些细节在C#上位机场景里尤其重要因为没人希望产线调试时程序突然卡住。5. 本项目最容易翻车的5个坑模板匹配与行人检测排错笔记5.1 运行时提示DllNotFoundException: opencv_core450.dll现象编译完全正常一运行就弹DllNotFoundException报错信息指向opencv_core450.dll或类似的DLL。这个报错在C#调用原生库的场合非常典型和不少人用C#调用C动态库时遇到的Access Violation C0000005一样根因大半是平台不匹配。原因Emgu.CV的托管DLL有两个版本的原始DLL需要加载x86和x64。项目默认的“首选32位”被勾选时进程以x86模式运行加载x64的DLL必然失败。另一个常见原因是只安装了Emgu.CV主包没有安装Emgu.CV.runtime.windows导致输出目录里根本没有原生DLL。解决项目属性里把平台目标设为x64取消首选32位。然后检查bin目录下是否有x64和x86文件夹里面应该能找到opencv_core*.dll。如果没有右键项目选择“管理NuGet程序包”安装Emgu.CV.runtime.windows并重新生成。这个问题通常只用五秒钟解决但能卡住新手一整天。5.2 MatchTemplate结果全黑MinMaxLoc的最大和最小值几乎一样现象跑完MatchTemplate后result图像显示出来是纯黑的MinMaxLoc返回的maxVal和minVal数值非常接近甚至完全一样检测框乱画。原因模板和搜索图的通道数或位深不一致。最常见的情况是把BGR彩色图直接和ImageGray, byte做匹配MatchTemplate对通道数有严格要求两者必须同为单通道或同为三通道。第二个常见情况是模板尺寸大于或等于搜索图尺寸result的宽或高算出来是0或负数MinMaxLoc在一个空图上执行自然得到无意义结果。解决在传入MatchTemplate之前统一做一次灰度转换。模板匹配并不需要彩色信息灰度图计算量更小匹配结果也更稳定。同时检查一下模板是不是真的比搜索图小我一般会加一段防御校验模板宽度和高度都至少比搜索图小10个像素以上否则直接抛出异常避免后续逻辑吃到脏数据。5.3 模板匹配的检测框总是偏半个模板现象明明模板匹配分数很高位置也不错但画出来的框就是往右上角偏了几个像素看起来像是框的中心不对但模板左上角的位置计算看起来很合理。原因这是对maxLoc坐标系理解的问题。MinMaxLoc返回的maxLoc是模板左上角在搜索图中的位置但如果你在result图和原图之间做了一次缩放或者用Rectangle(maxLoc.X - template.Width / 2, maxLoc.Y - template.Height / 2, ...)这种方式画框就会偏。很多人习惯性地认为返回的是中心点实际上它给出的是模板的锚点位置。解决记住一个口诀单尺度匹配时直接用maxLoc做左上角多尺度匹配时把maxLoc除以缩放系数再做左上角。画框的宽度和高度用模板尺寸不要自作聪明地加减偏移。如果画出来的框整体偏右上或左下先检查是不是在MatchTemplate前对搜索图做过了Resize忘了把坐标换算回来。5.4 HOG行人检测把树干、晾衣架当成人现象对一张街景图做行人检测框出了五六个区域仔细一看树干、路灯、停在路边的车都被框上了真正的行人反而漏掉了一半。这是HOG默认检测器最典型的误检和漏检问题。原因HOG特征本质是“边缘方向分布”统计树干和人的腿在梯度分布上确实有相似性。OpenCV自带的默认SVM模型是在INRIA行人数据集上训练出来的这个数据集里的行人绝大多数是站立、正面或背面、全身可见的所以对非标准姿态和静态柱状物体区分力不足。另外检测窗口是一个固定64x128的区域小目标行人经过金字塔缩放后可能小于这个窗口就检测不到。解决先调参数而不是换算法。把hitThreshold从0调到0.2或0.3误检数会明显下降但漏检率也可能升高。把scale从1.05改成1.03让金字塔层数更密小目标被漏检的概率降低。groupThreshold从2改成3更强的合并策略可以减少同一目标多个框的问题。如果用了这些参数还是误检严重再做一次面积过滤行人在画面中的宽度通常不会小于某个像素值比如20像素把小于这个宽度的框直接丢弃。仍然不满足需求时才考虑自己标注数据微调SVM或者换成深度学习检测模型。5.5 程序跑几分钟后内存飙升、图像循环变慢现象模板匹配或行人检测单独跑都没事一接进视频循环里跑三五分钟内存从50MB涨到500MB画面越来越卡最后GC一触发就停顿一秒钟。这是C#视觉项目的血泪经验。原因视频循环里每帧都创建了新的Mat或Image对象却没有释放。比如frame.ToImageGray, byte()这个方法每调用一次就会在托管堆上创建一个新对象底层指向新的非托管内存。如果这个对象没有Dispose它要等GC来回收而GC回收非托管内存是滞后的。解决严格执行几个编辑习惯。第一循环里能复用Mat就复用比如while(capture.Read(frame)) { ... }里的frame一次创建循环里反复填充。第二必须新建的中间图像用using包住。第三多尺度模板匹配里的scaled图和result图都在一次循环迭代结束时主动Dispose。如果项目里已经有了一堆历史代码排查时可以每隔100帧打印一次GC.GetTotalMemory(false)哪个循环迭代里内存涨幅明显就把那个迭代里的新建图像找出来释放掉。别指望GC自动帮你收拾还是要养成手动释放的习惯。6. 进阶验证技巧先量化匹配率再做HOG模板匹配组合很多人代码跑通就交差了但要让这个项目真正能写进简历或支撑一个结论需要做两件事第一是把“效果不错”变成一串数字第二是把两个算法组合起来解决更实际的问题。验证模板匹配最简单的办法是准备三组样本正样本是包含目标且位置已知的图负样本是不包含目标的图。对每组样本跑匹配记录匹配分数和位置误差。位置误差定义为检测框中心与人工标注中心的欧氏距离小于5个像素算匹配成功。最后统计出成功率、误检率和平均耗时。这个流程看起来不起眼却是把“调阈值像玄学”变成“阈值有依据”的唯一途径。HOG检测也有类似的验证思路取一段带标注的行人视频逐帧统计检出数和误检数计算召回率与误检率。基线召回率一般能达到70%左右就能说明方案可行。再往上一层模板匹配和HOG检测是可以组合使用的。HOG定位“哪里有人”模板匹配判断“这个人是不是目标人员”或者反过来HOG先在画面里圈出人的区域模板匹配在区域内做精确定位用于测量人在画面中的像素坐标。这种组合能缓解HOG定位框不精准的问题模板匹配不需要在全图搜索速度也更快。具体做法是把HOG框出来的Rect扩大1.2倍作为模板匹配的搜索区域再在这个区域内跑单目标匹配。这个技巧在C#上位机上做人员定位时非常实用比单独用任何一个算法都靠谱。这段路走下来最大的教训就是别信参数第一次就调对。环境、阈值、尺度这些都要靠样本数据一手一手调出来。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。