GDAL是一個操作各種栅格和矢量地理資料格式的開源庫。包括讀取、寫入、轉換、處理各種栅格和矢量資料格式。它支援各種圖像格式,其詳細清單見: http://www.gdal.org/formats_list.htm 。
完成了圖像的讀取和顯示,但不知這種方法是否為最佳,請各位指正,謝謝!
本文就以VC為開發平台介紹GDAL對圖像資料的操作方法。
1.首先進行GDAl的配置工作,這在上文中已經提到,不再做陳述。
2.然後,我是在Doc類裡面添加OnOpenDocument(LPCTSTR lpszPathName)函數,其具體的操作在其中進行。建立檔案對話框:,傳回lpszPathName.
CFile file;
CFileException fe;
if (!file.Open(lpszPathName,CFile::modeRead | CFile::shareDenyWrite,&fe))
{
ReportSaveLoadException(lpszPathName,&fe,FALSE,AFX_IDP_FAILED_TO_CREATE_DOC);
return FALSE;
}
3.函數中,首先的進行驅動的注冊。所使用的函數是GDALAllRegister()函數,然後進行打開檔案操作,這裡介紹一個DataSet概念,在GDAL中可以說資料的核心就是Dataset,簡單來說可以将Dataset就了解為圖像檔案。在資料集下最重要組成部分就是所謂的波段band,檔案的打開使用的是:GDALOpen函數。
GDALDataset * DataSet; // 在這裡資料集即為了解為圖像檔案
GDALAllRegister(); //注冊驅動,這項萬不可少,必要步驟。
DataSet = (GDALDataset *)GDALOpen(lpszPathName,GA_ReadOnly);//檔案的打開使用的是GDALOpen函數
4.在确認DataSet不是NULL的情況下就可以對圖像資料集進行操作了。
if (DataSet == NULL)
{
AfxMessageBox("無法打開遙感圖像");
return 0;
}
5.接下來,我們就開始進入到波段處理。波段的擷取使用GetRasterBand函數,
GDALRasterBand **pBand; //資料集下最重要的成分波段。
int m_Bands = DataSet->GetRasterCount();
pBand = new GDALRasterBand * [m_Bands]; //建立波段
if (pBand == NULL)
{
AfxMessageBox("建立資料集波段失敗");
return 0;
}
for (int i =0;i<m_Bands;i++)
{
pBand[i] = DataSet->GetRasterBand(i+1);//預讀取遙感的第一個波段,因該是這個作用吧!
if (pBand[i] == NULL)
{
AfxMessageBox("建立i波段資料集失敗!");
return 0;
}
}
6,建立一個對話框,其布局如圖所示:
對話框的設計此處就不作詳述啦,它的作用是傳回顯示模式以及波段選擇。
CDlgBands dlg;
dlg.m_mBands = m_Bands;
if (dlg.m_mBands == 1)
{
dlg.mBandsType = 0;
}
else
{
dlg.mBandsType = 1;
}
dlg.DoModal();
7,進入我認為最重要的步驟:波段資料的讀寫核心函數就是RasterIO。這個函數可以将圖像的某一個子塊讀入或寫入。當然此處要判斷一下要打開的的是灰階圖像還是彩色圖像。
if (dlg.mBandsType == 0)//打開灰色圖像
{
BandsType = dlg.mBandsType;
BdCGray = dlg.BdChoiceGray;
if (pBand[BdCGray] == NULL)
{
return 0;
}
nXsize = pBand[BdCGray]->GetXSize();
nYsize = pBand[BdCGray]->GetYSize(); //資料塊的xy方向像素尺寸
poBandBlock_Gray = (BYTE*)CPLMalloc(sizeof(BYTE)*(nXsize*nYsize));//配置設定緩沖區空間
//RasterIO函數可以将圖像的某一個子塊讀入或寫入
pBand[BdCGray]->RasterIO(GF_Read, 0, 0, nXsize,
nYsize, poBandBlock_Gray, nXsize, nYsize, pBand[BdCGray]->GetRasterDataType(), 0, 0);
}
if (dlg.mBandsType == 1)
{
BandsType = dlg.mBandsType;
BdCR = dlg.BdChoiceR;
BdCG = dlg.BdChoiceG;
BdCB = dlg.BdChoiceB;
int nXsizeR,nXsizeG,nXsizeB;
int nYsizeR,nYsizeG,nYsizeB;
nXsizeR = pBand[BdCR]->GetXSize();
nYsizeR = pBand[BdCR]->GetYSize();
nXsizeG = pBand[BdCG]->GetXSize();
nYsizeG = pBand[BdCG]->GetYSize();
nXsizeB = pBand[BdCB]->GetXSize();
nYsizeB = pBand[BdCB]->GetYSize();
nXsize = nXsizeR;
nYsize = nYsizeR;
poBandBlock_R = (BYTE*)CPLMalloc(sizeof(BYTE)*(nXsizeR*nYsizeR));
poBandBlock_G = (BYTE*)CPLMalloc(sizeof(BYTE)*(nXsizeG*nYsizeG));
poBandBlock_B = (BYTE*)CPLMalloc(sizeof(BYTE)*(nXsizeB*nYsizeB));
pBand[BdCR]->RasterIO(GF_Read,0,0,nXsizeR,nYsizeR,poBandBlock_R,nXsizeR,nYsizeR,pBand[BdCR]->GetRasterDataType(),0,0);
pBand[BdCG]->RasterIO(GF_Read,0,0,nXsizeG,nYsizeG,poBandBlock_G,nXsizeG,nYsizeG,pBand[BdCG]->GetRasterDataType(),0,0);
pBand[BdCB]->RasterIO(GF_Read,0,0,nXsizeB,nYsizeB,poBandBlock_B,nXsizeB,nYsizeB,pBand[BdCB]->GetRasterDataType(),0,0);
}
8.更新和釋放指針
UpdateAllViews(NULL);
delete DataSet; //釋放資源
return TRUE;
要顯示圖像,當然得在View類的OnDraw()函數中添加必要的代碼:
1.假如要打開的是灰階圖像,先對資料頭檔案操作,包括資料頭和顔色表的指派。然後建立資料區,為各像素指派,即完成圖像的顯示:
if (pDoc->BandsType == 0)//GDI繪圖法
{
//資料頭檔案
//1.圖像資料塊頭
int i,j;
int nWidth = pDoc->nXsize;
int nHeight = pDoc->nYsize;
BITMAPINFO * pBmpInfo = (BITMAPINFO*) new char[sizeof(BITMAPINFO) + sizeof(RGBQUAD)*(256)];
pBmpInfo->bmiHeader.biBitCount = 8;
pBmpInfo->bmiHeader.biClrImportant = 0;
pBmpInfo->bmiHeader.biClrUsed = 0;
pBmpInfo->bmiHeader.biCompression = BI_RGB;
pBmpInfo->bmiHeader.biWidth = nWidth;
pBmpInfo->bmiHeader.biHeight = nHeight;
pBmpInfo->bmiHeader.biPlanes = 1;
pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBmpInfo->bmiHeader.biSizeImage = (nWidth*8+31)/32*4*nHeight;
pBmpInfo->bmiHeader.biXPelsPerMeter = 0;
pBmpInfo->bmiHeader.biYPelsPerMeter = 0;
//2.顔色表
for (i = 0;i < 256;i++)
{
pBmpInfo->bmiColors[i].rgbRed = i;
pBmpInfo->bmiColors[i].rgbGreen = i;
pBmpInfo->bmiColors[i].rgbBlue = i;
pBmpInfo->bmiColors[i].rgbReserved = 0;
}
//建立資料區
LONG LineBytes = (nWidth*8+31)/32*4;
LPBYTE pData = (LPBYTE)new char[LineBytes*nHeight];
//為各像素指派!!!!!!
for (i=0;i<nHeight;i++)
{
for (j=0;j<nWidth;j++)
{
pData[(nHeight-i-1)*LineBytes + j] = pDoc->poBandBlock_Gray[i*nWidth+j];//此表達式有待研究
}
}
SetStretchBltMode(pDC->m_hDC,BLACKONWHITE|WHITEONBLACK);
StretchDIBits(pDC->m_hDC, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
pData, pBmpInfo, DIB_RGB_COLORS, SRCCOPY);
UpdateWindow();
delete pBmpInfo;
delete pData;
}
2,當然打開彩色圖像也要如此操作
if (pDoc->BandsType == 1)//GDI繪圖法
{
//資料頭檔案
//1.圖像資料塊頭
int i,j,k;
int nWidth = pDoc->nXsize;
int nHeight = pDoc->nYsize;
BITMAPINFO * pBmpInfo = (BITMAPINFO*) new char[sizeof(BITMAPINFO) + sizeof(RGBQUAD)*(256)];
pBmpInfo->bmiHeader.biBitCount = 24;
pBmpInfo->bmiHeader.biClrImportant = 0;
pBmpInfo->bmiHeader.biClrUsed = 0;
pBmpInfo->bmiHeader.biCompression = BI_RGB;
pBmpInfo->bmiHeader.biWidth = nWidth;
pBmpInfo->bmiHeader.biHeight = nHeight;
pBmpInfo->bmiHeader.biPlanes = 1;
pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBmpInfo->bmiHeader.biSizeImage = (nWidth*24+31)/32*4*nHeight;
pBmpInfo->bmiHeader.biXPelsPerMeter = 0;
pBmpInfo->bmiHeader.biYPelsPerMeter = 0;
//2.顔色表
for (i = 0;i < 256;i++)
{
pBmpInfo->bmiColors[i].rgbRed = i;
pBmpInfo->bmiColors[i].rgbGreen = i;
pBmpInfo->bmiColors[i].rgbBlue = i;
pBmpInfo->bmiColors[i].rgbReserved = 0;
}
//建立資料區
LONG LineBytes = (nWidth*24+31)/32*4;
LPBYTE pData = (LPBYTE)new char[LineBytes*nHeight*3];
//為各像素指派!!!!!!
for (i=0;i<nHeight;i++)
{
for (j=0,k=0;j<nWidth,k<3*nWidth;j++,k+=3)
{
// pData[(nHeight-i-1)*LineBytes + j] = pDoc->poBandBlock_Gray[i*nWidth+j];//此表達式有待研究
pData[(nHeight-i-1)*LineBytes + k] = pDoc->poBandBlock_B[i*nWidth + j];
pData[(nHeight-i-1)*LineBytes + k+1] = pDoc->poBandBlock_G[i*nWidth + j];
pData[(nHeight-i-1)*LineBytes + k+2] = pDoc->poBandBlock_R[i*nWidth + j];
}
}
SetStretchBltMode(pDC->m_hDC,BLACKONWHITE|WHITEONBLACK);
StretchDIBits(pDC->m_hDC, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
pData, pBmpInfo, DIB_RGB_COLORS, SRCCOPY);
UpdateWindow();
delete pBmpInfo;
delete pData;
}