opencv(c++)遥感影像加载与保存

8 篇文章 0 订阅
7 篇文章 0 订阅

参考:
1、https://docs.opencv.org/3.2.0/d7/d73/tutorial_raster_io_gdal.html
2、http://www.cnblogs.com/zyore2013/p/4657702.html
3、http://www.cnblogs.com/zyore2013/p/5815941.html
4、http://blog.csdn.net/liminlu0314/article/details/7433936


1、使用imread加载

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    char* img_path = "D:/14.tif";

    //加载图像,这样加载没有投影信息
    Mat image = imread(img_path, IMREAD_LOAD_GDAL | IMREAD_COLOR | IMREAD_ANYDEPTH);

    //判断是否加载成功
    if (!image.data) //或者image.empty()
    {
        cout << img_path << "  cannot open!" << endl;
        return -1;
    }
    // 输出图像大小信息 C x W x H
    cout << image.channels()<<" x " <<image.rows<<" x "<<image.cols<< endl; 

    //转成灰度
    Mat dst;
    cvtColor(image, dst, COLOR_BGR2GRAY);

    //显示图像
    namedWindow("src", 1);
    namedWindow("dst", 1);
    imshow("src", image);
    imshow("dst", dst);
    waitKey(0);
    destroyAllWindows();

    //保存转换的图像
    imwrite("D:/14_2.tif", dst);

    return 0;
}

注:直接使用imread加载遥感影像不会有投影信息,且只能加载不超过3波段的影像


2、结合GDAL

GDAL读取遥感图像在转成Mat,再保存
参考:
1、http://www.cnblogs.com/zyore2013/p/4657702.html
2、http://www.cnblogs.com/zyore2013/p/5815941.html
3、http://blog.csdn.net/liminlu0314/article/details/7433936

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <gdal.h>
#include <gdal_priv.h>  
#include <iostream>
#include <string>
#include <vector>

using namespace std;
using namespace cv;


/*! byte */
typedef unsigned char   byte;
/*! 8U */
typedef unsigned char   DT_8U;
/*! 16U */
typedef unsigned short  DT_16U;
/*! 16S */
typedef short           DT_16S;
/*! 32U */
typedef unsigned int    DT_32U;
/*! 32S */
typedef int             DT_32S;
/*! 32F */
typedef float           DT_32F;
/*! 64F */
typedef double          DT_64F;

//创建一个存放影像信息的structure
typedef struct
{
    //GDALDataset *poDataset = NULL;
    int Xsize=0;
    int Ysize=0;
    int nbands=0;
    double *tmpadfGeoTransform=new double[6]; //存储地理6参数
    const char* proj = NULL;//存储投影
    GDALDataType iDataType = GDT_Byte;
}MyStruct;

cv::Mat GDAL2Mat(GDALDataset *poDataset, MyStruct &St);
bool Mat2File(cv::Mat img, MyStruct &St, GDALDataset *poDataset);

