RasterProcessTool/BaseCommonLibrary/BaseTool/MergeRasterOperator.cpp

489 lines
16 KiB
C++
Raw Normal View History

2025-03-25 08:41:05 +00:00
#include "stdafx.h"
#include "ImageOperatorBase.h"
#include "BaseTool.h"
#include "GeoOperator.h"
#include <Eigen/Core>
#include <Eigen/Dense>
#include <omp.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <gdal.h>
#include <gdal_utils.h>
#include <gdal_priv.h>
#include <gdalwarper.h>
#include <proj.h>
#include <string.h>
#include <memory>
#include <iostream>
#include "FileOperator.h"
#include <opencv2/opencv.hpp>
#include <QMessageBox>
#include <QDir>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <QProgressDialog>
#include <gdal_priv.h>
#include <ogr_spatialref.h> // OGRSpatialReference <20><><EFBFBD>ڿռ<DABF><D5BC>ο<EFBFBD>ת<EFBFBD><D7AA>
#include <gdal_alg.h> // <20><><EFBFBD><EFBFBD> GDALWarp <20><><EFBFBD><EFBFBD>
ErrorCode MergeRasterProcess(QVector<QString> filepaths, QString outfileptah, QString mainString, MERGEMODE mergecode, bool isENVI, ShowProessAbstract* dia)
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (!isExists(mainString)) {
qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::FILENOFOUND)) << "\t" << mainString;
return ErrorCode::FILENOFOUND;
}
else {}
gdalImage mainimg(mainString);
QVector<gdalImage> imgdslist(filepaths.count());
for (long i = 0; i < filepaths.count(); i++) {
if (!isExists(filepaths[i])) {
qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::FILENOFOUND)) << "\t" << filepaths[i];
return ErrorCode::FILENOFOUND;
}
else {
imgdslist[i] = gdalImage(filepaths[i]);
if (imgdslist[i].band_num != mainimg.band_num) {
qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::RASTERBAND_NOTEQUAL)) << "\t" << imgdslist[i].band_num << " != " << mainimg.band_num;
return ErrorCode::RASTERBAND_NOTEQUAL;
}
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD>Ƿ<EFBFBD>ͳһ
long EPSGCode = GetEPSGFromRasterFile(mainString);
long tempCode = 0;
for (long i = 0; i < filepaths.count(); i++) {
tempCode = GetEPSGFromRasterFile(filepaths[i]);
if (EPSGCode != tempCode) {
qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::EPSGCODE_NOTSAME)) << "\t" << EPSGCode << "!=" << tempCode;
return ErrorCode::EPSGCODE_NOTSAME;
}
}
// <20><><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>ͳһ
GDALDataType mainType = mainimg.getDataType();
for (long i = 0; i < imgdslist.count(); i++) {
if (mainType != imgdslist[i].getDataType()) {
qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::RASTER_DATETYPE_NOTSAME)) << "\t" << mainType << "!=" << imgdslist[i].getDataType();
return ErrorCode::RASTER_DATETYPE_NOTSAME;
}
}
Eigen::MatrixXd maingt = mainimg.getGeoTranslation();
Eigen::MatrixXd rgt = Eigen::MatrixXd::Zero(2, 3);
RasterExtend mainExtend = mainimg.getExtend();
rgt(0, 1) = (mainExtend.max_x - mainExtend.min_x) / (mainimg.width - 1); //dx
rgt(1, 2) = -1 * std::abs(((mainExtend.max_y - mainExtend.min_y) / (mainimg.height - 1)));//dy
QVector<RasterExtend> extendlist(imgdslist.count());
for (long i = 0; i < imgdslist.count(); i++) {
extendlist[i] = imgdslist[i].getExtend();
mainExtend.min_x = mainExtend.min_x < extendlist[i].min_x ? mainExtend.min_x : extendlist[i].min_x;
mainExtend.max_x = mainExtend.max_x > extendlist[i].max_x ? mainExtend.max_x : extendlist[i].max_x;
mainExtend.min_y = mainExtend.min_y < extendlist[i].min_y ? mainExtend.min_y : extendlist[i].min_y;
mainExtend.max_y = mainExtend.max_y > extendlist[i].max_y ? mainExtend.max_y : extendlist[i].max_y;
}
rgt(0, 0) = mainExtend.min_x;
rgt(1, 0) = mainExtend.max_y;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
long width = std::ceil((mainExtend.max_x - mainExtend.min_x) / rgt(0, 1) + 1);
long height = std::ceil(std::abs((mainExtend.min_y - mainExtend.max_y) / rgt(1, 2)) + 1);
OGRSpatialReference oSRS;
if (oSRS.importFromEPSG(EPSGCode) != OGRERR_NONE) {
qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::EPSGCODE_NOTSUPPORT)) << "\t" << EPSGCode;
return ErrorCode::EPSGCODE_NOTSUPPORT;
}
gdalImage resultImage = CreategdalImage(outfileptah, height, width, mainimg.band_num, rgt, EPSGCode, mainType, true, true, isENVI);
QString resultMaskString = addMaskToFileName(outfileptah, QString("_MASK"));
gdalImage maskImage = CreategdalImage(resultMaskString, height, width, 1, rgt, EPSGCode, GDT_Int32, true, true, isENVI);
// <20><>ʼ<EFBFBD><CABC>
long resultline = Memory1MB * 500 / 8 / resultImage.width;
resultline = resultline < 10000 ? resultline : 10000; // <20><><EFBFBD><EFBFBD>100<30><30>
resultline = resultline > 0 ? resultline : 2;
long bandnum = resultImage.band_num + 1;
long starti = 0;
long rasterCount = imgdslist.count();
QProgressDialog progressDialog(u8"<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>Ӱ<EFBFBD><EFBFBD>", u8"<EFBFBD><EFBFBD>ֹ", 0, resultImage.height);
progressDialog.setWindowTitle(u8"<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>Ӱ<EFBFBD><EFBFBD>");
progressDialog.setWindowModality(Qt::WindowModal);
progressDialog.setAutoClose(true);
progressDialog.setValue(0);
progressDialog.setMaximum(resultImage.height);
progressDialog.setMinimum(0);
progressDialog.show();
for (starti = 0; starti < resultImage.height; starti = starti + resultline) {
long blocklines = resultline;
blocklines = starti + blocklines < resultImage.height ? blocklines : resultImage.height - starti;
for (long b = 1; b < bandnum; b++) {
Eigen::MatrixXd data = resultImage.getData(starti, 0, blocklines, resultImage.width, b);
Eigen::MatrixXi maskdata = maskImage.getDatai(starti, 0, blocklines, resultImage.width, b);
data = data.array() * 0;
maskdata = maskdata.array() * 0;
resultImage.saveImage(data, starti, 0, b);
maskImage.saveImage(maskdata, starti, 0, b);
}
if (nullptr != dia) {
dia->showProcess(starti * 1.0 / resultImage.height, u8"<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>Ӱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
}
progressDialog.setValue(starti + blocklines);
}
progressDialog.close();
switch (mergecode)
{
case MERGE_GEOCODING:
return MergeRasterInGeoCoding(imgdslist, resultImage, maskImage, dia);
default:
break;
}
return ErrorCode::SUCCESS;
}
ErrorCode MergeRasterInGeoCoding(QVector<gdalImage> imgdslist, gdalImage resultimg, gdalImage maskimg, ShowProessAbstract* dia)
{
omp_set_num_threads(Paral_num_thread);
// <20><><EFBFBD><EFBFBD><EFBFBD>ϲ<EFBFBD><CFB2><EFBFBD><EFBFBD><EFBFBD>
QVector<RasterExtend> extendlist(imgdslist.count());
for (long i = 0; i < imgdslist.count(); i++) {
extendlist[i] = imgdslist[i].getExtend();
imgdslist[i].InitInv_gt();
}
// <20>ֿ<EFBFBD><D6BF><EFBFBD><EFBFBD><EFBFBD>
long resultline = Memory1MB * 1000 / 8 / resultimg.width;
resultline = resultline < 300 ? resultline : 300; // <20><><EFBFBD><EFBFBD>100<30><30>
long bandnum = resultimg.band_num + 1;
long starti = 0;
long rasterCount = imgdslist.count();
long processNumber = 0;
QProgressDialog progressDialog(u8"<EFBFBD>ϲ<EFBFBD>Ӱ<EFBFBD><EFBFBD>", u8"<EFBFBD><EFBFBD>ֹ", 0, resultimg.height);
progressDialog.setWindowTitle(u8"<EFBFBD>ϲ<EFBFBD>Ӱ<EFBFBD><EFBFBD>");
progressDialog.setWindowModality(Qt::WindowModal);
progressDialog.setAutoClose(true);
progressDialog.setValue(0);
progressDialog.setMaximum(resultimg.height);
progressDialog.setMinimum(0);
progressDialog.show();
omp_lock_t lock;
omp_init_lock(&lock);
#pragma omp parallel for
for (starti = 0; starti < resultimg.height; starti = starti + resultline) {
long blocklines = resultline;
blocklines = starti + blocklines < resultimg.height ? blocklines : resultimg.height - starti;
long rid = starti;
long cid = 0;
Landpoint pp = { 0,0,0 };
Landpoint lp = { 0,0,0 };
for (long ir = 0; ir < rasterCount; ir++) {// Ӱ<><D3B0>
long minRid = imgdslist[ir].height;
long maxRid = 0;
Eigen::MatrixXd ridlist = resultimg.getData(starti, 0, blocklines, resultimg.width, 1);
ridlist = ridlist.array() * 0;
Eigen::MatrixXd cidlist = ridlist.array() * 0;
for (long i = 0; i < blocklines; i++) {// <20>к<EFBFBD>
rid = starti + i;
for (long j = 0; j < resultimg.width; j++) {// <20>к<EFBFBD>
cid = j;
resultimg.getLandPoint(rid, cid, 0, pp);
lp = imgdslist[ir].getRow_Col(pp.lon, pp.lat); // <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ridlist(i, j) = lp.lat;
cidlist(i, j) = lp.lon;
}
}
//ImageShowDialogClass* dialog = new ImageShowDialogClass;
//dialog->show();
//dialog->load_double_MatrixX_data(cidlist, u8"");
//dialog->exec();
if (ridlist.maxCoeff() < 0 || ridlist.minCoeff() >= imgdslist[ir].height) {
continue;
}
if (cidlist.maxCoeff() < 0 || cidlist.minCoeff() >= imgdslist[ir].width) {
continue;
}
minRid = std::floor(ridlist.minCoeff());
maxRid = std::ceil(ridlist.maxCoeff());
minRid = minRid < 0 ? 0 : minRid;
maxRid = maxRid < imgdslist[ir].height ? maxRid : imgdslist[ir].height - 1;
long rowlen = maxRid - minRid + 1;
if (rowlen <= 0) {
continue;
}
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Landpoint p0{ 0,0,0 }, p11{ 0,0,0 }, p21{ 0,0,0 }, p12{ 0,0,0 }, p22{ 0,0,0 }, p{ 0,0,0 };
long rowcount = 0;
long colcount = 0;
double ridtemp = 0, cidtemp = 0;
long lastr = 0, nextr = 0;
long lastc = 0, nextc = 0;
double r0 = 0, c0 = 0;
for (long b = 1; b < bandnum; b++) {
Eigen::MatrixXd resultdata = resultimg.getData(starti, 0, blocklines, resultimg.width, b);
Eigen::MatrixXi resultmask = maskimg.getDatai(starti, 0, blocklines, resultimg.width, b);
Eigen::MatrixXd data = imgdslist[ir].getData(minRid, 0, rowlen, imgdslist[ir].width, b);
double nodata = imgdslist[ir].getNoDataValue(b);
for (long ii = 0; ii < data.rows(); ii++) {
for (long jj = 0; jj < data.cols(); jj++) {
if (std::abs(data(ii, jj) - nodata) < 1e-6) {
data(ii, jj) = 0;
}
}
}
rowcount = ridlist.rows();
colcount = ridlist.cols();
double Bileanervalue = 0;
for (long i = 0; i < rowcount; i++) {
for (long j = 0; j < colcount; j++) {
ridtemp = ridlist(i, j);
cidtemp = cidlist(i, j);
lastr = std::floor(ridtemp);
nextr = std::ceil(ridtemp);
lastc = std::floor(cidtemp);
nextc = std::ceil(cidtemp);
if (lastr < 0 || lastr >= imgdslist[ir].height
|| nextr < 0 || nextr >= imgdslist[ir].height
|| lastc < 0 || lastc >= imgdslist[ir].width
|| nextc < 0 || nextc >= imgdslist[ir].width) {
continue;
}
else {}
r0 = ridtemp - std::floor(ridtemp);
c0 = cidtemp - std::floor(cidtemp);
lastr = lastr - minRid;
nextr = nextr - minRid;
p0 = Landpoint{ c0,r0,0 };
p11 = Landpoint{ 0,0,data(lastr,lastc) };
p21 = Landpoint{ 0,1,data(nextr,lastc) };
p12 = Landpoint{ 1,0,data(lastr,nextc) };
p22 = Landpoint{ 1,1,data(nextr,nextc) };
Bileanervalue = Bilinear_interpolation(p0, p11, p21, p12, p22);
if (std::abs(Bileanervalue) < 1e-6 || resultmask(i, j) > 0) {
continue;
}
resultdata(i, j) = resultdata(i, j) + Bileanervalue;
resultmask(i, j) = resultmask(i, j) + 1;
}
}
resultimg.saveImage(resultdata, starti, 0, b);
maskimg.saveImage(resultmask, starti, 0, b);
}
}
omp_set_lock(&lock);
processNumber = processNumber + blocklines;
qDebug() << "\rprocess bar:\t" << processNumber * 100.0 / resultimg.height << " % " << "\t\t\t";
if (nullptr != dia) {
dia->showProcess(processNumber * 1.0 / resultimg.height, u8"<EFBFBD>ϲ<EFBFBD>ͼ<EFBFBD><EFBFBD>");
}
if (progressDialog.maximum() <= processNumber) {
processNumber = progressDialog.maximum() - 1;
}
progressDialog.setValue(processNumber);
omp_unset_lock(&lock);
}
omp_destroy_lock(&lock);
progressDialog.setWindowTitle(u8"Ӱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĥ");
progressDialog.setLabelText(u8"Ӱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĥ");
for (starti = 0; starti < resultimg.height; starti = starti + resultline) {
long blocklines = resultline;
blocklines = starti + blocklines < resultimg.height ? blocklines : resultimg.height - starti;
for (long b = 1; b < bandnum; b++) {
Eigen::MatrixXd data = resultimg.getData(starti, 0, blocklines, resultimg.width, b);
Eigen::MatrixXd maskdata = maskimg.getData(starti, 0, blocklines, maskimg.width, b);
for (long i = 0; i < data.rows(); i++) {
for (long j = 0; j < data.cols(); j++) {
if (maskdata(i, j) == 0) {
data(i, j) = -9999;
continue;
}
data(i, j) = data(i, j) / maskdata(i, j);
}
}
resultimg.saveImage(data, starti, 0, b);
maskimg.saveImage(maskdata, starti, 0, b);
}
if (nullptr != dia) {
dia->showProcess((starti + blocklines) * 1.0 / resultimg.height, u8"Ӱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĥ");
}
progressDialog.setValue(starti + blocklines);
}
progressDialog.close();
return ErrorCode::SUCCESS;
}
void MergeTiffs(QList<QString> inputFiles, QString outputFile) {
GDALAllRegister();
if (inputFiles.isEmpty()) {
fprintf(stderr, "No input files provided.\n");
return;
}
// Open the first file to determine the data type and coordinate system
GDALDataset* poFirstDS = (GDALDataset*)GDALOpen(inputFiles.first().toUtf8().constData(), GA_ReadOnly);
if (poFirstDS == nullptr) {
fprintf(stderr, "Failed to open the first file %s\n", inputFiles.first().toUtf8().constData());
return;
}
double adfGeoTransform[6];
CPLErr eErr = poFirstDS->GetGeoTransform(adfGeoTransform);
if (eErr != CE_None) {
fprintf(stderr, "Failed to get GeoTransform for the first file %s\n", inputFiles.first().toUtf8().constData());
GDALClose(poFirstDS);
return;
}
int nXSize = 0;
int nYSize = 0;
double minX = std::numeric_limits<double>::max();
double minY = std::numeric_limits<double>::max();
double maxX = std::numeric_limits<double>::lowest();
double maxY = std::numeric_limits<double>::lowest();
double pixelWidth = adfGeoTransform[1];
double pixelHeight = adfGeoTransform[5];
// Determine the bounding box and size of the output raster
for (const QString& inputFile : inputFiles) {
GDALDataset* poSrcDS = (GDALDataset*)GDALOpen(inputFile.toUtf8().constData(), GA_ReadOnly);
if (poSrcDS == nullptr) {
fprintf(stderr, "Failed to open %s\n", inputFile.toUtf8().constData());
continue;
}
double adfThisTransform[6];
eErr = poSrcDS->GetGeoTransform(adfThisTransform);
if (eErr != CE_None) {
fprintf(stderr, "Failed to get GeoTransform for %s\n", inputFile.toUtf8().constData());
GDALClose(poSrcDS);
continue;
}
minX = std::min(minX, adfThisTransform[0]);
minY = std::min(minY, adfThisTransform[3] + adfThisTransform[5] * poSrcDS->GetRasterYSize());
maxX = std::max(maxX, adfThisTransform[0] + adfThisTransform[1] * poSrcDS->GetRasterXSize());
maxY = std::max(maxY, adfThisTransform[3]);
GDALClose(poSrcDS);
}
nXSize = static_cast<int>(std::ceil((maxX - minX) / pixelWidth));
nYSize = static_cast<int>(std::ceil((maxY - minY) / (-pixelHeight)));
GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
if (poDriver == nullptr) {
fprintf(stderr, "GTiff driver not available.\n");
GDALClose(poFirstDS);
return;
}
char** papszOptions = nullptr;
GDALDataset* poDstDS = poDriver->Create(outputFile.toUtf8().constData(), nXSize, nYSize, 1, poFirstDS->GetRasterBand(1)->GetRasterDataType(), papszOptions);
if (poDstDS == nullptr) {
fprintf(stderr, "Creation of output file failed.\n");
GDALClose(poFirstDS);
return;
}
poDstDS->SetGeoTransform(adfGeoTransform);
const OGRSpatialReference* oSRS = poFirstDS->GetSpatialRef();
poDstDS->SetSpatialRef(oSRS);
float fillValue = std::numeric_limits<float>::quiet_NaN();
void* pafScanline = CPLMalloc(GDALGetDataTypeSizeBytes(poFirstDS->GetRasterBand(1)->GetRasterDataType()) * nXSize);
memset(pafScanline, 0, GDALGetDataTypeSizeBytes(poFirstDS->GetRasterBand(1)->GetRasterDataType()) * nXSize);
// Initialize all pixels to NaN
for (int iY = 0; iY < nYSize; ++iY) {
GDALRasterBand* poBand = poDstDS->GetRasterBand(1);
poBand->RasterIO(GF_Write, 0, iY, nXSize, 1, pafScanline, nXSize, 1, poFirstDS->GetRasterBand(1)->GetRasterDataType(), 0, 0);
}
CPLFree(pafScanline);
// Read each source image and write into the destination image
for (const QString& inputFile : inputFiles) {
GDALDataset* poSrcDS = (GDALDataset*)GDALOpen(inputFile.toUtf8().constData(), GA_ReadOnly);
if (poSrcDS == nullptr) {
fprintf(stderr, "Failed to open %s\n", inputFile.toUtf8().constData());
continue;
}
double adfThisTransform[6];
poSrcDS->GetGeoTransform(adfThisTransform);
int srcXSize = poSrcDS->GetRasterXSize();
int srcYSize = poSrcDS->GetRasterYSize();
int dstXOffset = static_cast<int>(std::round((adfThisTransform[0] - minX) / pixelWidth));
int dstYOffset = static_cast<int>(std::round((maxY - adfThisTransform[3]) / (-pixelHeight)));
GDALRasterBand* poSrcBand = poSrcDS->GetRasterBand(1);
GDALRasterBand* poDstBand = poDstDS->GetRasterBand(1);
void* pafBuffer = CPLMalloc(GDALGetDataTypeSizeBytes(poFirstDS->GetRasterBand(1)->GetRasterDataType()) * srcXSize * srcYSize);
poSrcBand->RasterIO(GF_Read, 0, 0, srcXSize, srcYSize, pafBuffer, srcXSize, srcYSize, poFirstDS->GetRasterBand(1)->GetRasterDataType(), 0, 0);
poDstBand->RasterIO(GF_Write, dstXOffset, dstYOffset, srcXSize, srcYSize, pafBuffer, srcXSize, srcYSize, poFirstDS->GetRasterBand(1)->GetRasterDataType(), 0, 0);
CPLFree(pafBuffer);
GDALClose(poSrcDS);
}
GDALClose(poDstDS);
GDALClose(poFirstDS);
}