OpenCV的Mat 等价GDAL的数据(float型)

GDAL 数据读取(float型)与 OpenCV数据读取的等价

开发环境:VS2015+QT5.7.0
工程已配置好GDAL与OpenCV

在遥感影像数据处理中,我们常常要利用GDAL强大的对各类数据的支持能力读取数据,然后利用OpenCV丰富的算法库处理数据。

在做项目编码的过程中,我碰到一个需要把GDAL的数据转成MAT数据的问题。GDAL读取数据时数据的组织方式是RRR…GGG…BBB…,而OpenCV的Mat组织数据的方式是BGRBGRBGR…要实现这样的互转很容易,利用OpenCV的split()函数可以实现。示例如下:

这里写代码片
//GDAL//支持中文路径
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");

//QString 转 const char*
QString m_strPath = "文件路径";
QByteArray ba = m_strPath.toLocal8Bit();
const char* ch = ba.data();

//GDAL数据集 
GDALDataset *m_pDataset = (GDALDataset *)GDALOpen(ch, GA_ReadOnly);
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
if (m_pDataset == nullptr)
{
    QMessageBox::information(this, tr("error"), tr("open file failed!!!"));
    return ;
}

int bandCount = m_pDataset->GetRasterCount();//波段的数目
int width = m_pDataset->GetRasterXSize();
int height = m_pDataset->GetRasterYSize();

float* buf = new float[pIM->Width*pIM->Height];
GDALRasterBand  *m_pBand = NULL;
for (d = 0; d < bandCount; ++d)
{
    m_pBand = m_pDataset->GetRasterBand(d + 1);
    if (m_pBand)
    { 
       //读取数据,buf存储一个波段数据
       if (CE_None == m_pBand->RasterIO(GF_Read, 0, 0, width, height, buf, width, height, GDT_Float32, 0, 0))
       {
           //数据处理
       }
    }
}

delete[] buf;