int main()
{
    //注册驱动  
    GDALAllRegister();

    string  src_path = "D:/14.tif";
    string dst_path = "D:/14_2.tif";

    MyStruct St;
    GDALDataset *poDataset = (GDALDataset *)GDALOpen(src_path.c_str(), GA_ReadOnly);

    St.Xsize = poDataset->GetRasterXSize();
    St.Ysize = poDataset->GetRasterYSize();
    St.nbands = poDataset->GetRasterCount();
    poDataset->GetGeoTransform(St.tmpadfGeoTransform);
    St.proj = poDataset->GetProjectionRef();
    //获取数据类型
    St.iDataType = poDataset->GetRasterBand(1)->GetRasterDataType();


    Mat img = GDAL2Mat(poDataset, St);

    /*
    //直接保存mat
    std::vector<cv::Mat> imgMat(St.nbands);
    std::vector<cv::Mat> tempMat(St.nbands);
    cv::split(img, imgMat);
    tempMat.at(0) = (imgMat.at(2));//BGR-->RGB
    tempMat.at(1) = (imgMat.at(1));
    tempMat.at(2) = (imgMat.at(0));
    Mat img2;
    cv::merge(tempMat, img2);
    imgMat.clear();
    tempMat.clear();
    imwrite("D:/14_3.tif", img2);
    */



    //判断是否加载成功
    if (!img.data) //或者image.empty()
    {
        cout << src_path << "  cannot open!" << endl;
        return -1;
    }

    //定义输出数据
    GDALDataset *poDataset2;   //GDAL数据集
    GDALDriver *poDriver;      //驱动,用于创建新的文件
    //poDriver = GetGDALDriverManager()->GetDriverByName("ENVI");
    poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");

    if (poDriver == NULL)
        return 0;
    poDataset2 = poDriver->Create(dst_path.c_str(), St.Xsize, St.Ysize, St.nbands,
        St.iDataType, NULL);//GDT_Float32

    //重新设置地理参考和投影系
    poDataset2->SetGeoTransform(St.tmpadfGeoTransform);
    poDataset2->SetProjection(St.proj);

    GDALClose((GDALDatasetH)poDataset);


    Mat2File(img, St, poDataset2);

    GDALClose((GDALDatasetH)poDataset2);


    return 0;
}

//GDAL数据转opencv的Mat格式
cv::Mat GDAL2Mat(GDALDataset *poDataset,MyStruct &St)  //const QString fileName
{
    //获取数据类型
    //GDALDataType iDataType = poDataset->GetRasterBand(1)->GetRasterDataType();
    //int idepth = GDALGetDataTypeSize((GDALDataType)iDataType);

    //将GDAL的数据类型与Mat的数据类型对应起来
    auto MdataType = NULL;
    auto MdataTypes = NULL;
    if (St.iDataType == GDT_Byte)
    {
        MdataType = CV_MAKETYPE(CV_8U, 1);
        MdataTypes= CV_MAKETYPE(CV_8U, St.nbands);
    }
    if (St.iDataType == GDT_UInt16)
    {
        MdataType = CV_MAKETYPE(CV_16U, 1);
        MdataTypes = CV_MAKETYPE(CV_16U, St.nbands);
    }

    //QVector <cv::Mat> imgMat;  
    vector<Mat> imgMat;// 每个波段
    float *pafScan = new float[St.Xsize*St.Ysize];   // 存储数据

    for (int i = 0; i< St.nbands; i++)
    {
        GDALRasterBand *pBand = poDataset->GetRasterBand(i + 1);
        //pafScan = new float[tmpCols*tmpRows];
        pBand->RasterIO(GF_Read, 0, 0, St.Xsize, St.Ysize, pafScan,
            St.Xsize, St.Ysize, St.iDataType, 0, 0); //GDT_Float32
        cv::Mat tmpMat = cv::Mat(St.Ysize, St.Xsize, MdataType, pafScan);//CV_32FC1
        imgMat.push_back(tmpMat.clone());
    }
    delete[]pafScan;
    pafScan = NULL;

    cv::Mat img;
    img.create(St.Ysize, St.Xsize, MdataTypes); //CV_32FC(tmpBandSize)
    //cv::merge(imgMat.toStdVector(), img);
    cv::merge(imgMat, img);
    //释放内存
    imgMat.clear();
    //GDALClose((GDALDatasetH)poDataset);
    return img;
}

