美文网首页
CV进阶操作【5】——基于直方图的目标跟踪(target tra

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

作者: Mr_Relu | 来源:发表于2019-05-12 10:03 被阅读0次

编程环境:

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

相关文章

网友评论

      本文标题:CV进阶操作【5】——基于直方图的目标跟踪(target tra

      本文链接:https://www.haomeiwen.com/subject/xhgqaqtx.html