OneTif
#pragma once #include <string> #include <vector> #include "gdal.h" #include "gdal_priv.h" #include <io.h> enum _PIC_TYPE_ { Pixel_Byte = 0, Pixel_Int16 = 1, Pixel_SInt16 = 2, Pixel_Int32 = 3, Pixel_SInt32 = 4, Pixel_Float = 5, Pixel_Double = 6, Pixel_Int64 = 7, Pixel_SInt64 = 8 }; class COneTif { public: COneTif(); ~COneTif(); public: std::string m_strTifPath; double m_LBX; double m_LBY; double m_RTX; double m_RTY; double m_lfGSD; int m_nImgHeight; int m_nImgWidth; int m_nBandNum; int m_nBPB; int m_nBPP; public: bool Initialize(bool b16Trans8 = true); bool ReadImage(int nStartCol, int nStartRow, int nWidth, int nHeight, unsigned char* pData, int nBufferWidth, int nBufferHeight); bool readImageGDAL(unsigned char **pImageData, int &width, int &height, int &nChannels, const char *filePath); bool WriteImageGDAL(const char* pDstImgFileName, unsigned char *pImageData, int width, int height, int nChannels); char* findImageTypeGDAL(char *pDstImgFileName); int ReadImg(int nSrcLeft, int nSrcTop, int nSrcRight, int nSrcBottom, unsigned char* pBuf, int nBufWid, int nBufHeight, int nBandNum, int nDestLeft, int nDestTop, int nDestRight, int nDestBottom, int nSrcSkip, int nDestSkip); private: bool m_bHasOverviews; bool m_bTranto8bit; GDALDataset *m_poDataset; GDALDataType m_eGDALType; _PIC_TYPE_ m_nDataType; int m_nBytesPerBand; int m_nOldBytesPerBand; unsigned char* m_plut; double* m_plfCount; double* m_pHist; };
#include "OneTif.h" COneTif::COneTif() { m_strTifPath = ""; m_LBX = 0.0; m_LBY = 0.0; m_RTX = 0.0; m_RTY = 0.0; m_lfGSD = 0.0; m_nImgHeight = 0; m_nImgWidth = 0; m_nBandNum = 0; int m_nBPB = 1; int m_nBPP = 1; m_bHasOverviews = false; m_bTranto8bit = true; m_poDataset = NULL; m_eGDALType = GDT_Unknown; m_nDataType = Pixel_Byte; m_nBytesPerBand = 1; m_nOldBytesPerBand = 1; m_plut = NULL; m_plfCount = NULL; m_pHist = NULL; } COneTif::~COneTif() { if (m_plut) { delete[] m_plut; m_plut = NULL; } if (m_plfCount) { delete[] m_plfCount; m_plfCount = NULL; } if (m_pHist) { delete[] m_pHist; m_pHist = NULL; } if (m_poDataset != NULL) { GDALClose((GDALDatasetH)m_poDataset); m_poDataset = NULL; } } bool COneTif::Initialize(bool b16Trans8) { const char *pszFilename = m_strTifPath.c_str(); GDALAllRegister(); CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); //设置支持中文路径 m_poDataset = (GDALDataset *)GDALOpen(pszFilename, GA_ReadOnly); if (m_poDataset == NULL) { return false; } double adfGeoTransform[6] = { 0 }; m_nImgWidth = m_poDataset->GetRasterXSize(); m_nImgHeight = m_poDataset->GetRasterYSize(); m_nBandNum = m_poDataset->GetRasterCount(); m_eGDALType = m_poDataset->GetRasterBand(1)->GetRasterDataType(); if (m_poDataset->GetRasterBand(1)->GetOverviewCount() != 0) { m_bHasOverviews = true; } switch (m_eGDALType) { case 1: { m_nDataType = Pixel_Byte; m_nBytesPerBand = 1; break; } case 2: { m_nDataType = Pixel_Int16; m_nBytesPerBand = 2; break; } case 3: { m_nDataType = Pixel_SInt16; m_nBytesPerBand = 2; break; } case 4: { m_nDataType = Pixel_Int32; m_nBytesPerBand = 4; break; } case 5: { m_nDataType = Pixel_SInt32; m_nBytesPerBand = 4; break; } case 6: { m_nDataType = Pixel_Float; m_nBytesPerBand = 4; break; } case 7: { m_nDataType = Pixel_Double; m_nBytesPerBand = 8; break; } } m_nBPB = m_nBytesPerBand; m_nOldBytesPerBand = m_nBPB; m_nBPP = m_nBandNum * m_nBPB; if (m_poDataset->GetGeoTransform(adfGeoTransform) == CE_None) { //左上角 m_LBX = adfGeoTransform[0]; m_RTY = adfGeoTransform[3]; m_lfGSD = adfGeoTransform[1]; } else { return false; } //计算出的值 m_RTX = m_LBX + m_lfGSD * m_nImgWidth; m_LBY = m_RTY - m_lfGSD * m_nImgHeight; if (m_nBPB == 2 && b16Trans8 == true) { m_bTranto8bit = true; } else { m_bTranto8bit = false; } if (m_nBPB == 2 && b16Trans8 == true) { int nBandNum = m_nBandNum; if (m_plut) { delete[] m_plut; m_plut = NULL; } m_plut = new unsigned char[nBandNum * 65536]; memset(m_plut, 0, sizeof(unsigned char)* 65536 * nBandNum); //保存lut文件 std::string szFileName = m_strTifPath + ".czb"; if (_access(szFileName.c_str(), 0) == -1) { const int nBlockLength = 5000; double dWidthIniProp = (double)nBlockLength / m_nImgWidth; double dHeightIniProp = (double)nBlockLength / m_nImgHeight; double dIniScale = dWidthIniProp < dHeightIniProp ? dWidthIniProp : dHeightIniProp; int nIniWidth = int(m_nImgWidth * dIniScale + 0.5); int nIniHeight = int(m_nImgHeight * dIniScale + 0.5); if (dIniScale >= 1.0) { //此时不需要缩放 dIniScale = 1.0; nIniWidth = m_nImgWidth; nIniHeight = m_nImgHeight; } unsigned char *m_pBufferPy = new unsigned char[nIniWidth * nIniHeight * nBandNum * m_nBPB]; memset(m_pBufferPy, 0, nIniWidth * nIniHeight * nBandNum * m_nBPB); const int nBlock = 1024; unsigned char *m_pBlockBuffer = new unsigned char[m_nImgWidth * nBandNum * m_nBPB * nBlock]; memset(m_pBlockBuffer, 0, sizeof(unsigned char)* m_nImgWidth * nBandNum * m_nBPB * nBlock); int nBPP = m_nBPB * nBandNum; COneTif tif; tif.m_strTifPath = pszFilename; tif.Initialize(false); int nRowBlockNum = (m_nImgHeight + nBlock - 1) / nBlock; for (int j = 0; j < nRowBlockNum; ++j) { memset(m_pBlockBuffer, 0, sizeof(unsigned char)* m_nImgWidth * nBandNum * m_nBPB * nBlock); tif.ReadImage(0, j * nBlock, m_nImgWidth, nBlock, m_pBlockBuffer, m_nImgWidth, nBlock); for (int m = 0; m < nIniHeight; m++) { int nSrcRows = int(m / dIniScale + 0.5) - j * nBlock; if (nSrcRows >= nBlock || nSrcRows < 0) { continue; } unsigned char *pBufferPyIndex = m_pBufferPy + m * nIniWidth * nBPP; unsigned char *pBufferBlockIndex = m_pBlockBuffer + nSrcRows * m_nImgWidth * nBPP; for (int n = 0; n < nIniWidth; n++) { int nSrcCols = int(n / dIniScale + 0.5); if (nSrcCols >= m_nImgWidth) { continue; } unsigned char *pSubBufferPyIndex = pBufferPyIndex + n * nBPP; unsigned char *pSubBufferBlockIndex = pBufferBlockIndex + nSrcCols * nBPP; memcpy(pSubBufferPyIndex, pSubBufferBlockIndex, nBPP); } } } delete[] m_pBlockBuffer; m_pBlockBuffer = NULL; m_pHist = new double[65536 * nBandNum]; memset(m_pHist, 0, sizeof(double)* 65536 * nBandNum); for (int j = 0; j < nIniHeight; ++j) { unsigned short *pBufferIndex = (unsigned short*)m_pBufferPy + j * nIniWidth * nBandNum; for (int i = 0; i < nIniWidth; ++i) { unsigned short *pSubBufferIndex = pBufferIndex + i * nBandNum; for (int k = 0; k < nBandNum; ++k) { m_pHist[k * 65536 + pSubBufferIndex[k]] += 1.0; } } } if (m_plfCount) { delete[] m_plfCount; m_plfCount = NULL; } m_plfCount = new double[10]; memset(m_plfCount, 0, sizeof(double)* 10); for (int i = 0; i < nBandNum; i++) { for (int j = 1; j < 65536; j++) { m_plfCount[i] += m_pHist[i * 65536 + j]; } } double lfMinThreshold = 0.001, lfMaxThreshold = 0.001; for (int i = 0; i < nBandNum; i++) { double lfTmpCount = 0.0001; int nMinCut = 1, nMaxCut = 65535; for (int j = 1; j < 65536; j++) { lfTmpCount += m_pHist[i * 65536 + j]; if (lfTmpCount / m_plfCount[i] > lfMinThreshold) { nMinCut = j; break; } } int nMinValue = 0, nMaxValue = 0; for (int j = 1; j < 65536; j++) { if (m_pHist[i * 65536 + j] > 1e-3) { nMinValue = j; break; } } for (int j = 65534; j > 0; j--) { if (m_pHist[i * 65536 + j] > 1e-3) { nMaxValue = j; break; } } lfTmpCount = 0.0001; for (int j = 65534; j > 0; j--) { lfTmpCount += m_pHist[i * 65536 + j]; if (lfTmpCount / m_plfCount[i] > lfMaxThreshold) { nMaxCut = j; break; } } for (int j = 1; j < nMinCut; j++) { m_plut[i * 65536 + j] = 1; } for (int j = nMinCut; j <= nMaxCut; j++) { m_plut[i * 65536 + j] = MAX(1, MIN(253, (int)(251.0 * ((double)j - nMinCut) / ((double)nMaxCut - nMinCut) + 2))); } for (int j = nMaxCut + 1; j < 65536; j++) { m_plut[i * 65536 + j] = 254; } } delete[] m_plfCount; m_plfCount = NULL; delete[] m_pHist; m_pHist = NULL; delete[] m_pBufferPy; m_pBufferPy = NULL; FILE *pFile; if (fopen_s(&pFile, szFileName.c_str(), "wb") == 0) { fwrite(m_plut, sizeof(unsigned char), 65536 * m_nBandNum, pFile); // for (int i = 0; i < 65536; ++i) // { // fprintf(pFile, "%d\n", m_pClrLut[i]); // } } fclose(pFile); } else { //读取lut文件 FILE *pFile; if (fopen_s(&pFile, szFileName.c_str(), "rb") == 0) { fread(m_plut, sizeof(unsigned char), 65536 * m_nBandNum, pFile); } fclose(pFile); } } return true; } bool COneTif::ReadImage(int nStartCol, int nStartRow, int nWidth, int nHeight, unsigned char* pData, int nBufferWidth, int nBufferHeight) { if (m_nBandNum == 1) { return ReadImg(nStartCol, nStartRow, nStartCol + nWidth, nStartRow + nHeight, pData, nBufferWidth, nBufferHeight, m_nBandNum, 0, 0, nBufferWidth, nBufferHeight, 0, 0) == 0; } return ReadImg(nStartCol, nStartRow, nStartCol + nWidth, nStartRow + nHeight, pData, nBufferWidth, nBufferHeight, m_nBandNum, 0, 0, nBufferWidth, nBufferHeight, -1, 0) == 0; } int COneTif::ReadImg(int nSrcLeft, int nSrcTop, int nSrcRight, int nSrcBottom, unsigned char* pBuf, int nBufWid, int nBufHeight, int nBandNum, int nDestLeft, int nDestTop, int nDestRight, int nDestBottom, int nSrcSkip, int nDestSkip) { int m_nWidth = m_nImgWidth; int m_nHeight = m_nImgHeight; double lfScale = (nDestRight - nDestLeft) / (double)(nSrcRight - nSrcLeft); if (nSrcLeft >= m_nWidth || nSrcTop >= m_nHeight || nSrcRight <= 0 || nSrcBottom <= 0) { return 1; } int nStartRowOffset = 0, nStartColOffset = 0, nEndRowOffset = 0, nEndColOffset = 0; if (nSrcLeft < 0) { nStartColOffset = -nSrcLeft; } if (nSrcTop < 0) { nStartRowOffset = -nSrcTop; } if (nSrcRight > m_nWidth) { nEndColOffset = m_nWidth - nSrcRight; } if (nSrcBottom > m_nHeight) { nEndRowOffset = m_nHeight - nSrcBottom; } nSrcLeft += nStartColOffset; nSrcRight += nEndColOffset; nSrcTop += nStartRowOffset; nSrcBottom += nEndRowOffset; nDestLeft += int(nStartColOffset*lfScale); nDestRight += int(nEndColOffset*lfScale); nDestTop += int(nStartRowOffset*lfScale); nDestBottom += int(nEndRowOffset*lfScale); if (nSrcSkip == -1) { if (nBandNum != m_nBandNum) { return 1; } int *bandmap = new int[nBandNum]; for (int i = 0; i < nBandNum; ++i) { bandmap[i] = i + 1; } if (!m_bTranto8bit) { CPLErr er = m_poDataset->RasterIO(GF_Read, nSrcLeft, m_nHeight - nSrcBottom, nSrcRight - nSrcLeft, nSrcBottom - nSrcTop, pBuf + (nDestBottom - 1) * nBufWid * m_nBPP + nDestLeft * m_nBPP, nDestRight - nDestLeft, nDestBottom - nDestTop, m_eGDALType, nBandNum, bandmap, m_nBPP, -m_nBPP * nBufWid, m_nBPB); if (CE_Failure == er) { return 1; } } else { unsigned char *temBuf = new unsigned char[m_nOldBytesPerBand*m_nBandNum*nBufHeight*nBufWid]; memset(temBuf, 0, m_nOldBytesPerBand*m_nBandNum*nBufHeight*nBufWid); CPLErr er = m_poDataset->RasterIO(GF_Read, nSrcLeft, m_nHeight - nSrcBottom, nSrcRight - nSrcLeft, nSrcBottom - nSrcTop, temBuf + (nDestBottom - 1) * nBufWid * m_nOldBytesPerBand*nBandNum + nDestLeft * m_nOldBytesPerBand*nBandNum, nDestRight - nDestLeft, nDestBottom - nDestTop, m_eGDALType, nBandNum, bandmap, m_nOldBytesPerBand*nBandNum, -m_nOldBytesPerBand*nBandNum * nBufWid, m_nOldBytesPerBand); if (CE_Failure == er) { return 1; } switch (m_nDataType) { case Pixel_Int16: { unsigned short* pp = (unsigned short*)temBuf; for (int j = nDestTop; j < nDestBottom; ++j) { int nRowOffset = j * nBufWid * nBandNum; unsigned char *pBufferIndex = pBuf + nRowOffset; unsigned short *ppIndex = pp + nRowOffset; for (int i = nDestLeft; i < nDestRight; ++i) { int nColOffset = i * nBandNum; unsigned char *pSubBufferIndex = pBufferIndex + nColOffset; unsigned short *ppSubIndex = ppIndex + nColOffset; int bBackGround = TRUE; for (int nb = 0; nb < nBandNum; ++nb) { if (ppSubIndex[nb] != 0) { bBackGround = FALSE; break; } } if (bBackGround == TRUE) { memset(pSubBufferIndex, 0, nBandNum); } else { for (int nb = 0; nb < nBandNum; ++nb) { pSubBufferIndex[nb] = m_plut[nb * 65536 + ppSubIndex[nb]]; } } } } break; } case Pixel_SInt16: { short* pp = (short*)temBuf; for (int j = nDestTop; j < nDestBottom; ++j) { for (int i = nDestLeft; i < nDestRight; ++i) { for (int nb = 0; nb < m_nBandNum; ++nb) { pBuf[j*nBufWid*nBandNum + i*nBandNum + nb] = m_plut[nb * 65536 + pp[j*nBufWid*nBandNum + i*nBandNum + nb]]; } } } break; } } delete[]temBuf; temBuf = NULL; } delete[] bandmap; bandmap = NULL; } else { if (nDestSkip > nBandNum - 1) { return 1; } if (!m_bTranto8bit) { CPLErr er = m_poDataset->GetRasterBand(nSrcSkip + 1)->RasterIO(GF_Read, nSrcLeft, m_nHeight - nSrcBottom, nSrcRight - nSrcLeft, nSrcBottom - nSrcTop, pBuf + (nDestBottom - 1) * nBufWid * nBandNum* m_nBPB + nDestLeft * nBandNum * m_nBPB + nDestSkip * m_nBPB, nDestRight - nDestLeft, nDestBottom - nDestTop, m_eGDALType, nBandNum * m_nBPB, -nBandNum * m_nBPB * nBufWid); if (CE_Failure == er) { return 1; } } else { unsigned char *temBuf = new unsigned char[m_nOldBytesPerBand*nBufHeight*nBufWid]; CPLErr er = m_poDataset->GetRasterBand(nSrcSkip + 1)->RasterIO(GF_Read, nSrcLeft, m_nHeight - nSrcBottom, nSrcRight - nSrcLeft, nSrcBottom - nSrcTop, temBuf + (nDestBottom - 1) * nBufWid * m_nOldBytesPerBand + nDestLeft * m_nOldBytesPerBand, nDestRight - nDestLeft, nDestBottom - nDestTop, m_eGDALType, m_nOldBytesPerBand, -m_nOldBytesPerBand * nBufWid); if (CE_Failure == er) { return 1; } switch (m_nDataType) { case Pixel_Int16: { unsigned short* pp = (unsigned short*)temBuf; for (int j = nDestTop; j < nDestBottom; ++j) { for (int i = nDestLeft; i < nDestRight; ++i) { pBuf[j*nBufWid*nBandNum + i*nBandNum + nDestSkip] = m_plut[nSrcSkip * 65536 + pp[j*nBufWid + i]]; } } break; } case Pixel_SInt16: { short* pp = (short*)temBuf; for (int j = nDestTop; j < nDestBottom; ++j) { for (int i = nDestLeft; i < nDestRight; ++i) { pBuf[j*nBufWid*nBandNum + i*nBandNum + nDestSkip] = m_plut[nSrcSkip * 65536 + pp[j*nBufWid + i]]; } } break; } } delete[]temBuf; temBuf = NULL; } } return 0; } /****************************************************************************** 函数名: readImageGDAL 功能: 读取图像 参数: unsigned char **pImageData - 指向图像数据指针的指针,将由new操作符动态创建,需要在函数外部由调用者使用delete[]销毁,否则内存泄露 int &width,int &height - 图像宽度、高度,由于是引用,可以作为返回值。 nChannels - 图像通道,可选值为1或3。1代表灰度图像,3代表RGB图像,-1表示按照图像自身通道数目读取。 const char *filePath - 图像文件路径名称 说明:******************************************************************************/ bool COneTif::readImageGDAL(unsigned char **pImageData, int &widthDst, int &heightDst, int &nChannels, const char *filePath) { int width = 0, height = 0; GDALAllRegister(); GDALDataset *poDataset = NULL; poDataset = (GDALDataset*)GDALOpen(filePath, GA_ReadOnly); if (poDataset == NULL) { GDALClose(poDataset); return false; } width = poDataset->GetRasterXSize(); height = poDataset->GetRasterYSize(); if (widthDst <= 0 && heightDst <= 0) { widthDst = width; heightDst = height; } GDALRasterBand* pBand; int i = 0; int nRastercount = poDataset->GetRasterCount(); if (nRastercount == 1) //只有1个通道,则为灰度图像 { nChannels = 1; pBand = poDataset->GetRasterBand(1); *pImageData = new unsigned char[widthDst * heightDst]; pBand->RasterIO(GF_Read, 0, 0, //nXOff,nYOff:从左上角坐标point(nXOff,nYOff)处读取图像数据 width, height, //nXSize,nXSize:要读取的图像数据尺寸,注意可以不是band的实际尺寸,这样就是读取roi区域数据 *pImageData, //pData:读取的数据即将存储的目的地址。 widthDst, heightDst,//nBufXSize,nBufYSize:目的地址处图像的尺寸,如果与roi尺寸不一致,则缩放。 GDT_Byte, //eBufType:读取图像后,将要存储为的类型 0, //nPixelSpace:控制同一行相邻像素间隔,0代表使用目的数据类型大小 0); //nLineSpace:控制相邻行的行间隔,0代表使用[目的数据类型大小 * nXsize] GDALClose(poDataset); return true; } else if (nRastercount == 3 && (nChannels == 3 || nChannels < 0)) //有3个通道,并且输出为RGB图像 { nChannels = 3; *pImageData = new unsigned char[nRastercount * widthDst * heightDst]; for (i = 1; i <= nRastercount; ++i) { //GDAL内band存储顺序为RGB,需要转换为我们一般的BGR存储,即低地址->高地址为:B G R unsigned char *pImageOffset = *pImageData + i - 1; GDALRasterBand* pBand = poDataset->GetRasterBand(nRastercount - i + 1); pBand->RasterIO( GF_Read, 0, 0, width, height, pImageOffset, widthDst, heightDst, GDT_Byte, 3, 0); } GDALClose(poDataset); return true; } else if (nRastercount == 3 && nChannels == 1) //有3个通道,但是要求输出灰度图像 { unsigned char **img = new unsigned char*[nRastercount]; for (i = 0; i < nRastercount; i++) { img[i] = new unsigned char[widthDst * heightDst]; } for (i = 1; i <= nRastercount; ++i) { //GDAL内band存储顺序为RGB,需要转换为我们一般的BGR存储,即低地址->高地址为:B G R pBand = poDataset->GetRasterBand(nRastercount - i + 1); pBand->RasterIO(GF_Read, 0, 0, width, height, img[i - 1], widthDst, heightDst, GDT_Byte, 0, 0); } GDALClose(poDataset); *pImageData = new unsigned char[widthDst*heightDst]; for (int r = 0; r < heightDst; ++r) { for (int c = 0; c < widthDst; ++c) { int t = (r*widthDst + c); //r g b分量依次占:0.299 0.587 0.144,可简化为3:6:1 //img[1.2.3]依次对应BGR (*pImageData)[t] = (img[2][t] * 3 + img[1][t] * 6 + img[0][t] + 5) / 10; } } for (i = 0; i < nRastercount; ++i) { delete[] img[i]; } delete[]img; img = NULL; return true; } else { return false; } } char* COneTif::findImageTypeGDAL(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; } bool COneTif::WriteImageGDAL(const char* pDstImgFileName, unsigned char *pImageData, int width, int height, int nChannels) { if ((pDstImgFileName == NULL || pImageData == NULL || width <1 || height < 1 || nChannels < 1)) { return false; } GDALAllRegister(); char *GType = NULL; GType = findImageTypeGDAL((char*)pDstImgFileName); if (GType == NULL) { return false; } GDALDriver *pMemDriver = NULL; pMemDriver = GetGDALDriverManager()->GetDriverByName("MEM"); if (pMemDriver == NULL) { return false; } GDALDataset * pMemDataSet = pMemDriver->Create("", width, height, nChannels, GDT_Byte, NULL); GDALRasterBand *pBand = NULL; int nLineCount = width * nChannels; unsigned char *ptr1 = (unsigned char *)pImageData; for (int i = 1; i <= nChannels; i++) { pBand = pMemDataSet->GetRasterBand(nChannels - i + 1); pBand->RasterIO(GF_Write, 0, 0, width, height, ptr1 + i - 1, width, height, GDT_Byte, nChannels, nLineCount); } GDALDriver *pDstDriver = NULL; pDstDriver = (GDALDriver *)GDALGetDriverByName(GType); if (pDstDriver == NULL) { return false; } GDALDataset* Dstds = pDstDriver->CreateCopy(pDstImgFileName, pMemDataSet, FALSE, NULL, NULL, NULL); GDALClose(pMemDataSet); GDALClose(Dstds); return true; }