C C++最全【OpenCV】“帧差法”实现移动物体的检测(车辆识别(1),C C++高级开发面试题

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

int main(int argc, char *argv[])
{
    Mat frame;

    VideoCapture cap("D:/QT-Project/image/carMove.mp4");
    while(cap.read(frame))
    {
        //读取一帧显示一帧
        imshow("frame", frame);

        //延时
        waitKey(25);
    }
    return 0;
}

2、灰度处理+帧差计算

  • 为了提高计算机的运算速度,图像处理前一般将图像转成灰度图

因为彩色图片是3通道(RGB)24位深度的图像,而灰度图是单通道8位深度的图像,因此处理灰度图比彩色图效率快多了。

  • frontMat为前一帧,afterMat为后一帧
//灰度处理
cvtColor(frontMat, frontGray, CV_BGR2GRAY);
cvtColor(afterMat, afterGray, CV_BGR2GRAY);

//帧差处理 找到帧与帧之间运动的物体差异
absdiff(frontGray, afterGray, diffGray);
  • 效果:原图(左)、处理后(右)

通过下图可以发现检测是检测出来了,但是画面非常的暗淡(不清晰),因此需要通过二值化来让图像更清晰点。

3、二值化

  • 通过threshold函数将图像二值化

参数一为原图,参数二为处理后的图,直接将处理后的图覆盖掉原图即可

//二值化:黑白分明 会产生大量白色噪点
threshold(diffGray, diffGray, 25, 255, CV_THRESH_BINARY);
  • 下面是二值化处理过后的效果

可以发现图像确实是变“清晰”了,因为二值化后的图像只有黑白两种颜色。并且我们还可以发现白色噪点非常多,因为摄像机抖动,风吹树叶等原因,因此还需要通过腐蚀来去除掉这些白色噪点。

4、腐蚀

  • 概念

腐蚀是针对图片的二值化数据进行操作的,主要是针对高亮部分。使用算法,将图像的边缘腐蚀掉。作用就是将目标的边缘的“毛刺”踢除掉。

如下图所示:

  • 通过erode函数将图像进行腐蚀
//腐蚀处理:去除白色噪点 噪点不能完全去除,反而主要物体会被腐蚀的图案都变得不明显
Mat element = cv::getStructuringElement(MORPH_RECT, Size(3, 3));
erode(diffGray, diffGray, element);
  • 下面是腐蚀之后的效果

😧白色噪点确实是被去除了,但是我们的车辆也被腐蚀的不成车样(内部坑坑洼洼的),所以还需要通过膨胀将车辆进行进一步处理。

5、膨胀

  • 概念

膨胀是针对图片的二值化数据进行操作的,主要是针对高亮部分。使用算法,将图像的边缘扩大些。作用就是将目标的边缘或者是内部的坑填掉。

如下图所示:

  • 通过dilate函数将图像进行膨胀
//膨胀处理:将白色区域变“胖”
Mat element2 = cv::getStructuringElement(MORPH_RECT, Size(20, 20));

dilate(diffGray, diffGray, element2);
  • 下面是膨胀之后的效果

我们的车辆变成一个个大方块了,做到这一步差不多就可以来标记运动的车辆了,只要画矩形将白色大方块框起来即可。

6、框选出车辆

  • 下面是用白色的框框,框选出来的效果

框选的原理就是找到白色方块最左边的点与最右边的点,得到之间的大小差距(矩形宽),找到白色方块最上边的点与最下边的点,得到之间的大小差距(矩形高)。

通过宽高即可画出一个把白色方块包含在内的矩形,矩形左上角坐标通过白色方块最上方的值和最左方的值来确定。

  • 我们只要将白色方框改个显眼的颜色,并在原视频的对应位置画出这个框框即可。下面附全部代码。

三、全部代码+实现效果

1、代码

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

//帧差法检测车辆
Mat MoveCheck(Mat &frontMat, Mat &afterMat)
{
    Mat frontGray ,afterGray, diffGray;
    Mat resframe = afterMat.clone();
    //灰度处理
    cvtColor(frontMat, frontGray, CV_BGR2GRAY);
    cvtColor(afterMat, afterGray, CV_BGR2GRAY);
    //imshow("GRAY", frontGray);

    //帧差处理 找到帧与帧之间运动的物体差异
    //缺点:会把其他运动物体也算进来
    absdiff(frontGray, afterGray, diffGray);
    //imshow("absdiff", diffGray);

    //二值化:黑白分明 会产生大量白色噪点
    threshold(diffGray, diffGray, 25, 255, CV_THRESH_BINARY);
    //imshow("diff", diffGray);

    //腐蚀处理:去除白色噪点 噪点不能完全去除,反而主要物体会被腐蚀的图案都变得不明显
    Mat element = cv::getStructuringElement(MORPH_RECT, Size(3, 3));
    erode(diffGray, diffGray, element);
    //imshow("erode", diffGray);

    //膨胀处理:将白色区域变“胖”
    Mat element2 = cv::getStructuringElement(MORPH_RECT, Size(20, 20));
    dilate(diffGray, diffGray, element2);
    //imshow("dilate", diffGray);

    //动态物体标记
    vector<vector<Point>> contours; //保存关键点
    findContours(diffGray, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    //提取关键点
    vector<vector<Point>> contours_poly(contours.size());
    vector<Rect> boundRect(contours.size());

    int x, y, w, h;
    int num = contours.size();

    for(int i =0; i< num; i++)
    {
        approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);
        boundRect[i] = boundingRect(Mat(contours_poly[i]));

        x = boundRect[i].x;
        y = boundRect[i].y;
        w = boundRect[i].width;
        h = boundRect[i].height;

        //绘制
        rectangle(resframe, Point(x, y), Point(x+w, y+h), Scalar(0, 255, 0), 4);
    }
    return resframe;
}

int main(int argc, char *argv[])
{
    Mat frame;
    Mat tempframe;
    Mat res;
    int count = 0;

    VideoCapture cap("D:/QT-Project/image/carMove.mp4");
    while(cap.read(frame))
    {
        count++;
        if(count == 1)
        {
            res = MoveCheck(frame, frame);
        }
        else
        {
            res = MoveCheck(tempframe, frame);


![img](https://img-blog.csdnimg.cn/img_convert/421dd893bd3b302baa3751466efb1408.png)
![img](https://img-blog.csdnimg.cn/img_convert/1d02eb57337fc42187a2bd0f324ef2c4.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

...(img-G3Fi8yFT-1715701999359)]
[外链图片转存中...(img-STFU0vMB-1715701999359)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 25
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
差法是一种简单有效的运动目标检测方法,可以通过比较相邻的三图像像素值的差异来检测运动物体。下面是基于C++OpenCV4.6实现差法的步骤: 1. 读取视频并初始化三个Mat对象:currentFrame, previousFrame和nextFrame。 ```c++ VideoCapture capture("video.mp4"); Mat currentFrame, previousFrame, nextFrame; capture >> previousFrame; capture >> currentFrame; capture >> nextFrame; ``` 2. 将转换为灰度图像,以便进行差分计算。 ```c++ cvtColor(previousFrame, previousFrame, COLOR_BGR2GRAY); cvtColor(currentFrame, currentFrame, COLOR_BGR2GRAY); cvtColor(nextFrame, nextFrame, COLOR_BGR2GRAY); ``` 3. 计算相邻之间的差异,并将其存储在Mat对象中。 ```c++ Mat diff1, diff2; absdiff(previousFrame, currentFrame, diff1); absdiff(currentFrame, nextFrame, diff2); ``` 4. 对两个差分图像进行二值化处理,以便提取物体的运动。 ```c++ threshold(diff1, diff1, 30, 255, THRESH_BINARY); threshold(diff2, diff2, 30, 255, THRESH_BINARY); ``` 5. 将两个二值化的图像进行逻辑与运算,以便提取出物体移动区域。 ```c++ Mat motionMask; bitwise_and(diff1, diff2, motionMask); ``` 6. 对运动区域进行形态学处理,以便去除噪声并填充空洞。 ```c++ Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3)); morphologyEx(motionMask, motionMask, MORPH_OPEN, kernel); morphologyEx(motionMask, motionMask, MORPH_CLOSE, kernel); ``` 7. 显示运动区域,并等待按下任意键退出程序。 ```c++ imshow("Motion Mask", motionMask); waitKey(0); ``` 完整的代码如下所示: ```c++ #include <opencv2/opencv.hpp> using namespace cv; int main() { VideoCapture capture("video.mp4"); Mat currentFrame, previousFrame, nextFrame; capture >> previousFrame; capture >> currentFrame; capture >> nextFrame; cvtColor(previousFrame, previousFrame, COLOR_BGR2GRAY); cvtColor(currentFrame, currentFrame, COLOR_BGR2GRAY); cvtColor(nextFrame, nextFrame, COLOR_BGR2GRAY); while (true) { Mat diff1, diff2; absdiff(previousFrame, currentFrame, diff1); absdiff(currentFrame, nextFrame, diff2); threshold(diff1, diff1, 30, 255, THRESH_BINARY); threshold(diff2, diff2, 30, 255, THRESH_BINARY); Mat motionMask; bitwise_and(diff1, diff2, motionMask); Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3)); morphologyEx(motionMask, motionMask, MORPH_OPEN, kernel); morphologyEx(motionMask, motionMask, MORPH_CLOSE, kernel); imshow("Motion Mask", motionMask); char key = waitKey(1); if (key == 27) break; previousFrame = currentFrame; currentFrame = nextFrame; capture >> nextFrame; if (nextFrame.empty()) break; cvtColor(nextFrame, nextFrame, COLOR_BGR2GRAY); } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值