?? motion.cpp
字號(hào):
#include "GlobalApi.h"
#include "stdafx.h"
#include "cdib.h"
#include "math.h"
/*************************************************************************
*
* \函數(shù)名稱:
* GetFileName()
*
* \輸入?yún)?shù):
* CString strFilePathName - 圖象的文件名
* int nCurFrameNum - 當(dāng)前幀的圖象文件名
*
* \返回值:
* CString - 返回給定幀數(shù)的圖象文件名
*
* \說明:
* 該函數(shù)根據(jù)指定文件路徑名和當(dāng)前圖象序列的幀數(shù)獲取圖象文件名
* 該函數(shù)中需要注意的是,只能讀取0-999幀圖象,圖象為bmp格式,且按照
* 幀數(shù)數(shù)字進(jìn)行存儲(chǔ),例如第一幀圖象文件名為×××001.bmp,第33幀圖象
* 的文件名為×××033.bmp。如果不是bmp文件,則返回"NULL"。
*
*************************************************************************
*/
CString GetFileName(CString strFilePathName, int nCurFrameNum)
{
//文件的路徑名
CString strTempFileName;
int nNumPos=strFilePathName.Find(".");
if(nNumPos==-1){
AfxMessageBox("Please choose a bmp file");
return "NULL";
}
//表示去掉了擴(kuò)展名和數(shù)字標(biāo)號(hào)的路徑名,在這里,限定幀數(shù)為0~999,所以采用三位來表示
CString strFileNameNoExtNoNum=strFilePathName.Left(nNumPos-3);
//表示標(biāo)號(hào)的字符串
CString strTempNum;
if(nCurFrameNum<10){
strTempNum.Format("00%d",nCurFrameNum);
}
else {
if(nCurFrameNum<100 &&nCurFrameNum>=10){
strTempNum.Format("0%d",nCurFrameNum);
}
else{
strTempNum.Format("%d",nCurFrameNum);
}
}
// 得到圖象文件名
strTempFileName=strFileNameNoExtNoNum+strTempNum+".bmp";
// 返回
return strTempFileName;
}
/*************************************************************************
*
* \函數(shù)名稱:
* LoadDibSeq()
*
* \輸入?yún)?shù):
* CString strFilePath - 第一幀圖象的文件名
* int nCurFrameNum - 當(dāng)前幀的圖象文件名
* int nTotalFrameNum - 進(jìn)行檢測(cè)的圖象幀數(shù)
* CDib* pDib - 指向返回CDib類的指針
*
* \返回值:
* BOOL - 成功則返回TRUE,否則返回FALSE
*
* \說明:
* 該函數(shù)根據(jù)指定文件路徑名和當(dāng)前圖象序列的幀數(shù)讀取圖象數(shù)據(jù)道pDib中
* 該函數(shù)中需要注意的是,只能讀取0-999幀圖象,圖象為bmp格式,且按照
* 幀數(shù)數(shù)字進(jìn)行存儲(chǔ),例如第一幀圖象文件名為×××001.bmp,第33幀圖象
* 的文件名為×××033.bmp。
*
*************************************************************************
*/
BOOL LoadDibSeq(CString strFilePath, int nCurFrameNum, int nTotalFrameNum, CDib* pDib)
{
//一般來講,程序在處理的過程中需要裝載的幀號(hào)應(yīng)該是由外界指定的
//當(dāng)指定的幀號(hào)不合法時(shí),就裝載當(dāng)前幀作為默認(rèn)值
if (nCurFrameNum<1 || nCurFrameNum>nTotalFrameNum)
{
AfxMessageBox("Invalidate file frame number");
return FALSE;
}
// 獲得當(dāng)前幀的圖象文件名
CString strTempFileName;
strTempFileName=GetFileName(strFilePath,nCurFrameNum);
CFile fileOpen=NULL;
// 打開文件并讀取
fileOpen.Open(strTempFileName,CFile::modeRead);
if(pDib->Read(&fileOpen)==FALSE){
AfxMessageBox("can not open the file "+strTempFileName);
return FALSE;
}
return TRUE;
}
/*************************************************************************
*
* \函數(shù)名稱:
* BinaFrameDiff()
*
* \輸入?yún)?shù):
* unsigned char* pUnchImg1 - 圖象的文件名
* unsigned char* pUnchImg2 - 當(dāng)前幀的圖象文件名
* int nWidth
* int nHeight
* unsigned char* pUnchResult
* int nThreshold
*
* \返回值:
* CString - 返回給定幀數(shù)的圖象文件名
*
* \說明:
* 該函數(shù)比較pUnchImg1和pUnchImg2兩個(gè)區(qū)域中的內(nèi)容,如果兩個(gè)區(qū)域內(nèi)
*容的差值的絕對(duì)值比Threshold大,則將pUnchResult相應(yīng)的元素設(shè)置為邏輯值1,
*用灰度255表示,否則為0,并用灰度0表示
*
*************************************************************************
*/
void BinaFrameDiff(unsigned char *pUnchImg1, unsigned char *pUnchImg2,
int nWidth, int nHeight, unsigned char * pUnchResult,
int nThreshold)
{
int nTemp=0;
for (int i=0;i<nHeight*nWidth;i++) {
nTemp = abs(pUnchImg1[i] - pUnchImg2[i]);
pUnchResult[i] = nTemp > nThreshold ? 255:0;
}
return ;
}
/*************************************************************************
*
* \函數(shù)名稱:
* ErodeFrameDiff()
*
* \輸入?yún)?shù):
* unsigned char* pUnchImg1 - 圖象數(shù)據(jù)指針
* int nWidth - 圖象寬度
* int nHeight - 圖象高度
* int nErodeHalfWin - 腐蝕窗口大小的一半
* unsigned char* pUnchResult - 結(jié)果數(shù)據(jù)制止
* int nThreshold - 閾值
*
* \返回值:
* 無
*
* \說明:
* 該函數(shù)進(jìn)行腐蝕操作,形態(tài)學(xué)操作對(duì)pUnchImg中的每一點(diǎn),計(jì)算這一點(diǎn)對(duì)應(yīng)的
*窗口內(nèi)的一些參數(shù),然后根據(jù)參數(shù)結(jié)果給這個(gè)點(diǎn)設(shè)置相應(yīng)的值. 功能上相當(dāng)于廣義濾波
*
*************************************************************************
*/
void ErodeFrameDiff(unsigned char *pUnchImg, int nWidth, int nHeight, int nErodeHalfWin,
int nErodeThreshold, unsigned char *pUnchResult)
{
// 搜索整個(gè)圖象,對(duì)圖象進(jìn)行腐蝕處理
for (int i=nErodeHalfWin;i<nHeight-nErodeHalfWin;i++) {
for (int j=nErodeHalfWin;j<nWidth-nErodeHalfWin;j++) {
// 如果幀間的差不為0才進(jìn)行處理
if (pUnchImg[i*nWidth+j] != 0)
{
int iPointCount = 0;
// 根據(jù)此點(diǎn)的鄰域判斷此點(diǎn)是否需要?jiǎng)h除
for (int r=-nErodeHalfWin;r<=nErodeHalfWin;r++) {
for (int c=-nErodeHalfWin;c<=nErodeHalfWin;c++) {
if (pUnchImg[(i+r)*nWidth+j+c] != 0) {
iPointCount++;
}
}
}
// 如果鄰域中不為0的個(gè)數(shù)小于設(shè)定的閾值,則強(qiáng)行設(shè)置為0
if (iPointCount < nErodeThreshold) {
pUnchResult[i*nWidth+j] = 0;
}
else {
pUnchResult[i*nWidth+j] = 255;
}
}
else
{
pUnchResult[i*nWidth+j] = 0;
}
}
}
return ;
}
/*************************************************************************
*
* \函數(shù)名稱:
* GetBackground()
*
* \輸入?yún)?shù):
* CString strFilePath - 第一幀圖象的文件名
* int nTotalFrameNum - 進(jìn)行檢測(cè)的圖象幀數(shù)
* int nImageWidth - 圖象寬度
* int nImageHeight - 圖象高度
* unsigned char * pUnchBackGround - 指向返回背景數(shù)據(jù)的指針
*
* \返回值:
* BOOL - 成功則返回TRUE,否則返回FALSE
*
* \說明:
* 該函數(shù)根據(jù)指定文件名的圖象序列求取靜止背景
*
*************************************************************************
*/
BOOL GetBackground(CString strFilePath, int nTotalFrameNum, int nImageWidth,
int nImageHeight, unsigned char* pUnchBackGround)
{
// 如果此時(shí)背景已經(jīng)生成,函數(shù)返回,不需要再一次計(jì)算
/*if (pUnchBackGround!=NULL){
return TRUE;
}*/
// pUnchTemp1和pUnchTemp2用來計(jì)算相鄰兩幀之間的幀差
// 每次只要讀入一幀即可,即:假設(shè)剛剛比較k-1和k幀,那么現(xiàn)在比較k和
// k+1幀,那么k幀是不需要重新讀入的
unsigned char* pUnchTemp1;
unsigned char* pUnchTemp2;
pUnchTemp1 = new unsigned char[nImageWidth * nImageHeight * sizeof(unsigned char)];
pUnchTemp2 = new unsigned char[nImageWidth * nImageHeight * sizeof(unsigned char)];
// 臨時(shí)存放圖象數(shù)據(jù)的CDib指針
CDib* pDibTemp;
pDibTemp = new CDib;
// 讀出第一幀數(shù)據(jù)并放入pDibTemp
pDibTemp->Empty();
if(!LoadDibSeq(strFilePath,1,nTotalFrameNum,pDibTemp)){
return FALSE;
}
// 然后將數(shù)據(jù)取出,存放在pUnchTemp1中
memcpy(pUnchTemp2,pDibTemp->m_lpImage,nImageWidth*nImageHeight*sizeof(unsigned char));
// pChResultAfterMor 是用來記錄幀間變化的內(nèi)存區(qū)域
unsigned char * pUnchTrackBox = new unsigned char[(nTotalFrameNum)*
nImageWidth*nImageHeight*sizeof(unsigned char)];
unsigned int index = 0;
// 幀間差的區(qū)域,二進(jìn)制
unsigned char *pUnchTemp3=new unsigned char[nImageWidth*nImageHeight*sizeof(unsigned char)];
// 腐蝕之后的區(qū)域,二進(jìn)制
unsigned char * pUnchResultAfterMor = new unsigned char[nImageWidth*nImageHeight*sizeof(unsigned char)];
// 對(duì)每一幀進(jìn)行比較
for (int i = 2; i<nTotalFrameNum-1; i++) {
// 打開第i幀圖象文件,并將圖象存放在CDib對(duì)象pDibTemp中
pDibTemp->Empty();
if(!LoadDibSeq(strFilePath , i , nTotalFrameNum , pDibTemp)){
return FALSE;
}
// 然后將數(shù)據(jù)取出,存放在pUnchTemp2中
memcpy(pUnchTemp2,pDibTemp->m_lpImage,nImageWidth*nImageHeight);
// 對(duì)圖象幀差進(jìn)行二值化處理,并將二值化后的圖象存放在pUnchTemp3中
BinaFrameDiff(pUnchTemp1,pUnchTemp2 ,nImageWidth,nImageHeight,pUnchTemp3,10);
// 對(duì)二值化后的圖象進(jìn)行腐蝕處理,在這里對(duì)腐蝕窗口的大小設(shè)置為2,閾值為7
ErodeFrameDiff(pUnchTemp3,nImageWidth,nImageHeight,2,7,pUnchResultAfterMor);
// 將此二值化后的程序放入pUnchTrackBox的相應(yīng)位置
memcpy(pUnchTrackBox+index,pUnchResultAfterMor,sizeof(unsigned char)*nImageWidth*nImageHeight);
// 計(jì)算圖象數(shù)據(jù)在pUnchTrackBox中的偏移量
index = index + nImageWidth*nImageHeight*sizeof(unsigned char);
// 每做完兩幀之間的比較,就使幀號(hào)下移一個(gè),pUnchTemp1中是存k幀內(nèi)容,pUnchTemp2幀是存k+1
// 幀內(nèi)容,所以,每次只要把pUnchTemp2中的內(nèi)容給pTemp1,而pTemp2重新讀入既可以了.
unsigned char* pUnchTag = NULL;
pUnchTag = pUnchTemp1;
pUnchTemp1 = pUnchTemp2;
pUnchTemp2 = pUnchTag;
}
// 釋放已分配內(nèi)存
delete []pUnchTemp1;
pUnchTemp1 = NULL;
delete []pUnchTemp2;
pUnchTemp2 = NULL;
delete []pUnchTemp3;
pUnchTemp3 = NULL;
delete []pUnchResultAfterMor;
pUnchResultAfterMor=NULL;
// 每一幀的大小
int nFrameSize = nImageWidth * nImageHeight * sizeof(unsigned char);
// 記錄最大長(zhǎng)度
int * pnTrackSegLen = new int [nImageWidth*nImageHeight];
// 記錄最大長(zhǎng)度中的中間幀標(biāo)號(hào)
int * pnTrackSegFrame = new int [nImageWidth*nImageHeight];
// 對(duì)每一個(gè)象素點(diǎn)跟蹤最大為0的長(zhǎng)度,并將最大長(zhǎng)度中的中間幀標(biāo)號(hào)記錄下來
for (int y = 0; y<nImageHeight; y++) {
for (int x = 0; x<nImageWidth; x++) {
// 此象素在一幀那相對(duì)于該幀第一個(gè)元素的偏移量
int offset = y * nImageWidth + x;
// 初始化最大長(zhǎng)度
int largeLen = 0;
int t = 1;
// 連續(xù)為0的段的開始和結(jié)束幀標(biāo)號(hào)
int segStart,segEnd;
// 跟蹤長(zhǎng)度
int segLen;
// 當(dāng)前幀數(shù)
int frameNum;
segLen = 0;
frameNum = 1;
// 遍歷整個(gè)序列,跟蹤并記錄此點(diǎn)連續(xù)為0的最大長(zhǎng)度
while (t < nTotalFrameNum - 1) {
// 如果還沒有到達(dá)序列結(jié)束并且此點(diǎn)的不為0,則繼續(xù)到下一幀搜索
while ((t < nTotalFrameNum -1) && (pUnchTrackBox[t*nFrameSize+offset] != 0))
t++;
//如果此時(shí)的t>= nTotalFrameNum - 1,則說明,已經(jīng)遍歷到最后一幀了
if (t >= nTotalFrameNum - 1)
break;
// 此時(shí)應(yīng)為此長(zhǎng)度的開始
segStart = t;
while ((t < nTotalFrameNum - 1) && (pUnchTrackBox[t*nFrameSize+offset] == 0))
t++;
// 此長(zhǎng)度的結(jié)束幀標(biāo)號(hào)
segEnd = t - 1;
// 獲得此連續(xù)為0的幀的長(zhǎng)度
segLen = segEnd +1 -segStart;
// 判斷是否為最大長(zhǎng)度,是則進(jìn)行替換
if (segLen > largeLen) {
largeLen = segLen;
frameNum = (segEnd + segStart)/2;
}
}
pnTrackSegLen[offset] = largeLen;
pnTrackSegFrame[offset] = frameNum;
}
}
delete []pUnchTrackBox; pUnchTrackBox=NULL;
// 因?yàn)閷?duì)每個(gè)象素而言,背景可能出現(xiàn)在不同幀里,此時(shí)需要把所有幀調(diào)入內(nèi)存
unsigned char* pBuffer = new unsigned char[nTotalFrameNum*(nImageWidth*nImageHeight)];
for (int k=1; k<nTotalFrameNum; k++) {
pDibTemp->Empty();
LoadDibSeq(strFilePath , k , nTotalFrameNum , pDibTemp);
// 然后將數(shù)據(jù)取出,存放在pBuffer的相應(yīng)位置中
memcpy(pBuffer+k*nFrameSize,pDibTemp->m_lpImage,nImageWidth*nImageHeight);
}
// 遍歷整個(gè)圖象,設(shè)置背景數(shù)據(jù)
for (y=0; y<nImageHeight; y++) {
for (int x=0; x<nImageWidth; x++) {
// 獲得此象素點(diǎn)在一幀數(shù)據(jù)中的偏移量
int k = y * nImageWidth + x;
// 獲得此象素點(diǎn)連續(xù)為0的最大長(zhǎng)度的中間幀標(biāo)號(hào)
int nFrameMax = pnTrackSegFrame [k];
// 設(shè)置具有最大長(zhǎng)度的中間幀的數(shù)據(jù)為背景數(shù)據(jù)
pUnchBackGround[k] = pBuffer[(nFrameMax*nFrameSize)+k];
}
}
delete []pnTrackSegLen;
pnTrackSegLen=NULL;
delete []pnTrackSegFrame;
pnTrackSegFrame=NULL;
delete []pBuffer;
pBuffer=NULL;
::SetCursor(::LoadCursor(NULL, IDC_ARROW));
return TRUE;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -