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