zoukankan      html  css  js  c++  java
  • opencv车流量统计算法

    #include "cv.h"
    #include <cxcore.h>
    #include <highgui.h>
    #include <cvaux.h>//必须引此头文件
    #include "opencv2/imgproc/imgproc.hpp"
    typedef uchar byte;
    #define QUEUE_MAX_SIZE 100
    #define RANGE  5
    #define UPDATE_RATE  (0.01)
    #define  RATIO_QUEUE_LEN 1000
    typedef unsigned int uint32;
    #define MIN(x,y) (x>y?y:x)
    
    int g_QueueSize=10;
    int threshold=20;
    int g_CarWidth=10;//车的宽和高
    int g_CarHeight=10;
    int g_CarArea=20;//检测的范围
    int g_Erosion_kernel_size=3;
    int g_Dilation_kernel_size=3;
    struct PIXEL_RECORD
    {
        byte   PX_data;
        uint32 PX_count;
    };
    
    struct QUEUE
    {
        struct RECORD
        {
            double ratio;
            uint64 count;
        }record [RATIO_QUEUE_LEN];
    
        int     curPos;
        double MostRatio;
    
    };
    struct RECORD
    {
        PIXEL_RECORD queue[QUEUE_MAX_SIZE];
        uint32 CurPos;//the postion of last element in queue; 
    
    };
    
    void QUEUE_init(QUEUE* queue)
    {
        for (int i=0;i<RATIO_QUEUE_LEN;i++)
        {
            queue->record[i].ratio=0.0;
            queue->record[i].count=0;
    
        }
        queue->curPos=0;
        queue->MostRatio=0.0;
    }
    double UpatePixelRatio(QUEUE& queue,double ratio)
    {
    
        int i=0;
        int MinPos=0;
        int MaxPos=0;
        for (;i<RATIO_QUEUE_LEN;i++)
        {
            if(queue.record[i].ratio  ==  ratio)
            {
                queue.record[i].count++;
                break;
            }
    
        }
        if (i==RATIO_QUEUE_LEN)
        {
            if(queue.curPos<RATIO_QUEUE_LEN)
            {
                queue.record[queue.curPos++].ratio=ratio;
            }
            if(queue.curPos== RATIO_QUEUE_LEN)
            {
                uint32 MinCount=0xFFFFFFFF;
                for(int j=0;j<queue.curPos;j++)
                {
                    if(queue.record[j].count<MinCount)
                    {
                        MinPos=j;
                        MinCount=queue.record[j].count;
                    }
                }
                queue.record[MinPos].ratio=ratio;
            }
        }
        uint32 MaxCount=0;
        for (int j=0;j<RATIO_QUEUE_LEN;j++)
        {
            if (queue.record[j].count>MaxCount)
            {
                MaxCount=queue.record[j].count;
                MaxPos=j;
            }
        }
        return queue.record[MaxPos].ratio;
    }
    uint32 GetMaxValueData(const PIXEL_RECORD* arr,int len)
    {
        uint32 tmp=0;
        uint32 MaxPos=0;
        for (int i=0;i<len-1;i++)
        {
            if(arr[i].PX_count>tmp)
            {
                tmp=arr[i].PX_count;
                MaxPos=i;
            }
        }
        return arr[MaxPos].PX_data;
    }
    
    uint32 GetMinValuePos(const PIXEL_RECORD* arr,int len)
    {
        byte tmp=255;
        uint32 MinPos=g_QueueSize;
        for (int i=0;i<len-1;i++)
        {
            if(arr[i].PX_count<tmp)
            {
                tmp=arr[i].PX_count;
                MinPos=i;
            }
        }
        return MinPos;
    }
    
    byte UpdateQueue(RECORD* record,byte Vpixel,uint32 nFrm)
    {
        PIXEL_RECORD tmp;
        int i=0;
        double UpdateRate;
        for (;i<g_QueueSize;i++)
        {
    
            if ((record->queue[i].PX_data)/RANGE  == Vpixel/RANGE )
            {
                record->queue[i].PX_count++;
                record->queue[i].PX_data=(record->queue[i].PX_data)*(1-UPDATE_RATE)+Vpixel*UPDATE_RATE;
    
            }
        }
        if (i==g_QueueSize)
        {
            if (record->CurPos < g_QueueSize)
            {
                record->queue[record->CurPos++].PX_data=Vpixel;
            }
            else 
            {
                uint32 Pos=GetMinValuePos(record->queue,record->CurPos);
                record->queue[Pos].PX_data=Vpixel;
            }
    
        }
        return  GetMaxValueData(record->queue,record->CurPos);
    } 
    
    void RecordFrame(IplImage* pFrame,IplImage* pBKImg ,const int nFrm,RECORD* pRecordMap,QUEUE& PX_queue)
    {
        IplImage* pFrmGrayImg=NULL;
        pFrmGrayImg=cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);
        if(pFrame->colorModel != CV_8U && pFrame->nChannels != 1)
        {
            cvCvtColor(pFrame,pFrmGrayImg,CV_BGR2GRAY);
        }
        else
            pFrmGrayImg=pFrame;
    
        uint32 ROW=pFrmGrayImg->width;
        uint32 COL=pFrmGrayImg->height;
    
        for (uint32 i=0;i<ROW*COL;i++)
        { 
            pBKImg->imageData[i]=UpdateQueue(pRecordMap+i,pFrmGrayImg->imageData[i], nFrm);
    
        }
    
    }
    
    void TouchTag(int* buf,int ROW,int COL,int& ctag,int x,int y)
    {
        int  tag=ctag;
        bool mark=0;
        for (int i=-1;i<2;i++) 
        {
    
            for (int j=-1;j<2;j++)
            {
    
                if (buf[(x+i)*COL+(y+j)]>0)
                {
                    tag= MIN(buf[(x+i)*COL+(y+j)],tag);
                    mark=1;
                }
            }
        }
        if(mark==0)
        {
            ctag++;
            tag=ctag;
        }
        buf[x*COL+y]=tag;
    }
    
    size_t DetectRect(CvMat* Img,int* buf)
    {
        uint32 ROW=Img->rows;
        uint32 COL=Img->cols;
        int cTag=0;
        for (int i=1;i<ROW -1;i++)//! 图像中的横轴为X轴,即为列坐标
        {
            for (int j=1;j<COL-1;j++)
            {
                if(*(byte*)(CV_MAT_ELEM_PTR(*Img,i,j)) == 255)
                {
                    TouchTag(buf,ROW,COL,cTag,i,j);
                }
            }
        }
    
    
        return cTag;
    }
    
    struct TAG_RECORD
    {
        uint32 MinX;
        uint32 MaxX;
        uint32 MinY;
        uint32 MaxY;
        uint32 count;
    };
    void GetRect(std::vector<TAG_RECORD>& TagArry,size_t cTag,int* buf,uint32 ROW,uint32 COL)
    {
        for (size_t i=0;i<TagArry.size();i++)
        {
            TagArry[i].MaxX=0;
            TagArry[i].MaxY=0;
            TagArry[i].MinX=COL;
            TagArry[i].MinY=ROW;
            TagArry[i].count=0;
        }
        int index=0;
        for (int i=0;i<ROW;i++)
        {
            for (int j=0;j<COL;j++)
            {
                index=buf[i*COL+j];
                if (index>0 && index<TagArry.size())
                {
                    TagArry[index].count++;
                    if (i<TagArry[index].MinY)
                    {
                        TagArry[index].MinY=i;
                    }
                    if(i>TagArry[index].MaxY)
                    {
                        TagArry[index].MaxY=i;
                    }
                    if (j<TagArry[index].MinX)
                    {
                        TagArry[index].MinX=j;
                    }
                    if (j>TagArry[index].MaxX)
                    {
                        TagArry[index].MaxX=j;
                    }
                }
    
            }
        }
    
    }
    
    void onTrackbarSlide(int)
    {
    
    }
    int main()
    {
    
        //声明IplImage指针
        IplImage* pFrame = NULL; 
        IplImage* pFrImg = NULL;
        IplImage* pBkImg = NULL;
        CvMat* pDiff =NULL;
        CvMat* pFrameMat = NULL;
        CvMat* pFrMat = NULL;
        CvMat* pBkMat = NULL;
        RECORD* pRecordMap=NULL;
        int* TagMap=NULL;
        CvCapture* pCapture = NULL;
        CvRect FrRect;
        int nFrmNum = 0;
        int ncount=0;
        QUEUE PX_queue;
        size_t  RecordSize;
        int ROW;
        int COL;
        //! 文字输出
        CvFont font;
        char str[20]="flow:";
        double hscale = 0.6;
        double vscale = 0.6;
        int linewidth = 1;
        double flow;
        char  ncar[20]="cars:";
        char  nframe[20]="frames:";
        char sframeRate[30]="[FPS]:";
        //创建窗口
        cvNamedWindow("video", 1);
        cvNamedWindow("background",1);
        cvNamedWindow("foreground",1);
        //使窗口有序排列
        cvMoveWindow("video", 30, 0);
        cvMoveWindow("background", 360, 0);
        cvMoveWindow("foreground", 690, 0);
    
        char* filename="d:\test.mp4";
        //打开视频文件
    
        if( !(pCapture = cvCaptureFromFile(filename)))
        {
            fprintf(stderr, "Can not open video file %s
    ", filename);
            return -2;
        }
    
        QUEUE_init(&PX_queue);
    
        double framesRate=cvGetCaptureProperty(pCapture,CV_CAP_PROP_FPS);
        int frames=cvGetCaptureProperty(pCapture,CV_CAP_PROP_FRAME_COUNT);
    
    
        cvCreateTrackbar("QueueSize","background", &g_QueueSize, QUEUE_MAX_SIZE,onTrackbarSlide);
        cvCreateTrackbar("CarWiedth","video", &g_CarWidth, 150,onTrackbarSlide);
        cvCreateTrackbar("CarHeight","video", &g_CarHeight, 150,onTrackbarSlide);
        cvCreateTrackbar("CarArea","video", &g_CarArea, 200,onTrackbarSlide);
        cvCreateTrackbar("Threshold","foreground", &threshold, 255,onTrackbarSlide);
        cvCreateTrackbar("dilate","foreground", &g_Dilation_kernel_size, 20,onTrackbarSlide);
        cvCreateTrackbar("erode","foreground", &g_Erosion_kernel_size, 20,onTrackbarSlide);
        //逐帧读取视频
        while(pFrame = cvQueryFrame( pCapture ))
        {
            nFrmNum++;
    
            //如果是第一帧,需要申请内存,并初始化
            if(nFrmNum == 1)
            {
    
                pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);
                pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);
                pDiff  =cvCreateMat(pFrame->height, pFrame->width, CV_8U);
                pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
                pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
                pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
                ROW=pDiff->rows;
                COL=pDiff->cols;
                //转化成单通道图像再处理
                cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
                RecordSize=pFrame->width * pFrame->height;
                pRecordMap=new RECORD[RecordSize];
                TagMap=new int[RecordSize];
    
                for (int i=0;i<RecordSize;i++)  //init
                {
                    for (int j=0;j<g_QueueSize;j++)
                    {
    
                        pRecordMap[i].queue[j].PX_count=0;
                        pRecordMap[i].queue[j].PX_data=0;
                        pRecordMap[i].CurPos=0;
                    }
                }
    
                cvConvert(pFrImg, pFrameMat);
                cvConvert(pBkImg, pBkMat);
    
            }
            else
            {
    
    
                cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
                cvSmooth(pFrImg, pFrImg, CV_GAUSSIAN, 3, 0, 0);
    
    
                RecordFrame(pFrImg,pBkImg,nFrmNum,pRecordMap,PX_queue);
    
    
                //高斯滤波先,以平滑图像
                cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0);
    
                //当前帧跟背景图相减
                cvAbsDiff(pFrImg, pBkImg, pDiff);
    
                //二值化前景图
                cvThreshold(pDiff, pDiff, threshold, 255, CV_THRESH_BINARY);
                //进行形态学滤波,去掉噪音  
    
                IplConvKernel* element_erode=cvCreateStructuringElementEx(g_Erosion_kernel_size + 1, g_Erosion_kernel_size+1,
                    g_Erosion_kernel_size/2, g_Erosion_kernel_size/2, 0);
    
                IplConvKernel*  element_dilate = cvCreateStructuringElementEx(g_Dilation_kernel_size + 1, g_Dilation_kernel_size+1,
                    g_Dilation_kernel_size/2, g_Dilation_kernel_size/2, 0);
    
                //! 腐蚀操作
                cvErode( pDiff, pDiff, element_erode );
    
    
                /// 膨胀操作
                cvDilate( pDiff, pDiff, element_dilate );
    
                //             cvErode(pDiff, pDiff, 0, 1);
                //             cvDilate(pDiff, pDiff, 0, 1);
                //          
    
                for (int i=0;i<RecordSize;i++) 
                {
                    TagMap[i]=0;
                }
    
                size_t cTag=DetectRect(pDiff,TagMap);
                TAG_RECORD tmp;
    
                tmp.MinX=pDiff->cols;
                tmp.MinY=pDiff->rows;
                tmp.MaxX=0;
                tmp.MaxY=0;
                std::vector<TAG_RECORD> TagRecord(cTag+1,tmp);      
    
                GetRect(TagRecord,cTag,TagMap,pDiff->rows,pDiff->cols);
                ncount=0;
                for (size_t i=1;i<TagRecord.size();i++)
                {
    
                    if (TagRecord[i].count<g_CarArea)
                    {
                        continue;
                    }
    
                    int MinX=TagRecord[i].MinX;
                    int MinY=TagRecord[i].MinY;
                    int MaxX=TagRecord[i].MaxX;
                    int MaxY=TagRecord[i].MaxY;
    
                    if (MaxX-MinX<g_CarWidth || MaxY-MinY<g_CarHeight)
                    {
                        continue;
    
                    }
                    ncount++;
                    cvRectangle( pFrame, cvPoint(MinX,MinY), cvPoint(MaxX,MaxY), CV_RGB(255,0,0), 1, 8, 0 );
    
                }  
    
                flow=framesRate*ncount/(double)nFrmNum;
    
                sprintf(nframe+7,"%d",nFrmNum);
                sprintf(ncar+5,"%d",ncount);
                
                sprintf(str+5,"%f",flow);
                sprintf(sframeRate+6,"%f",framesRate);
    
                cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX | CV_FONT_ITALIC,hscale,vscale,0,linewidth);
                cvPutText(pFrame,sframeRate,cvPoint(0,15),&font,cvScalar(0,0,0)); 
                cvPutText(pFrame,ncar,cvPoint(0,35),&font,cvScalar(0,0,0)); 
                cvPutText(pFrame,nframe,cvPoint(0,55),&font,cvScalar(0,0,0)); 
    
                cvPutText(pFrame,str,cvPoint(0,75),&font,cvScalar(0,0,0));            
                //显示图像
                cvShowImage("video", pFrame);
                cvShowImage("background", pBkImg);
                cvShowImage("foreground", pDiff);
    
    
                //如果有按键事件,则跳出循环
                //此等待也为cvShowImage函数提供时间完成显示
                //等待时间可以根据CPU速度调整
                if( cvWaitKey(2) >= 0 )
                    break;
    
    
            }
    
        }
    
        cvWaitKey();
    
    
        //销毁窗口
        cvDestroyWindow("video");
        cvDestroyWindow("background");
        cvDestroyWindow("foreground");
    
        //释放图像和矩阵
        cvReleaseImage(&pFrImg);
        cvReleaseImage(&pBkImg);
    
        cvReleaseMat(&pFrameMat);
        cvReleaseMat(&pFrMat);
        cvReleaseMat(&pBkMat);
    
        cvReleaseCapture(&pCapture);
        delete[] pRecordMap;
        delete[] TagMap;
        return 0;
    }
  • 相关阅读:
    Windows关于文件句柄数的限制
    python 的未来5-10年的就业方向
    想着给要做的软件起一个名儿~
    sql server 特殊sql
    字节序之大小端_Intelx86是小端_网络传输是大端
    维基百科Wikipedia镜像网站列表
    NodeJS开启GZIP功能
    SqlServer2008 跨服务器同步数据
    Asp.net中的ViewState用法
    JAVA Netty入门Demo实例代码(自写测试可用)实现客户端服务器端互传数据
  • 原文地址:https://www.cnblogs.com/mengxingxinqing/p/3791266.html
Copyright © 2011-2022 走看看