您的位置:首页 > 运维架构

【OpenCV】图像代数运算:平均值去噪,减去背景

2016-05-07 09:38 686 查看
代数运算,就是对两幅图像的点之间进行加、减、乘、除的运算。四种运算相应的公式为:



代数运算中比较常用的是图像相加和相减。图像相加常用来求平均值去除addtive噪声或者实现二次曝光(double-exposure)。图像相减用于减去背景或周期噪声,污染等。


图像相加

OpenCV中提供了相加的函数

[cpp] view
plain copy

void cvAcc(   

           const CvArr* image,//输入图像  

           CvArr* sum,  //累积图像   

           const CvArr* mask=NULL//可选的运算  

 );  

我们还需要用到一个线性变换转换函数来对相加的结果求平均

[cpp] view
plain copy

void cvConvertScale(   

        const CvArr* src, //输入数组  

        CvArr* dst,//输出数组  

        double scale=1,//比例  

        double shift=0 //缩放比例,可选  

);  

#define cvCvtScale cvConvertScale  

#define cvScale  cvConvertScale  

#define cvConvert( src, dst )  cvConvertScale( (src), (dst), 1, 0 )  


实践:平均值去噪

我们用NASA的一段幸运团的视频做实验,截取视频的某几个连续帧求平均值:

[cpp] view
plain copy

int main()  

{  

    CvCapture* capture=cvCaptureFromFile("media.avi");  

    IplImage* frame=  NULL;  

    IplImage * imgsum =NULL;  

      

    int start=301;  

    int end=304;  

    cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, start);  

      

    int count = start;  

    while( cvGrabFrame(capture) && count <= end )  

    {  

        frame = cvRetrieveFrame(capture);// 获取当前帧  

        if(imgsum==NULL){  

            imgsum=cvCreateImage(cvGetSize(frame),IPL_DEPTH_32F,3);  

            cvZero(imgsum);  

        }  

        cvAcc(frame,imgsum);  

  

        char testname[100];  

        sprintf(testname,"%s%d%s","image",count,".jpg");  

        cvShowImage(testname,frame);  

        cvSaveImage(testname,frame);  

          

        count++;  

    }  

    IplImage * imgavg = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,3);  

    cvConvertScale(imgsum,imgavg,1.0/4.0);  

      

    cvShowImage("imageavg",imgavg);  

    cvSaveImage("imageavg_4.jpg",imgavg);  

      

    cvWaitKey(0);  

    cvReleaseCapture(&capture);  

    return 0;  

}  

以下从左到右分别是连续两帧、四帧、八帧、十六帧求均值的结果:


   



   



实践:图像二次曝光

曝光和去噪是一样的,也是对几幅图像求平均

[cpp] view
plain copy

//通过求平均二次曝光  

int main()  

{  

    IplImage* image1=  cvLoadImage("psu3.jpg");  

    IplImage* image2=  cvLoadImage("psu4.jpg");  

      

    IplImage * imgsum =cvCreateImage(cvGetSize(image1),IPL_DEPTH_32F,3);  

    cvZero(imgsum);  

    cvAcc(image1,imgsum);  

    cvAcc(image2,imgsum);  

  

    IplImage * imgavg = cvCreateImage(cvGetSize(image1),IPL_DEPTH_8U,3);  

    cvConvertScale(imgsum,imgavg,1.0/2.0);  

  

    cvShowImage("imageavg",imgavg);  

    cvSaveImage("avg.jpg",imgavg);  

  

    cvWaitKey(0);  

    cvReleaseImage(&image1);  

    cvReleaseImage(&image2);  

    cvReleaseImage(&imgsum);  

    cvReleaseImage(&imgavg);  

    return 0;  

}  

下图是对同学街舞截图的“二次曝光”效果:



图像相减

OpenCV中用cvAbsDiff函数计算两数组的差的绝对值

[cpp] view
plain copy

void cvAbsDiff(   

        const CvArr* src1,//第一个输入数组  

        const CvArr* src2,//第二个输入数组  

        CvArr* dst//输出数组  

);  


实践:减去背景

减去背景是通过两幅图像代数相减,可以判断出前景区域和运动区域,这是最简单(很多时候也是效果很好的)运动检测方法。

[cpp] view
plain copy

//减去背景  

int main()  

{  

    IplImage* pFrame = NULL;   

    IplImage* pFrImg = NULL;  

    IplImage* pBkImg = NULL;  

  

    CvMat* pFrameMat = NULL;  

    CvMat* pFrMat = NULL;  

    CvMat* pBkMat = NULL;  

  

    CvCapture* pCapture = NULL;  

  

    int nFrmNum = 0;  

  

    //创建窗口  

    cvNamedWindow("video", 1);  

    cvNamedWindow("background",1);  

    cvNamedWindow("foreground",1);  

  

    pCapture = cvCaptureFromFile("media.avi");  

    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);  

  

            pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);  

            pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);  

            pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);  

  

            //转化成单通道图像再处理  

            cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);  

            cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);  

  

            cvConvert(pFrImg, pFrameMat);  

            cvConvert(pFrImg, pFrMat);  

            cvConvert(pFrImg, pBkMat);  

        }  

        else  

        {  

            cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);  

            cvConvert(pFrImg, pFrameMat);  

            //当前帧跟背景图相减  

            cvAbsDiff(pFrameMat, pBkMat, pFrMat);  

            //二值化前景图  

            cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);  

            //更新背景  

            cvRunningAvg(pFrameMat, pBkMat, 0.003, 0);  

            //将背景转化为图像格式,用以显示  

            cvConvert(pBkMat, pBkImg);  

  

            cvShowImage("video", pFrame);  

            cvShowImage("background", pBkImg);  

            cvShowImage("foreground", pFrImg);  

  

            if( cvWaitKey(2) >= 0 )  

                break;  

        }  

    }  

    cvDestroyWindow("video");  

    cvDestroyWindow("background");  

    cvDestroyWindow("foreground");  

    cvReleaseImage(&pFrImg);  

    cvReleaseImage(&pBkImg);  

    cvReleaseMat(&pFrameMat);  

    cvReleaseMat(&pFrMat);  

    cvReleaseMat(&pBkMat);  

    cvReleaseCapture(&pCapture);  

    return 0;  

}  

效果图:



转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7610665

实验代码及视频下载:http://download.csdn.net/detail/xiaowei_cqu/4335573

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: