传统目标检测后处理问题
一、处理逻辑
- 背景建模得到前景 ----> 二值化标记 ---> 合并重叠框
- 由于二值化标记的局限,导致出现了很多的重叠框;
- 重叠框过多,在合并重叠框Merge这一步的时候举步维艰。时间消耗过长。
- 计算包围框,不在Merge的范围内!计算包围框时间过长了。
- 原因分析 + 证据证明!!!
1. 证据辅助过程
现象描述的准确文件:
① 找到超过3W点时,崩溃的数据。即找到当时耗时间过长的数据段,仔细分析问题。 fg格式文件准备。
② 时间间消耗证明过程。每帧是多少时间,多少点数,时间消耗。
③ fg到Meanshift到底得到了多少个标签?(非重复标签?)又得到了到底多少个框框?其中框框是个什么情况?重叠非重叠?需要处理多少个重叠的情况?
④ Merge这一步,面对这么多个重叠的框框,需要多少时间去处理?效率怎么样?
⑤ 这两个模块到底面临了多大的限制?局限性?天花板?
⑥ 如何解决这个局限性?
时间消耗过长的现象描述:
来了一个异常帧之后,由于前景点较多。在漂移半径较小的情况下,出现了很多这样的分割区域。
- 有1300多个分割区域。(①CCL二值图标记的时间消耗;②二值图标记的标签个数问题)
- 时间消耗不是主要的,关键是标签个数是一大缺陷;导致了后续的问题
- 后续的计算包围框的算法效率太低。
- 29W个点,以及56W个点的move_points,要遍历
- for 1:max_classID=1300
for 1:move_points.size() 56W/29W
- for 1:max_classID=1300
2. 参考opencv源码 connectedComponentWithStats函数
OpenCV—连通域分析connectedComponentsWithStats()_i_chaoren的博客-CSDN博客_cv::connectedcomponentswithstats
其中,自带了这部分后处理。除了标记,也直接给出了每个标记的区域信息,rect,area,centroid等信息。
2.1 opencv源码探析
文档位置:OpenCV: Structural Analysis and Shape Descriptors
opencv源码位置在:opencv->modules->imgproc->src->connectedcomponents.cpp
源码下载位置:https://github.com/opencv/opencv
- connectedComponentsWithStats->connectedComponents_sub1->LabelingWu()
- LabelingWu基本上按照CCL的代码逻辑在走;
- 主要看获取了labels之后的操作
- sop统计的数据类型,代码原理:
3. 修改之后的问题
时间:20:36:58时刻,2022-09 微信文件夹,16-3的数据。含有几个打shutter的帧,结果是:ID=1300之前,ComputeClosingRect计算包围框的时间消耗<1s,其中meanshif消耗2s
- ① Meanshift模块,继续非常耗时。
- ② 计算包围框模块,此时还是耗时7.34s
3.1 耗时7.4s时的情况
上面是当前图像,打shutter
下面是meanshift之后的标记结果。界面上的漂移半径很小。
MAXID= 2420。 ID到2000多的时候,还是很慢。
此时前景像素点为68W点。
- Meanshift模块时间消耗过大了。
3.2 单独测试合并重叠框的模块
测试代码如下:使用随机生成的方式,来进行合并
/*测试:合并重叠框算法效率&性能
*/
#include <opencv2/opencv.hpp>
#include <vector>bool isOverlap(cv::Point2i tl1, cv::Point2i br1, cv::Point2i curTl, cv::Point2i curBR);
bool isCenterClose(cv::Rect center, cv::Rect curCenter);
std::vector<int> getAllOverlaps(std::vector<cv::Rect>move_rects, cv::Rect curRect, int index);
void MergeUpdate(std::vector<cv::Rect> &move_rects);#define IMG_WIDTH 200
#define IMG_HEIGHT 200int shift_radius = 10;int main(int argc, char* argv[])
{cv::Mat img = cv::Mat::zeros(IMG_WIDTH, IMG_HEIGHT, CV_8UC1);// 1.随机生成多个重叠框int seed = 20;cv::RNG rng(seed); int k = 0;while (k < 20){k++;std::vector<cv::Rect> move_rects;for (int i = 0; i < 10; ++i) // 随机生成10个框{// 10% 概率生成大目标; 90% 概率生成小目标; 宽度; 左上角+w/hint left = rng.next() % IMG_WIDTH;int top = rng.next() % IMG_HEIGHT;int width = 0, height = 0;if (rng.next() % 10 == 0) // 10% 大目标{width = rng.next() % IMG_WIDTH + 1;height = rng.next() % IMG_HEIGHT + 1;}else{width = rng.next() % (IMG_WIDTH / 3) + 1;height = rng.next() % (IMG_HEIGHT / 3) + 1;}cv::Rect rect(left, top, width, height);move_rects.push_back(rect);}cv::Mat imgBeforMerge = img.clone();for (int i = 0; i < move_rects.size(); ++i){cv::rectangle(imgBeforMerge, move_rects[i], 255, 1); // 画出处理之前的bbox}// 2.合并重叠框MergeUpdate(move_rects);for (int i = 0; i < move_rects.size(); ++i){cv::rectangle(img, move_rects[i], 255, 1); // 画出处理之前的bbox}}return 0;
}bool isOverlap(cv::Point2i tl1, cv::Point2i br1, cv::Point2i curTl, cv::Point2i curBR)
{//[tl1.x, tl1.y, br1.x, br1.y] [curTl.x, curTl.y, curBR.x, curBR.y]return !(br1.x < curTl.x || br1.y < curTl.y || tl1.x > curBR.x || tl1.y > curBR.y);
}bool isCenterClose(cv::Rect center, cv::Rect curCenter)
{int cenx = center.x + center.width / 2;int ceny = center.y + center.height / 2;int CurCenX = curCenter.x + curCenter.width / 2;int CurCenY = curCenter.y + curCenter.height / 2;float diff = (cenx - CurCenX) * (cenx - CurCenX)+ (ceny - CurCenY) * (ceny - CurCenY);return diff < shift_radius;
}std::vector<int> getAllOverlaps(std::vector<cv::Rect>move_rects, cv::Rect curRect, int index)
{std::vector<int> overlaps_ID;overlaps_ID.clear();// 从move_rects中找到所有与tl br的rect重叠的框,并返回索引for (int i = 0; i < move_rects.size(); i++){if (i != index){if (isOverlap(move_rects[i].tl(), move_rects[i].br(), curRect.tl(), curRect.br()))overlaps_ID.push_back(i);else if (isCenterClose(move_rects[i], curRect))overlaps_ID.push_back(i);}}return overlaps_ID;
}
/* 合并重叠框和近邻框 */
void MergeUpdate(std::vector<cv::Rect> &move_rects)
{bool finished = false;while (!finished) // 是否还有重叠框{finished = true;//std::cout << "size of rects:" << move_rects.size() << endl;int index = move_rects.size() - 1;while (index >= 0){// 加入边界cv::Rect curRect = move_rects[index];// 获取所有重叠框的IDstd::vector<int> overlaps = getAllOverlaps(move_rects, curRect, index);if (overlaps.size() > 0) // 有重叠就合并{overlaps.push_back(index);std::vector<cv::Point2i> points;points.clear();float cenx = 0.0;float ceny = 0.0;int validNumSum = 0;for (int i = 0; i < overlaps.size(); i++){points.push_back(move_rects[overlaps[i]].tl());points.push_back(move_rects[overlaps[i]].br());}// 合并后的大框cv::Rect mergeRect = cv::boundingRect(points);// 删除合并前的所有小框:逆向排序,再删除,效率较高std::sort(overlaps.begin(), overlaps.end(), [](int &a, int &b) {return a > b; });// 获取迭代器的第一个值for (int i = 0; i < overlaps.size(); i++){std::vector<cv::Rect>::iterator iter = move_rects.begin() + overlaps[i];move_rects.erase(iter);}move_rects.push_back(mergeRect);finished = false;break;}index -= 1;} // end of inner while} // end of outer while
}
参考YACCLAB Benchmark的代码
- 主要学习点:① 学习如何测试时间开销;② 如何测试性能? correctness 《算法4》在这部分是如何做的呢?
补充
- CV_32SC1 单通道;S--int 符号整,型;U--无符号整型。
- 32位int整型的表示范围:21,4748,3647。21亿。
- 全景像素点数:1280*35=4,4800。int
补充
- 写测试代码,测试合并重叠框的程序段功能。
- opencv的include问题
- cv.hpp和opencv.hpp,cv.hpp是早期opencv版本中的定义名称;opencv.hpp是3.0版本后的表示方法
- #include <opencv2/opencv.hpp>2
- opencv.hpp里面包含了 opencv2里面的大部分头文件。
- opencv include 包含目录:opencv/opencv/build/include opencv/opencv/build/include/opencv opencv/opencv/build/include/opencv2
- opencv lib目录 库目录: opencv/opencv/bulid/x64/vc14/lib
- 链接器附加依赖项: opencv_world340d.lib
- 看懂这些配置,需要去看书籍《深入浅出计算机系统》等,里面的描述。
- 实用、实践中,学为
- 所用。
D:.
├─build
│ ├─bin
│ ├─etc
│ │ ├─haarcascades
│ │ └─lbpcascades
│ ├─include
│ │ ├─opencv
│ │ └─opencv2
│ │ ├─calib3d
│ │ ├─core
│ │ │ ├─hal
│ │ │ └─utils
│ │ ├─dnn
│ │ ├─features2d
│ │ ├─flann
│ │ ├─highgui
│ │ ├─imgcodecs
│ │ ├─imgproc
│ │ │ ├─detail
│ │ │ └─hal
│ │ ├─ml
│ │ ├─objdetect
│ │ ├─photo
│ │ ├─shape
│ │ ├─stitching
│ │ │ └─detail
│ │ ├─superres
│ │ ├─video
│ │ ├─videoio
│ │ └─videostab
下面是opencv文件夹的大概内容:
- vs2015 最常用的: CTRL + M + O折叠代码 CTRL + M + L展开代码 亲测V2015中可用,其它版本应该也可以的
- vscode 折叠代码:Ctrl+K+0; 展开代码:Ctrl+K+J
算法加速问题探讨
1. 加速的方式
- ① 算法本身的复杂度:时间、空间开销问题。
- ② Python->C++,C++和C比python快。但关键的地方还是在第一步的算法本身的复杂度上。5~20倍的这种加速还是无法满足使用要求。
- ③ 算法并行;汇编加速;硬件加速;——我不涉及这个部分
是科研人就要快!加速你的算法!_小玺玺的博客-CSDN博客_智能优化算法执行速度特别慢 如何加速
2. 算法加速
数据结构—算法时间复杂度、空间复杂度和问题规模_南笙北萧~的博客-CSDN博客_问题规模对算法效率的影响
【3】算法的时间复杂度不仅仅依赖于问题的规模,还与输入实例的初始状态有关。
算法时间影响
- ① 数据规模 O(n?) 与规模n有关系
- ② 输入输出内容,与输入输出的内容有关系
基本是两个变量;不同规模下,不同内容,导致的时间开销问题;
- ① 规模过大,导致的冗余计算?——是否可以化多为少来进行?
- ② 输入内容差异,导致的时间问题?
测试MeanshiftMerge时间开销
- 影响算法运行的因素:① 算法的实现『时间复杂度』;② 数据规模;③ 输入数据的内容
1. 如何计算算法的时间复杂度?
- ① 理论分析:通过看源代码,看循环次数,结合经验;判断该代码的时间复杂度的量级;O(N^2)? NlogN? N? logN?
- ② 测试用例测试:2倍输入规模,看时间,画出双对数图log-log图,看比率。根据幂定理:log(T(2N)/(T(N)) = b
- NlogN算法的b=2;
- N^2算法,b=2
- 使用的测试资料为:50%前景,倍增尺寸看结果。
传统目标检测后处理问题相关推荐
- 【机器学习】传统目标检测算法总结
目标检测是什么 object detection,就是在给定的图片中精确找到物体所在位置,并标注出物体的类别.所以,object detection要解决的问题就是物体在哪里以及是什么的整个流程问题. ...
- 目标检测:传统目标检测方法
文章目录 引言 什么是传统目标检测? 区域选择 特征提取 分类器 传统目标检测方法不足 引言 提到Computer Vision,可能我们会最先想到CV的基本任务Image Classificatio ...
- 目标检测 Chapter1 传统目标检测方法
文章目录 目标检测问题定义 介绍 目标检测和图像分类.图像分割的区别 目标检测问题方法 传统目标检测 深度学习目标检测 传统 Vs 深度学习 传统目标检测综述 Viola-Jones HOG+SVM ...
- 2D: 传统目标检测算法综述
一. 目标检测的发展历程 1. 2001年,V-J检测器诞生,主要用于人脸的检测: 2. 2006年,HOG + SVM的方法出现,主要用于行人的检测: 3. 2008年,rgb大神(记住这个人,后面 ...
- 目标检测后处理:从nms到softer nms
文章目录 1 NMS 1.1 动机 1.2 步骤 2 Soft-NMS 2.1 动机 2.2 算法思想 2.3 步骤 3 Softer-NMS 3.1 动机 3.1.1 现有方法的问题 3.1.2 本 ...
- 【机器学习】传统目标检测算法之HOG
转载+理解:hog:https://www.cnblogs.com/wyuzl/p/6792216.html hog:https://blog.csdn.net/masibuaa/article/de ...
- 目标检测(三)传统目标检测与识别的特征提取——基于HOG特征的目标检测原理
目录 简介 提取HOG特征的步骤 1.预处理获取要计算其特征的输入图像 2.计算图像的梯度 3.计算8×8细胞梯度直方图 4.直方图归一化 5.计算HOG特征向量 Opencv利用HOG特征实现行人检 ...
- 【机器学习】传统目标检测算法之DPM
前面介绍了一下HOG,HOG有一个缺点:很难处理遮挡问题,人体姿势动作幅度过大或物体方向改变也不易检测. 继2005年HOG提出之后,DPM模型在借鉴了HOG之后也被提了出来同时还取得了不错的成绩. ...
- 【机器学习】传统目标检测算法之级联分类器Cascade
先附上参考文章吧. 文章其实是"P. Viola, M. Jones. Rapid Object Detection using a Boosted Cascade of Simple Fe ...
最新文章
- linux 内核位置无关,Linux内核启动阶段虚实地址映射
- MySQL系列:innodb源代码分析之线程并发同步机制
- can bus 中spn是什么_CP AUTOSAR功能栈简介NM网络管理(Can)
- spark里的hbase的ImmutableBytesWritable的打印问题scala
- 【转】ABP源码分析十六:DTO的设计
- 父亲节——女儿的礼物
- [置顶]c# 设计模式(2)结构型
- 编译原理 语法分析程序
- 百度AI开放平台文字之身份证识别的实现
- Android 调用免费短信验证码sdk开发
- js高级--jsonp跨域
- Cookie、Session 简述
- 在百度地图上展示dwg/dxf
- 思考分析常用思维模型
- javaee图书管理系统mysql,图书管理系统设计与实现—看这篇就够了
- foobar2000-new
- java-net-php-python-jspm早教中心系统查重PPT计算机毕业设计程序
- [日推荐]『质安查』买到放心的产品就靠它了
- Auto-Icon:一款自动代码生成工具 | 开发​工程师必备
- 多个vue项目生产环境下NGINX配置文件
热门文章
- MATLAB数字图像处理复习概览
- 总结word2vec
- 反黑风暴·记一次遭遇 SSDP DDoS 和 EternalBlue(永恒之蓝)攻击经历
- 2021辽宁高考成绩查询具体时间,2021年辽宁高考成绩什么时候出具体时间几点 具体准确时间...
- Linux系统中的文件系统格式区别及详解
- java代码实现声纹识别_govpr--golang实现的gmm-ubm算法的说话人识别(声纹识别)引擎...
- ​单张图像三维人脸重建必备入门face3d—3DMM
- oracle clustered索引,数据库表--index clustered table
- html中map标签的用法,HTML中的map和area标签
- restrict关键字用法