利用GDAL保存bmp格式的灰度图(一)

1 篇文章 0 订阅

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中下载。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值