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\n", 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;
}

 

posted @ 2014-06-16 16:50  梦醒心晴  Views(4686)  Comments(6Edit  收藏  举报