利用GDAL儲存bmp格式的灰度圖(一)
阿新 • • 發佈:2018-12-05
GDAL是處理地理資訊的有力工具。從這篇部落格開始,我分3篇來介紹如何利用GDAL來儲存bmp格式的灰度圖。
第一篇是一個最簡單的例子:從TCP端接收資料,然後通過GDAL儲存為本地的bmp灰度檔案。這個例子有個缺點:GDAL要求資料每行位元組數被4整除,這個程式沒有對這個要求加保護措施。這個問題將在第二篇裡修正。
1)準備資料
在photoshop裡新建一個灰度檔案,檔案的寬度應該是4的倍數(正如前面所說,程式沒有加保護,所以檔案寬度要被四整除)。
注:建立的灰度圖,每個畫素佔一個位元組。但是CSDN似乎不支援上傳這種單位元組格式的bmp檔案。我只能傳一個png檔案示意。
2)撰寫一個TCP類,用來從TCP埠讀取二進位制資料:
#include "ClientThread.h" #include "ClientTCP.h" #include <wingdi.h> #include <qdebug.h> #if !defined(IMG_BUF_SIZE) #define IMG_BUF_SIZE (1024 * 1024 * 10) #endif #if !defined(TCP_BUF_SIZE) #define TCP_BUF_SIZE (1024 * 1024) #endif int MFCconnect(SOCKET skt, const sockaddr * pAddr, int iLen) { return connect(skt, pAddr, iLen); } ClientThread * pInstance = NULL; ClientThread::ClientThread() : QThread() { m_pData = new unsigned char[TCP_BUF_SIZE]; m_pImg = new unsigned char[IMG_BUF_SIZE]; m_iBufPtr = 0; pInstance = this; } ClientThread::~ClientThread() { terminate(); delete [] m_pData; delete [] m_pImg; } void ClientThread::run() { WSAData wsaData; int iRet = WSAStartup(MAKEWORD(2, 2), &wsaData); if (0 == iRet) { m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET != m_socket) { sockaddr_in saServer; saServer.sin_family = AF_INET; //地址家族 saServer.sin_port = htons(5050); //注意轉化為網路節序 saServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); if (SOCKET_ERROR != MFCconnect(m_socket, (const sockaddr *)&saServer, (int)sizeof(saServer))) { ClientTCP * pDlg = ClientTCP::pGetInstance(); pDlg->setReadyMsg(); while (true) { int iRet = recv(m_socket, (char *)m_pData, TCP_BUF_SIZE, 0); if (SOCKET_ERROR == iRet) { int nError = WSAGetLastError(); pDlg->setErrMsg(); break; } else if (0 == iRet)//連結斷開 { int nError = WSAGetLastError(); pDlg->setErrMsg(); break; } else { static bool static_bFlag = false; static BITMAPFILEHEADER stFileBMP; static BITMAPINFOHEADER stInfoBMP; if(!static_bFlag) { memcpy(&stFileBMP, m_pData, sizeof(stFileBMP)); memcpy(&stInfoBMP, m_pData + sizeof(BITMAPFILEHEADER), sizeof(BITMAPINFOHEADER)); static_bFlag = true; } memcpy(m_pImg + m_iBufPtr, m_pData, iRet); m_iBufPtr += iRet; if(m_iBufPtr == stFileBMP.bfSize) { bool bRet = bWriteMemToFile_GrayScale(m_pImg + stFileBMP.bfOffBits, stInfoBMP.biWidth, stInfoBMP.biHeight, "hehe.bmp"); } qDebug()<<m_iBufPtr; } } WSACleanup(); } } } } ClientThread * ClientThread::pGetInstance() { return pInstance; }
3) 撰寫一個專門用來儲存灰度圖的函式:
bool bWriteMemToFile_GrayScale(unsigned char * pData, int iWidth, int iHeight, const char * arrFileName) { char *GType = NULL; GType = pFindImageTypeGDAL((char *)arrFileName); if (GType == NULL) { return false; } GDALDriver *pDriver = NULL; pDriver = GetGDALDriverManager()->GetDriverByName((const char *)GType); if( pDriver == NULL ) { return false; } GDALDataset * pDataSet = pDriver->Create(arrFileName, iWidth, iHeight, 1, GDT_Byte, NULL); GDALRasterBand * pBand = pDataSet->GetRasterBand(1);// from 1 to GetRasterCount() pBand->RasterIO(GF_Write, 0, 0, iWidth, iHeight, pData , iWidth, iHeight, GDT_Byte, 0, 0, NULL);//用法見 https://www.gdal.org/classGDALRasterBand.html#a30786c81246455321e96d73047b8edf1 GDALClose((GDALDatasetH) pDataSet);//用法示例見https://blog.csdn.net/godenlove007/article/details/8864763 https://blog.csdn.net/liminlu0314/article/details/19633849 } char * pFindImageTypeGDAL( char *pDstImgFileName) { char *dstExtension = strlwr(strrchr(pDstImgFileName,'.') + 1); char *Gtype = NULL; if (0 == strcmp(dstExtension,"bmp")) Gtype = "BMP"; else if (0 == strcmp(dstExtension,"jpg")) Gtype = "JPEG"; else if (0 == strcmp(dstExtension,"png")) Gtype = "PNG"; else if (0 == strcmp(dstExtension,"tif")) Gtype = "GTiff"; else if (0 == strcmp(dstExtension,"gif")) Gtype = "GIF"; else Gtype = NULL; return Gtype; }
4)在main.cpp裡初始化GDAL驅動:
#include "ClientTCP.h"
#include <QtWidgets/QApplication>
#include "ClientThread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ClientThread thrd;
ClientTCP w;
w.show();
GDALAllRegister();
return a.exec();
}
5)通過TCP助手向你的程式傳送你剛剛製作的bmp檔案:
6) 傳送完畢後,你會看到hehe.bmp儲存在sln同級的目錄內:
7)注意,bmp檔案把記憶體的第一行作為影象最底一行。所以網路助手發出的資料其實是從底下往上發。但是GDAL儲存檔案時,仍然按照正常順序,記憶體第一行也是圖片第一行。所以最後的檔案hehe.bmp變成upside-down
原始碼請在我的資源https://download.csdn.net/my中下載。