只遍歷一次圖像如何求圖像個波段之間的協方差矩陣

根據圖像的協方差矩陣的求解公式,採用傳統的方法至少要遍歷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讀取圖像數據。有問題歡迎交流!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章