作者:朱金燦
請注意,這裡我所說的動態數組不是指你自己new 出來的數組,而是指STL 中的std::vector 和MFC 中的CArray 之類的容器。開始以為使用std::vector 不過是免除動態內存之苦。免除自己手動開辟和釋放內存是一方面,實際上在使用的過程中你會逐漸發現使用std::vector 的好處。今天我就發現了一個好處。
今天我修改別人寫的一個圖像匹配算法,所謂圖像匹配就是找出兩幅圖像中相同的地方,在我這個算法中就是找出匹配結果點。別人的代碼大致是這樣的:
view plaincopy to clipboardprint?
/*!
rief 匹配點信息結構體
*/
struct PointInfo
{
long x;
long y;
long Geo_x;
long Geo_y;
PointInfo()
{
x= 0;
y=0;
Geo_x = 0;
Geo_y = 0;
}
};
/*!
rief 匹配兩幅圖像,返回匹配結果點數組
param pLeftImg 左圖像文件句柄
param pRightImg 右圖像文將句柄
param lVaildNum 返回的匹配結果點個數
eturn 匹配結果點數組
*/
PointInfo* ImageMatch(FILE* pLeftImg,FILE* pRightImg,long &lVaildNum)
{
long Imgwidth = 0;
long ImgHeight= 0;
// 獲取左圖像寬高,具體代碼不寫
// 開辟一個整幅圖像大小的數組
PointInfo* pResultPt = new PointInfo[Imgwidth*ImgHeight];
// 開始圖像匹配,具體代碼不寫
return pResultPt;
}
/*!
rief 匹配點信息結構體
*/
struct PointInfo
{
long x;
long y;
long Geo_x;
long Geo_y;
PointInfo()
{
x= 0;
y=0;
Geo_x = 0;
Geo_y = 0;
}
};
/*!
rief 匹配兩幅圖像,返回匹配結果點數組
param pLeftImg 左圖像文件句柄
param pRightImg 右圖像文將句柄
param lVaildNum 返回的匹配結果點個數
eturn 匹配結果點數組
*/
PointInfo* ImageMatch(FILE* pLeftImg,FILE* pRightImg,long &lVaildNum)
{
long Imgwidth = 0;
long ImgHeight= 0;
// 獲取左圖像寬高,具體代碼不寫
// 開辟一個整幅圖像大小的數組
PointInfo* pResultPt = new PointInfo[Imgwidth*ImgHeight];
// 開始圖像匹配,具體代碼不寫
return pResultPt;
}
說實話我不喜歡這種函數的設計,為什麼呢?因為我覺得為了很好地避免內存洩露的話,最好遵循這樣一個原則:函數外部申請的內存函數外部釋放,函數內部申請的內存在函數內存釋放,如果像上面的函數設計,用戶往往會忘記釋放 pResultPt 的內存,而且這種釋放也令人感覺不自然。開始我想這樣改為這樣設計:
view plaincopy to clipboardprint?
/*!
rief 匹配兩幅圖像,返回匹配結果點數組
param pLeftImg 左圖像文件句柄
param pRightImg 右圖像文件句柄
param pResultPt 輸入的匹配點數組
param InitPtNum 輸入的匹配點數組的個數
param lVaildNum 返回的匹配結果點個數
eturn 無
*/
void ImageMatch(FILE* pLeftImg,FILE* pRightImg,PointInfo* pResultPt,long InitPtNum,long &lVaildNum)
{
// 具體實現代碼省去
}
/*!
rief 匹配兩幅圖像,返回匹配結果點數組
param pLeftImg 左圖像文件句柄
param pRightImg 右圖像文件句柄
param pResultPt 輸入的匹配點數組
param InitPtNum 輸入的匹配點數組的個數
param lVaildNum 返回的匹配結果點個數
eturn 無
*/
void ImageMatch(FILE* pLeftImg,FILE* pRightImg,PointInfo* pResultPt,long InitPtNum,long &lVaildNum)
{
// 具體實現代碼省去
}
調用這個函數的部分代碼:
view plaincopy to clipboardprint?
// 調用代碼
// 打開左右圖像
FILE* pLeftImg;
FILE* pRightImg;
long Imgwidth = 0;
long ImgHeight= 0;
// 獲取左圖像寬高,具體代碼不寫
long InitPtNum = Imgwidth*ImgHeight;
PointInfo* pResultPt = new PointInfo[InitPtNum];
long lVaildNum = 0;
ImageMatch(pLeftImg,pRightImg,pResultPt,InitPtNum,lVaildNum);
// 調用代碼
// 打開左右圖像
FILE* pLeftImg;
FILE* pRightImg;
long Imgwidth = 0;
long ImgHeight= 0;
// 獲取左圖像寬高,具體代碼不寫
long InitPtNum = Imgwidth*ImgHeight;
PointInfo* pResultPt = new PointInfo[InitPtNum];
long lVaildNum = 0;
ImageMatch(pLeftImg,pRightImg,pResultPt,InitPtNum,lVaildNum);
上面的代碼符合了函數外部申請的內存函數外部釋放,函數內部申請的內存在函數內存釋放的原則,但是依然給人別扭的感覺,首先是要找匹配點,先得開一個整幅圖的大數組(滿足找匹配點的需要,擔心不夠用),然而匹配點往往只占圖像的一小部分;其次是輸入的函數的參數增多了,除了輸入匹配點數組指針,還得輸入數組的難度,輸入參數增多往往增加了用戶的使用難度,比如用戶可能會搞不清楚 long InitPtNum 這個參數所代表的意義 。
最後我想比較理想的設計是什麼呢?用戶只需要輸入兩幅圖像的文件句柄和動態數組,調用後返回這個數組就行。於是我想到了下面這個設計:
view plaincopy to clipboardprint?
/*!
rief 匹配兩幅圖像
param pLeftImg 左圖像文件句柄
param pRightImg 右圖像文件句柄
param VecPt 輸入和匹配點數組
eturn 無
*/
void ImageMatch(FILE* pLeftImg,FILE* pRightImg,std::vector<PointInfo> &VecPt)
{
}
/*!
rief 匹配兩幅圖像
param pLeftImg 左圖像文件句柄
param pRightImg 右圖像文件句柄
param VecPt 輸入和匹配點數組
eturn 無
*/
void ImageMatch(FILE* pLeftImg,FILE* pRightImg,std::vector<PointInfo> &VecPt)
{
}
這樣設計,首先免去開辟和釋放內存之累,其次你再也不用開辟一大塊內存去應對一個不確定的情況,三是別人使用起來非常自然。
由此看來,適當使用現成的動態數組結構可以使我們的設計更為合理。