//Mat 数据保存
bool Mat2File(cv::Mat img,MyStruct &St, GDALDataset *poDataset)//const QString fileName
{
    if (img.empty())    //    判断是否为空
        return 0;

    const int nBandCount = St.nbands;
    const int nImgSizeX = St.Xsize;
    const int nImgSizeY = St.Ysize;

    //    将通道分开
    //  imgMat每个通道数据连续
    std::vector<cv::Mat> imgMat(nBandCount);
    cv::split(img, imgMat);

    //  分波段写入文件
    GDALAllRegister();


    //  循环写入文件
    GDALRasterBand *pBand = NULL;
    float *ppafScan = new float[nImgSizeX*nImgSizeY];
    cv::Mat tmpMat;// = cv::Mat(nImgSizeY,nImgSizeX,CV_32FC1);

    for (int i = 1; i <= nBandCount; i++)
    {
        pBand = poDataset->GetRasterBand(i);
        tmpMat = imgMat.at(i - 1);
        if (tmpMat.isContinuous())
        {
            if(St.iDataType==GDT_Byte)
                memmove(ppafScan, (void*)tmpMat.ptr(0), sizeof(unsigned char)*nImgSizeX*nImgSizeY);//GDT_Byte
            if(St.iDataType==GDT_UInt16)
                memmove(ppafScan, (void*)tmpMat.ptr(0), sizeof(unsigned short)*nImgSizeX*nImgSizeY);//GDT_Uint16
            //memmove(ppafScan, (void*)tmpMat.ptr(0),sizeof(float)*nImgSizeX*nImgSizeY);//GDT_Float32
        }
        else
            return false;

        CPLErr err = pBand->RasterIO(GF_Write, 0, 0, nImgSizeX, nImgSizeY, ppafScan,
            nImgSizeX, nImgSizeY, St.iDataType, 0, 0);
    }
    delete[] ppafScan;
    ppafScan = NULL;
    imgMat.clear();
    //GDALClose(poDataset);
    return 1;
}

3、使用imwrite保存

先使用GDAL与opencv将影像转成Mat,再直接使用opencv的imwrite保存Mat,只能针对不超过3波段的数据,而且保存的影像没有坐标。如果波段数不超过3,位数为8bit,推荐使用第一种方法加载图像,该方法保存;其他使用第二种方法加载图像和保存

//直接保存mat
    std::vector<cv::Mat> imgMat(St.nbands);
    std::vector<cv::Mat> tempMat(St.nbands);
    cv::split(img, imgMat);

    tempMat.at(0) = imgMat.at(2);//BGR-->RGB
    tempMat.at(1) = imgMat.at(1);
    tempMat.at(2) = imgMat.at(0);

    Mat img2;
    cv::merge(tempMat, img2);
    imgMat.clear();
    tempMat.clear();
    imwrite("D:/14_3.tif", img2);

本程序主要对遥感图像实现三种处理:几何校正、图像增强和图像配准。这三种处理都可以独立实现,然而对于原始的遥感图像将这三种处理依次进行效果更佳。 具体操作步骤如下: 1.在主窗口打开图像1 2.选择【几何校正】菜单,打开【图像几何校正】对话框进行几何校正。在此对话框中,首先打开待校正图像2,然后点击【选取特正点】按钮,按照提示依次在待校正图像和基准图像中手动选取特征点,最后点击【校正图像】得到几何校正结果,如果达到预期效果,则点击【保存并在主窗口打开】按钮,保存此校正图片,并在主窗口打开。 3.选择【图像增强】菜单,打开【图像增强】对话框进行图像增强。在此对话框中,首先在相应的处理类别(如:直方图增强、灰度增强等)中选择具体方法(如:均衡化、规定化等),然后点击本类别的按钮。增强后的结果会在右侧显示,如果达到预期效果,则点击【保存并在主窗口打开】按钮,保存此增强后的图片,并在主窗口打开。 4.选择【图像配准】菜单,打开【图像配准】对话框进行图像配准。在此对话框中,首先打开待匹配图像3,然后选择“半自动”或“手动”方法并点击【选取特正点】按钮,按照提示依次在待配准图像和基准图像中半自动或手动选取特征点(如果在半自动选取中特征点对应错误,可以更改特征点),最后点击【匹配图像】得到图像配准结果,如果达到预期效果,则点击【保存并在主窗口打开】按钮,保存此校正图片,并在主窗口打开。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值