CV进阶操作【5】——基于直方图的目标跟踪(target tracing baced histogram)

编程环境:

VS + OpenCV + C++
完整代码已经更新至GitHub,欢迎fork~GitHub链接


声明:创作不易,未经授权不得复制转载
statement:No reprinting without authorization


内容:

• 实现基于直方图的目标跟踪:已知第t帧目标的包围矩形,计算第t+1帧目标的矩形区域。
• 选择适当的测试视频进行测试:给定第1帧目标的矩形框,计算其它帧中的目标区域。

一、图像直方图的获取与表示

        本来打算自己一个数据结构将直方图表示为256*3(彩色图片)的向量,但在计算两个直方图的相似度时发现不好操作,而且精确度太低,于是采用了opencv提供的函数cv::calcHist来计算直方图,而后可以进行可视化,主要代码如下:

    //计算图像的直方图(红色通道部分)
    cv::calcHist(&rectImage, nimages, &channels[0], cv::Mat(), outputHist_red, dims, &histSize[0], &ranges[0], uni, accum);
    //计算图像的直方图(绿色通道部分)
    cv::calcHist(&rectImage, nimages, &channels[1], cv::Mat(), outputHist_green, dims, &histSize[1], &ranges[1], uni, accum);
    //计算图像的直方图(蓝色通道部分)
    cv::calcHist(&rectImage, nimages, &channels[2], cv::Mat(), outputHist_blue, dims, &histSize[2], &ranges[2], uni, accum);

for (int i = 0; i < histSize[0]; i++)
    {
        float value_red = outputHist_red.at<float>(i);
        float value_green = outputHist_green.at<float>(i);
        float value_blue = outputHist_blue.at<float>(i);
        //分别画出直线
        cv::line(histPic, cv::Point(i*scale, histSize[0]), cv::Point(i*scale, histSize[0] - value_red * rate_red), cv::Scalar(0, 0, 255));
        cv::line(histPic, cv::Point((i + 256)*scale, histSize[0]), cv::Point((i + 256)*scale, histSize[0] - value_green * rate_green), cv::Scalar(0, 255, 0));
        cv::line(histPic, cv::Point((i + 512)*scale, histSize[0]), cv::Point((i + 512)*scale, histSize[0] - value_blue * rate_blue), cv::Scalar(255, 0, 0));
    }
    cv::imshow("histgram", histPic);

效果如下:

image.png

image.png

二、如何动态的通过交互来框出目标物体

        主要利用的鼠标的回调函数void onMouse以及Rect(Point, Point)和画矩形函数rectangle来实现,先打开原视频,鼠标点击后暂停播放,记录矩形框的起点,鼠标抬起后记录第二个点,两个对角点围成的即为框出的目标图形:

targetImage = image(Rect(originalPoint, processPoint));
//获取目标图像targetImage

        上诉部分通过getStart函数实现,然后采用H-S直方图进行处理,首先得配置直方图的参数,进行原图直方图的计算,然后归一化后传入计算,得到目标的可以进行相似度比较的直方图MatND srcHist;

Mat srcHsvImage;
cvtColor(targetImage, srcHsvImage, CV_BGR2HSV);
//采用H-S直方图进行处理
//首先得配置直方图的参数
MatND srcHist;
//进行原图直方图的计算
calcHist(&srcHsvImage, 1, channels, Mat(), srcHist, 2, histSize, ranges, true, false);
//归一化
normalize(srcHist, srcHist, 0, 1, NORM_MINMAX);

三、如何对于下一帧的图片进行区域检索和直方图比较(重点)

        首先由于之前的交互得到的矩形框的大小,而且视频的大小尺寸不会变,根据一般事实可知,物体一般的移动都是渐变的,即其未来出现的区域不会离原来的矩形框区域太远,所以可以在矩形框周围选定适当的区域进行直方图相似度匹配搜索,经过调试后发现将区域改为(3width)X(3height)时效果会更好。
        在划定区域内保持矩形框大小不变进行左右上下的二重循环遍历,将“框”出的测试图片compareImg进行同样的操作而后得到其直方图,最后利用opencv的直方图比较函数compHist,将其与目标进行比较,Opencv提供的比较方法有四种:

  • Correlation 相关性比较
  • Chi-Square 卡方比较
  • Intersection 十字交叉性
  • Bhattacharyya distance 巴氏距离
    巴氏距离计算公式:
    image.png

    测试发现第四中巴氏距离效果要好一些,因此设计函数compHist(const MatND srcHist,Mat compareImage)完成比较并返回秒速相似度的值,值越小表示越相似,为0时表示相同。

四、效率问题

        实验发现将矩形框进行加1平移,会大大增加计算量(视频会很卡顿),很难做到实时的对目标跟踪的效果,可以调整平移的步数,有两种方案,一是将左右和上下平移的步数设为矩形框的宽或高的若干分之一,或者将其设为较大一点的固定值,都能够增加效率,遍历区域不断比较直方图得到相似值comnum,取最小的相似值时的检测图片,框出矩形框进行显示,另外对代码可以进一步重构优化。矩形框操作核心代码如下:(注意越界检查)

for (int Cy = Y1; Cy <= Y2; Cy += 10) {
        for (preStart.x = X1, preStart.y = Cy; preStart.x <= X2; preStart.x += 10) {
                if ((preStart.x + width) < image.cols)
                    preEnd.x = preStart.x + width;
                else
                    preEnd.x = image.cols - 1;
                if ((preStart.y + height) < image.rows)
                    preEnd.y = preStart.y + height;
                else
                    preEnd.y = image.rows - 1;
                Mat compareImg;
                compareImg = image(Rect(preStart, preEnd));
                double c = compHist(srcHist, compareImg);
                if (comnum > c) {
                    get1 = preStart;
                    get2 = preEnd;
                    comnum = c;
                }
        }
}

五、标记显示和初始位置更新问题

        由于物体是在运动的,所以需要更新计算区域的坐标位置,并且可以和直方图的比较相似度相结合,但检测区域和目标图像很接近时便更新矩形框到该位置,而且但相似度的值大于一定阀值后可断定目标被跟丢,不显示矩形框。代码如下:

//在原始视频图像上刷新矩形,只有当与目标直方图很相似时才更新起点搜索区域,满足目标进行移动的场景
        if (comnum < 0.15) {
            X1 = get1.x - width;
            X2 = get1.x + width;
            Y1 = get1.y - height;
            Y2 = get1.y + height;
            if (X1 < 0)
                X1 = 0;
            if (Y1 < 0)
                Y1 = 0;          
        }
        if(comnum<0.5)
            rectangle(image, get1, get2, Scalar(0, 0, 255), 2);

六、效果展示

处理好的视频截图如下:视频链接(可以观看上传的压缩包内的c502_test.mp4、c503_test.mp4、c504_test.mp4、c505_test.mp4视频)

image.png

image.png

image.png

经过测试后发现,对于目标姿态改变较小的并且在图像中大小变化不大的目标物体,能够保证有较高的识别追踪准确率。但是对于姿态变化和一些干扰较敏感。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,548评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,497评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,990评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,618评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,618评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,246评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,819评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,725评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,268评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,356评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,488评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,181评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,862评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,331评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,445评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,897评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,500评论 2 359

推荐阅读更多精彩内容