根據圖像的協方差矩陣的求解公式,採用傳統的方法至少要遍歷2次圖像才能求得圖像的協方差矩陣:
第一次是求均值,第二次是求每個樣本與均值樣本之差的積。
如果圖像比較大,存儲在磁盤上,頻繁的讀取磁盤數據是很費時的一項工作。
有沒有只遍歷一次圖像就能求得圖像的協方差矩陣的方法呢?
經過研究還真發現了這樣的一種方法,廢話少說直接上代碼:
GDALAllRegister(); //利用GDAL讀取圖片,先要進行註冊
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO"); //設置支持中文
//準備讀取圖片
GDALDataset *ReadDataSet=(GDALDataset*)GDALOpen(inputFileName,GA_ReadOnly);
if(ReadDataSet==NULL) return -1;
int x=0; //圖像的起始位置
int y=0;
int width=ReadDataSet->GetRasterXSize(); //圖像的寬度
int height=ReadDataSet->GetRasterYSize(); //圖像的高度
int bandsCount=ReadDataSet->GetRasterCount();//圖像的波段數
if(bandsCount<2)
{
delete ReadDataSet;ReadDataSet=NULL;
return -3; //波段個數必須大於等於2個
}
//緩存波段列表
int *bandsList=new int[bandsCount];
if (dims!=NULL && dims->bandsIndex!=NULL)
{
for(int i=0;i<bandsCount;i++)
{
bandsList[i]=dims->bandsIndex[i];
}
}
else
{
for(int i=0;i<bandsCount;i++)
{
bandsList[i]=i+1;
}
}//緩存波段列表完畢
int ppt=0;
int progress=0;
//協方差矩陣
long pixelsCount=width*height;
//有效像元的個數,不包括背景像元
long validPixelsCount=0;
//分配協方差矩陣內存
double *covMat=new double[bandsCount*bandsCount]();
//分配波段數據平均值的內存
double *bandsAverage=new double[bandsCount];
{//協方差矩陣的計算
//用於保存每行像元值的內存
float *rowData=new float[width*bandsCount];
//用於保存每個像元值的內存
double *pixelData=new double[bandsCount];
//分配波段數據之和的內存
double *bandsSum=new double[bandsCount]();
//開始循環
for(int r=0;r<height;++r)
{
// 獲取一行數據
if(ReadDataSet->RasterIO(GF_Read,x,y+r,width,1,rowData,width,1,
GDT_Float32,bandsCount,bandsList,0,0,0)==CE_Failure )
{
delete ReadDataSet;
delete[] covMat;
delete[] bandsAverage;
delete[] rowData;
delete[] pixelData;
delete[] bandsSum;
delete[] bandsList;
return -1;
}
//循環一行中的每一個像元
for (int w=0;w<width;w++)
{
//判斷該像元是否是背景像元
if(fabs(rowData[w]-backgroundValue)>FLT_EPSILON)
{
//有效像元個數加1
validPixelsCount++;
//獲取一個像元的數據
for(int n=0;n<bandsCount;n++)
{
pixelData[n]=rowData[n*width+w];
}
//計算協方差矩陣
for (int h=0;h<bandsCount;++h)
{
for (int l=h;l<bandsCount;++l)
{
covMat[h*bandsCount+l]+=pixelData[h]*pixelData[l];
}
bandsSum[h]+=pixelData[h];
}
}
}
}
// 計算均值
for(int n=0;n<bandsCount;n++)
{
bandsAverage[n]=bandsSum[n]/validPixelsCount;
}
//計算協方差矩陣
for (int h=0;h<bandsCount;++h)
{
for (int l=h;l<bandsCount;++l)
{
covMat[h*bandsCount+l]=covMat[h*bandsCount+l]-bandsSum[h]*bandsAverage[l]
-bandsSum[l]*bandsAverage[h]+bandsAverage[h]*bandsAverage[l]*validPixelsCount;
}
}
// 將協方差矩陣的和除以像元個數,並將上三角複製成下三角
for (int h=0;h<bandsCount;++h)
{
for (int l=h;l<bandsCount;++l)
{
covMat[h*bandsCount+l]/=(validPixelsCount-1);
covMat[l*bandsCount+h]=covMat[h*bandsCount+l];
}
}
//刪除臨時內存
delete[] pixelData;
delete[] rowData;
delete[] bandsSum;
}//協方差矩陣計算完畢
delete ReadDataSet;
delete[] covMat;
delete[] bandsAverage;
delete[] bandsList;
return 0;
代碼是從項目中摘抄出來的,要用的話可能的自己修改一下,用到了GDAL讀取圖像數據。有問題歡迎交流!