圖像代數(shù)運(yùn)算:平均值去噪,減去背景
代數(shù)運(yùn)算,就是對(duì)兩幅圖像的點(diǎn)之間進(jìn)行加、減、乘、除的運(yùn)算。四種運(yùn)算相應(yīng)的公式為:
代數(shù)運(yùn)算中比較常用的是圖像相加和相減。圖像相加常用來(lái)求平均值去除addtive噪聲或者實(shí)現(xiàn)二次曝光(double-exposure)。圖像相減用于減去背景或周期噪聲,污染等。
圖像相加
OpenCV中提供了相加的函數(shù)
void cvAcc(
const CvArr* image,//輸入圖像
CvArr* sum, //累積圖像
const CvArr* mask=NULL//可選的運(yùn)算
);
我們還需要用到一個(gè)線性變換轉(zhuǎn)換函數(shù)來(lái)對(duì)相加的結(jié)果求平均
void cvConvertScale(
const CvArr* src, //輸入數(shù)組
CvArr* dst,//輸出數(shù)組
double scale=1,//比例
double shift=0 //縮放比例,可選
);
#define cvCvtScale cvConvertScale
#define cvScale cvConvertScale
#define cvConvert( src, dst ) cvConvertScale( (src), (dst), 1, 0 )
實(shí)踐:平均值去噪
我們用NASA的一段幸運(yùn)團(tuán)的視頻做實(shí)驗(yàn),截取視頻的某幾個(gè)連續(xù)幀求平均值:
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);// 獲取當(dāng)前幀
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;
}
以下從左到右分別是連續(xù)兩幀、四幀、八幀、十六幀求均值的結(jié)果:
實(shí)踐:圖像二次曝光
曝光和去噪是一樣的,也是對(duì)幾幅圖像求平均
//通過(guò)求平均二次曝光
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;
}
下圖是對(duì)同學(xué)街舞截圖的“二次曝光”效果:
圖像相減
OpenCV中用cvAbsDiff函數(shù)計(jì)算兩數(shù)組的差的絕對(duì)值
void cvAbsDiff(
const CvArr* src1,//第一個(gè)輸入數(shù)組
const CvArr* src2,//第二個(gè)輸入數(shù)組
CvArr* dst//輸出數(shù)組
?。?
實(shí)踐:減去背景
減去背景是通過(guò)兩幅圖像代數(shù)相減,可以判斷出前景區(qū)域和運(yùn)動(dòng)區(qū)域,這是最簡(jiǎn)單(很多時(shí)候也是效果很
好的)運(yùn)動(dòng)檢測(cè)方法。
//減去背景
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;
//創(chuàng)建窗口
cvNamedWindow(“video”, 1);
cvNamedWindow(“background”,1);
cvNamedWindow(“foreground”,1);
pCapture = cvCaptureFromFile(“media.avi”);
while(pFrame = cvQueryFrame( pCapture ))
{
nFrmNum++;
//如果是第一幀,需要申請(qǐng)內(nèi)存,并初始化
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);
//轉(zhuǎn)化成單通道圖像再處理
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);
//當(dāng)前幀跟背景圖相減
cvAbsDiff(pFrameMat, pBkMat, pFrMat);
//二值化前景圖
cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);
//更新背景
cvRunningAvg(pFrameMat, pBkMat, 0.003, 0);
//將背景轉(zhuǎn)化為圖像格式,用以顯示
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;
}
效果圖:
========
opencv連通域去噪
//Find_Connected_Component參數(shù)說(shuō)明:
/*mask———一副灰度圖
polygon1_hull0———用多邊形擬合選1,用凸包擬合選0
scale———設(shè)置不被刪除的連通輪廓大小
num————連通輪廓的最大數(shù)目
bbs——指向連通輪廓的外接矩形
center——指向連通輪廓的中心*/
#define CVCONTOUR_APPROX_LEVEL 2//數(shù)越大連通區(qū)域的邊界越簡(jiǎn)單
#define CVCLOSE_ITR 1 //圖像形態(tài)學(xué)運(yùn)算的次數(shù)
void Find_Connected_Component(IplImage *mask,int polygon1_hull0=1,float scale=4
,int *num=0,CvRect *bbs=0,CvPoint
*centers=0)//連通域去噪聲
{
static CvMemStorage* mem_storage=0;
static CvSeq* contours=0;
//先開操作,后閉操作
cvMorphologyEx(mask,mask,0,0,CV_MOP_OPEN,CVCLOSE_ITR);
cvMorphologyEx(mask,mask,0,0,CV_MOP_CLOSE,CVCLOSE_ITR);
//找到所有輪廓
if(!mem_storage)
{
mem_storage=cvCreateMemStorage(0);
}
else{
cvClearMemStorage(mem_storage);
}
CvContourScanner scanner=cvStartFindContours(mask,mem_storage,sizeof
?。–vContour),CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
//丟棄太小的輪廓,用多邊形或凸包擬合剩下的輪廓
CvSeq* c;
int numCont=0;
while(c=cvFindNextContour(scanner))
{
double len=cvContourPerimeter(c);//連通域周長(zhǎng)
double q=(mask-》height+mask-》width)/scale;
//cout《《len《《“ ”;
if(len《q){cvSubstituteContour(scanner,NULL);}
else{
CvSeq* c_new;
if(polygon1_hull0)
{
//多邊形擬合
c_new=cvApproxPoly(c,sizeof
?。–vContour),mem_storage,CV_POLY_APPROX_DP,CVCONTOUR_APPROX_LEVEL,0);
}
else{
//凸包擬合
c_new=cvConvexHull2(c,mem_storage,CV_CLOCKWISE,1);
}
cvSubstituteContour(scanner,c_new);
numCont++;
}
}
contours=cvEndFindContours(&scanner);
const CvScalar CVX_WHITE=CV_RGB(0xff,0xff,0xff);//白色
const CvScalar CVX_BLACK=CV_RGB(0x00,0x00,0x00); //黑色
//重繪連通區(qū)域
cvZero(mask);
IplImage *maskTemp;
int numFilled=0;
if(num!=NULL)
{
int N=*num,i=0;
CvMoments moments;
double M00,M01,M10;
maskTemp=cvCloneImage(mask);
for(i=0,c=contours;c!=NULL;c=c-》h_next,i++)
{
if(i《N)
{
cvDrawContours(maskTemp,c,CVX_WHITE,CVX_WHITE,-1,CV_FILLED,8);
//找中心
if(centers){
cvMoments(maskTemp,&moments,1);
M00=cvGetSpatialMoment(&moments,0,0);
M10=cvGetSpatialMoment(&moments,1,0);
M01=cvGetSpatialMoment(&moments,0,1);
centers[i].x=(int)(M10/M00);
centers[i].y=(int)(M01/M00);
}
if(bbs!=NULL){
bbs[i]=cvBoundingRect(c);
}
cvZero(maskTemp);
numFilled++;
}
//畫區(qū)域
cvDrawContours(mask,c,CVX_WHITE,CVX_WHITE,-1,CV_FILLED,8);
}
//*num=numFilled;
cvReleaseImage(&maskTemp);
}
else
{
for(c=contours;c!=NULL;c=c-》h_next)
cvDrawContours(mask,c,CVX_WHITE,CVX_WHITE,-1,CV_FILLED,8);
}
*num=numCont;
}
========
評(píng)論
查看更多