//OpenCV
Mat pSrcMat = imread(ch, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
if (!pSrcMat.data) 
{ 
    QMessageBox::information(this, tr("error"), tr("open file failed!!!"));
    return;
}
int bandCount = pSrcMat.channels();
int width = pSrcMat.cols;
int height = pSrcMat.rows;
//!将通道分开
//!imgMat每个通道数据连续
std::vector<cv::Mat> bgrMat(bandCount);
cv::split(pSrcMat, bgrMat);

float* buf = new float[pIM->Width*pIM->Height];
for(int d = 0; d<bandCount; ++d)
{
    buf = (float* )bgrMat[2-d].data;
    //数据处理

}

如果要处理的数据类型是uchar,那这样转换应该就可以了。但是这里我要处理的是float型数据,由于OpenCV的imread函数总是把数据读成uchar型,这样的转换就会出问题。这时候需要加上如下代码:在用split()函数将通道分开后面,

这里写代码片  //格式转换
    std::vector<cv::Mat> matOut;
    QVector<double> _bandMaxS;
    QVector<double> _bandMinS;
    for (int i(0); i < bgrMat.size(); i++)
    {
        double max = _bandMaxS[i];
        double min = _bandMinS[i];
        cv::Mat cur = bgrMat[i];
        makeNormal(GDT_Float32, cur, max, min);
        matOut.push_back(cur);
    }

其中的makeNormal()函数定义在这个源文件(.cpp)的头文件(.h)中(priviate), 函数内容如下:

这里写代码片  void makeNormal(GDALDataType type, cv::Mat& cur, double max, double min) const
    {
        switch (type)
        {
        case GDT_Byte:
            this->normalize(cur, cur, 0, UCHAR_MAX, CV_8U, max, min);
            break;
        case GDT_UInt16:
            this->normalize(cur, cur, 0, UINT16_MAX, CV_16U, max, min);
            break;
        case GDT_Int16:
            this->normalize(cur, cur, INT16_MIN, INT16_MAX, CV_16S, max, min);
            break;
        case GDT_UInt32:
            this->normalize(cur, cur, 0, UINT32_MAX, CV_32F, max, min);
            break;
        case GDT_Int32:
            this->normalize(cur, cur, INT32_MIN, INT32_MAX, CV_32S, max, min);
            break;
        case GDT_Float32:
            cur.convertTo(cur, CV_32F);
            break;
        case GDT_Float64:
            cur.convertTo(cur, CV_64F);
            break;
        case GDT_CInt16: break;
        case GDT_CInt32: break;
        case GDT_CFloat32: break;
        case GDT_CFloat64: break;
        case GDT_TypeCount: break;
        case GDT_Unknown: break;
        default: break;
        }
    }

normalize()定义在头文件的public:

这里写代码片  static void normalize(const cv::Mat& _src, cv::Mat& _dst, double a, double b,
        int rtype, double smax = 0, double smin = 0)
    {
        double scale = 1, shift = 0;
        if (smax - 0 < DBL_EPSILON)
        {
            cv::minMaxLoc(_src, &smin, &smax, 0, 0);
        }
        double dmin = MIN(a, b), dmax = MAX(a, b);
        scale = (dmax - dmin) * (smax - smin > DBL_EPSILON ? 1. / (smax - smin) : 0);
        shift = dmin - smin * scale;

        int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
        cv::Mat res;
        res.create(_src.size(), CV_MAKETYPE(rtype, cn));

        cv::Mat src = _src, dst = res;
        src.convertTo(dst, rtype, scale, shift);
        _dst = res;

相应的头文件要包含。通过这样的转换,可以把GDAL读取的数据用Mat来表示。这样做的目的是项目小组已经将数据读取封装成为输出分块的Mat,将算法的输入输出改为Mat, 算法的调用更方便,算法本身不需要考虑数据分块等问题。

OpenCV中的图像数据转换为GDAL图像数据需要进行以下步骤: 1. 创建GDAL数据集 ```c++ GDALDataset *poDataset; poDataset = (GDALDataset*)GDALCreate( GDALDriverManager::GetDriverByName("GTiff"), "output.tif", nCols, nRows, nBands, GDT_Byte, NULL ); ``` 其中,nCols和nRows为图像的宽度和高度,nBands为图像的通道(例如RGB图像为3通道)。 2. 将OpenCV图像数据复制到GDAL数据集中 ```c++ for( i = 0; i < nBands; ++i ) { poBand = poDataset->GetRasterBand( i + 1 ); poBand->RasterIO( GF_Write, 0, 0, nCols, nRows, pData + i*nCols*nRows, nCols, nRows, GDT_Byte, 0, 0 ); } ``` 其中,pData为OpenCV图像数据的指针,需要根据通道计算偏移量,例如第二个通道的数据在pData + nCols*nRows处。 完整的代码示例: ```c++ #include "opencv2/opencv.hpp" #include "gdal_priv.h" using namespace cv; int main() { // 加载OpenCV图像 Mat img = imread("input.png", CV_LOAD_IMAGE_COLOR); if (img.empty()) { printf("Could not load image!\n"); return -1; } int nCols = img.cols; int nRows = img.rows; int nBands = img.channels(); uchar *pData = img.data; // 创建GDAL数据GDALDataset *poDataset; GDALAllRegister(); poDataset = (GDALDataset*)GDALCreate( GDALDriverManager::GetDriverByName("GTiff"), "output.tif", nCols, nRows, nBands, GDT_Byte, NULL ); if (poDataset == NULL) { printf("Could not create GDAL dataset!\n"); return -1; } // 将OpenCV图像数据复制到GDAL数据集中 GDALRasterBand *poBand; int i; for( i = 0; i < nBands; ++i ) { poBand = poDataset->GetRasterBand( i + 1 ); poBand->RasterIO( GF_Write, 0, 0, nCols, nRows, pData + i*nCols*nRows, nCols, nRows, GDT_Byte, 0, 0 ); } // 释放GDAL数据GDALClose((GDALDatasetH) poDataset); return 0; } ``` 注意,需要在程序中包含`gdal_priv.h`头文件,并链接GDAL库。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值