diff --git a/MMVII/CMakeLists.txt b/MMVII/CMakeLists.txt index 8e7749cdf1..ec5e9edc05 100644 --- a/MMVII/CMakeLists.txt +++ b/MMVII/CMakeLists.txt @@ -44,6 +44,8 @@ if((NOT OpenMP_CXX_FOUND) AND (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")) message(STATUS "OpenMP not found: did you install libomp-dev ?") endif() +# GDAL +find_package(GDAL REQUIRED) ####################################################### ## Compilation toolchain @@ -109,7 +111,7 @@ file(GLOB mmv2_headers "${mmv2_include_dir}/*.h" "${mmv2_include_dir}/*/*.h" "${ ####################################################### add_library(P2007 "${mmv2_libsrcs}" "${mmv2_headers}") target_include_directories(P2007 PRIVATE "${mmv2_include_dir};${mmv1_include_dir};${EIGEN3_INCLUDE_PATH}") -target_link_libraries(P2007 PRIVATE MMVII_compiler_flags Threads::Threads) +target_link_libraries(P2007 PRIVATE MMVII_compiler_flags Threads::Threads GDAL::GDAL) # Force parallel compilation with MSVC if(MSVC) diff --git a/MMVII/include/MMVII_DeclareAllCmd.h b/MMVII/include/MMVII_DeclareAllCmd.h index ef457f05c8..ba6ab9591a 100755 --- a/MMVII/include/MMVII_DeclareAllCmd.h +++ b/MMVII/include/MMVII_DeclareAllCmd.h @@ -90,7 +90,8 @@ extern cSpecMMVII_Appli TheSpec_CreateRTL; extern cSpecMMVII_Appli TheSpec_ChSysCo; extern cSpecMMVII_Appli TheSpec_CreateCalib; extern cSpecMMVII_Appli TheSpecImportPushbroom; -extern cSpecMMVII_Appli TheSpecTestImportSensors; +extern cSpecMMVII_Appli TheSpecTestImportSensors; +extern cSpecMMVII_Appli TheSpec_TestGdal; }; #endif // _MMVII_DeclareAllCmd_H_ diff --git a/MMVII/include/MMVII_Image2D.h b/MMVII/include/MMVII_Image2D.h index e33aef3702..a5ede9ec77 100755 --- a/MMVII/include/MMVII_Image2D.h +++ b/MMVII/include/MMVII_Image2D.h @@ -47,6 +47,7 @@ class cDataFileIm2D : public cRect2 static bool IsNameWith_PostFixImage(const std::string & aPost); private : cDataFileIm2D(const std::string &,eTyNums,const cPt2di & aSz,int aNbChannel) ; + cDataFileIm2D(const std::string & aName, const cPt2di & aSz) ; cMemCheck mMemCheck; ///< Inheritage may be multiple, member will have the same effect std::string mName; ///< Name on the disk diff --git a/MMVII/include/MMVII_util.h b/MMVII/include/MMVII_util.h index 75937c499d..cd8fa0f847 100755 --- a/MMVII/include/MMVII_util.h +++ b/MMVII/include/MMVII_util.h @@ -89,7 +89,7 @@ std::string Postfix(const std::string & aStr,char aSep='.',bool SVP=false,bool P std::string LastPostfix(const std::string & aStr,char aSep='.'); ///< No error: a=> "" a.b.c => "c" bool starts_with(const std::string & aFullStr,const std::string & aBegining); /// as c++20 std::string.starts_with -bool ends_with(const std::string & aFullStr,const std::string & aEnding); /// as c++20 std::string.starts_with TO IMPLEMENT +bool ends_with(const std::string & aFullStr,const std::string & aEnding); /// as c++20 std::string.ends_with bool contains(const std::string & aFullStr,const std::string & aEnding); /// as c++23 std::string.contains TO IMPLEMENT // Direcytory and files names, Rely on std::filesystem diff --git a/MMVII/src/Appli/cSpecMMVII_Appli.cpp b/MMVII/src/Appli/cSpecMMVII_Appli.cpp index f1bd9c96dd..61e9b31101 100755 --- a/MMVII/src/Appli/cSpecMMVII_Appli.cpp +++ b/MMVII/src/Appli/cSpecMMVII_Appli.cpp @@ -235,6 +235,7 @@ std::vector & cSpecMMVII_Appli::InternVecAll() TheVecAll.push_back(&TheSpec_ImportMesImGCP); TheVecAll.push_back(&TheSpecImportPushbroom); TheVecAll.push_back(&TheSpecTestImportSensors); + TheVecAll.push_back(&TheSpec_TestGdal); std::sort(TheVecAll.begin(),TheVecAll.end(),CmpCmd); } diff --git a/MMVII/src/GDAL/cTestGdal.cpp b/MMVII/src/GDAL/cTestGdal.cpp new file mode 100644 index 0000000000..493d7d6d9c --- /dev/null +++ b/MMVII/src/GDAL/cTestGdal.cpp @@ -0,0 +1,296 @@ +#include "cMMVII_Appli.h" +#include + +#include "MMVII_PCSens.h" +#include "MMVII_Image2D.h" +#include "MMVII_enums.h" + + +namespace MMVII +{ + + + class cAppli_TestGdal : public cMMVII_Appli + { + public : + + cAppli_TestGdal(const std::vector & aVArgs,const cSpecMMVII_Appli &); + int Exe() override; + cCollecSpecArg2007 & ArgObl(cCollecSpecArg2007 & anArgObl) override; + cCollecSpecArg2007 & ArgOpt(cCollecSpecArg2007 & anArgOpt) override; + void OpenTiffImage(); + void OpenTiffImageCIm2D(); + void OpenTiffImageCIm2DBox(); + void OpenTiffRGBImageCIm2DBox(); + void CreateTiffImage(); + void WriteImage(); + void WriteRGBImage(); + void WriteImageToFile(); + void WriteRGBImageToFile(); + void WriteImageTiles(); + + private : + cPhotogrammetricProject mPhProj; + std::string mImagePathBW; + std::string mImagePathRGB; + + }; + + + cAppli_TestGdal::cAppli_TestGdal + ( + const std::vector & aVArgs, + const cSpecMMVII_Appli & aSpec + ) : + cMMVII_Appli (aVArgs,aSpec), + mPhProj (*this) + { + } + + + + cCollecSpecArg2007 & cAppli_TestGdal::ArgObl(cCollecSpecArg2007 & anArgObl) + { + return anArgObl + << Arg2007(mImagePathBW,"Image BW") + << Arg2007(mImagePathRGB,"Image RGB") + ; + } + + + cCollecSpecArg2007 & cAppli_TestGdal::ArgOpt(cCollecSpecArg2007 & anArgOpt) + { + + return anArgOpt + ; + } + + + void cAppli_TestGdal::OpenTiffImage() + { + StdOut() << "Ouverture de l'image : " << mImagePathBW << std::endl; + cDataFileIm2D aImage = cDataFileIm2D::Create(mImagePathBW, 0); + StdOut() << "cDataFileIm2D créée" << std::endl; + StdOut() << "Taille de l'image : " << aImage.Sz() << std::endl; + StdOut() << "NbChannel : " << aImage.NbChannel() << std::endl; + //StdOut() << "Type : " << aImage.Type() << std::endl; + StdOut() << "Name : " << aImage.Name() << std::endl; + StdOut() << "IsEmpty : " << aImage.IsEmpty() << std::endl; + StdOut() << "" << std::endl; + } + + void cAppli_TestGdal::OpenTiffImageCIm2D() + { + StdOut() << "Ouverture de l'image : " << mImagePathBW << std::endl; + cIm2D aIm2D = cIm2D::FromFile(mImagePathBW); + cDataIm2D & aDataIm2D = aIm2D.DIm(); + StdOut() << "Taille de l'image : " << aDataIm2D.Sz() << std::endl; + StdOut() << "Valeur du pixel (5000, 8000) : " << (int) aDataIm2D.GetV(cPt2di(5000, 8000)) << std::endl; + StdOut() << "" << std::endl; + + } + + void cAppli_TestGdal::OpenTiffImageCIm2DBox() + { + StdOut() << "Ouverture de l'image avec une boite de (6000, 8000, 9000, 10000): " << mImagePathBW << std::endl; + cBox2di aBox = cBox2di(cPt2di(6000, 8000), cPt2di(9000, 10000)); + cIm2D aIm2D = cIm2D::FromFile(mImagePathBW, aBox); + StdOut() << "cDataFileIm2D créée" << std::endl; + cDataIm2D & aDataIm2D = aIm2D.DIm(); + StdOut() << "Taille de l'image : " << aDataIm2D.Sz() << std::endl; + StdOut() << "Valeur du pixel (0, 0) : " << aDataIm2D.GetV(cPt2di(0, 0)) << std::endl; + StdOut() << "Valeur du pixel (0, 1) : " << aDataIm2D.GetV(cPt2di(0, 1)) << std::endl; + StdOut() << "Valeur du pixel (1, 1) : " << aDataIm2D.GetV(cPt2di(1, 1)) << std::endl; + StdOut() << "Valeur du pixel (1, 0) : " << aDataIm2D.GetV(cPt2di(1, 0)) << std::endl; + StdOut() << "Valeur du pixel (0.5, 0.5) : " << aDataIm2D.DefGetVBL(cPt2dr(0.5, 0.5), -1) << std::endl; + StdOut() << "Valeur du pixel (1000.5, 1000.5) : " << aDataIm2D.DefGetVBL(cPt2dr(1000.5, 1000.5), -1) << std::endl; + + } + + + void cAppli_TestGdal::OpenTiffRGBImageCIm2DBox() + { + StdOut() << "Ouverture de l'image RGB avec une boite de (6000, 8000, 9000, 10000): " << mImagePathRGB << std::endl; + cBox2di aBox = cBox2di(cPt2di(6000, 8000), cPt2di(9000, 10000)); + cRGBImage aRGBIm = cRGBImage::FromFile(mImagePathRGB, aBox); + StdOut() << "Valeur du pixel (0, 1) : " << aRGBIm.GetRGBPix(cPt2di(0, 1)) << std::endl; + StdOut() << "Valeur du pixel (0.5, 0.5) : " << aRGBIm.GetRGBPixBL(cPt2dr(0.5, 0.5)) << std::endl; + } + + + void cAppli_TestGdal::CreateTiffImage() + { + std::string aCreatedImage = "image0.tif"; + StdOut() << "Ouverture de l'image : " << aCreatedImage << std::endl; + cDataFileIm2D aImage = cDataFileIm2D::Create(aCreatedImage, eTyNums::eTN_INT2, cPt2di(1000, 1000), 3); + StdOut() << "cDataFileIm2D créée : tINT2, 3 canaux" << std::endl; + StdOut() << "Taille de l'image : " << aImage.Sz() << std::endl; + StdOut() << "NbChannel : " << aImage.NbChannel() << std::endl; + StdOut() << "Name : " << aImage.Name() << std::endl; + StdOut() << "IsEmpty : " << aImage.IsEmpty() << std::endl; + StdOut() << "" << std::endl; + } + + + + void cAppli_TestGdal::WriteImage() + { + // Open image + cBox2di aBox = cBox2di(cPt2di(7000, 8000), cPt2di(7100, 8100)); + cIm2D aIm2D = cIm2D::FromFile(mImagePathBW, aBox); + // Create the new image of type eTyNums + std::string aCreatedImageName = "image1.tif"; + cDataFileIm2D aCreatedImage = cDataFileIm2D::Create(aCreatedImageName, eTyNums::eTN_REAL8, cPt2di(100, 100), 1); + // Open the new image + // Data will be written in Type (tREAL4), but the image will be save in eTyNums (eTyNums::eTN_REAL8) + cIm2D aCreatedIm2D = cIm2D::FromFile(aCreatedImageName); + + // Copy data + for (int x = aCreatedIm2D.DIm().X0(); x < aCreatedIm2D.DIm().X1(); x++) + { + for (int y = aCreatedIm2D.DIm().Y0(); y < aCreatedIm2D.DIm().Y1(); y++) + { + aCreatedIm2D.DIm().SetV(cPt2di(x, y), aIm2D.DIm().GetV(cPt2di(x, y))); + } + } + // Save image + aCreatedIm2D.Write(aCreatedImage, cPt2di(0, 0)); + } + + void cAppli_TestGdal::WriteRGBImage() + { + // Open image in ((7000, 8000), (7100, 8100)) + cBox2di aBox = cBox2di(cPt2di(7000, 8000), cPt2di(7100, 8100)); + cRGBImage aRGBImage = cRGBImage::FromFile(mImagePathRGB, aBox); + + // Create the new image of size (200, 200). Type must be eTyNums::eTN_U_INT1 because it is RGB image + std::string aCreatedImageName = "image2.tif"; + cDataFileIm2D aCreatedImage = cDataFileIm2D::Create(aCreatedImageName, eTyNums::eTN_U_INT1, cPt2di(200, 200), 3); + + // Open the new image in ((50, 50), (150, 150)) + // Origin of the box does not matter in writting because it is in Write method that the origin is defined. Only the size of the box is important here + cRGBImage aCreatedIm2D = cRGBImage::FromFile(aCreatedImageName, cBox2di(cPt2di(50, 50), cPt2di(150, 150))); + + // Copy data + for (int x = aRGBImage.ImR().DIm().X0(); x < aRGBImage.ImR().DIm().X1(); x++) + { + for (int y = aRGBImage.ImR().DIm().Y0(); y < aRGBImage.ImR().DIm().Y1(); y++) + { + aCreatedIm2D.SetRGBPix(cPt2di(x, y), aRGBImage.GetRGBPix(cPt2di(x, y))); + } + } + + // Save data in coordinates (50, 50) + aCreatedIm2D.Write(aCreatedImage, cPt2di(50, 50)); + } + + + void cAppli_TestGdal::WriteImageToFile() + { + // Open image in ((7000, 8000), (10000, 11000)) + cBox2di aBox = cBox2di(cPt2di(7000, 8000), cPt2di(10000, 11000)); + cIm2D aIm2D = cIm2D::FromFile(mImagePathBW, aBox); + + // Save extracted image + //aIm2D.DIm().ToFile(mImageCreatePath); + + // Save an extraction of the extracted image : ((8000, 9000), (9000, 10000)) of the first image + std::string aCreatedImageName = "image3.tif"; + aIm2D.DIm().ClipToFile(aCreatedImageName, cRect2(cPt2di(1000, 1000), cPt2di(2000, 2000))); + + } + + + void cAppli_TestGdal::WriteRGBImageToFile() + { + // Open image in ((7000, 8000), (10000, 11000)) + cBox2di aBox = cBox2di(cPt2di(7000, 8000), cPt2di(10000, 11000)); + cRGBImage aRGBImage = cRGBImage::FromFile(mImagePathRGB, aBox); + + // Read Image in ((15000, 12000), (18000, 15000)). Then aBox in aRGBImage is useless + aRGBImage.Read(mImagePathRGB, cPt2di(0, 0), 1.0, cBox2di(cPt2di(15000, 12000), cPt2di(18000, 15000))); + + + // Create new image + std::string aCreatedImageName = "image4.tif"; + cDataFileIm2D aRGBImagecreated = cDataFileIm2D::Create(aCreatedImageName, eTyNums::eTN_U_INT1, cPt2di(3000, 3000), 3); + // Write data + aRGBImage.Write(aRGBImagecreated, cPt2di(0, 0)); + + // Save extracted image in RGB + //aRGBImage.ImR().DIm().ToFile(mImageCreatePath, aRGBImage.ImG().DIm(), aRGBImage.ImB().DIm()); + + } + + void cAppli_TestGdal::WriteImageTiles() + { + // Open image in ((7000, 8000), (10000, 11000)) + cBox2di aBox = cBox2di(cPt2di(7000, 8000), cPt2di(10000, 11000)); + cIm2D aIm2D = cIm2D::FromFile(mImagePathBW, aBox); + // Create the new image of size (3000, 3000) + std::string aCreatedImageName = "image5.tif"; + cDataFileIm2D aCreatedImage = cDataFileIm2D::Create(aCreatedImageName, eTyNums::eTN_REAL8, cPt2di(3000, 3000), 1); + // Open the new image with a size of (1000, 1000) + // Origin of the box does not matter in writting because it is in Write method that the origin is defined. Only the size of the box is important here + cIm2D aTile = cIm2D::FromFile(aCreatedImageName, cBox2di(cPt2di(0, 0), cPt2di(1000, 1000))); + + // Give the same result : + // cIm2D aTile = cIm2D::FromFile(mImageCreatePath, cBox2di(cPt2di(300, 300), cPt2di(1300, 1300))); + + // Copy data + for (int x = aTile.DIm().X0(); x < aTile.DIm().X1(); x++) + { + for (int y = aTile.DIm().Y0(); y < aTile.DIm().Y1(); y++) + { + aTile.DIm().SetV(cPt2di(x, y), aIm2D.DIm().GetV(cPt2di(x, y))); + } + } + + // Save image at the origin (0, 0) + aTile.Write(aCreatedImage, cPt2di(0, 0)); + // Save the same image but at the origin (1000, 2000) + aTile.Write(aCreatedImage, cPt2di(1000, 2000)); + } + + int cAppli_TestGdal::Exe() + { + mPhProj.FinishInit(); // the final construction of photogrammetric project manager can only be done now + + OpenTiffImage(); + OpenTiffImageCIm2D(); + OpenTiffImageCIm2DBox(); + OpenTiffRGBImageCIm2DBox(); + CreateTiffImage(); + WriteImage(); + WriteRGBImage(); + WriteImageToFile(); + WriteRGBImageToFile(); + WriteImageTiles(); + + return EXIT_SUCCESS; + } + + /* ==================================================== */ + /* */ + /* MMVII */ + /* */ + /* ==================================================== */ + + + tMMVII_UnikPApli Alloc_TestGdal(const std::vector & aVArgs,const cSpecMMVII_Appli & aSpec) + { + return tMMVII_UnikPApli(new cAppli_TestGdal(aVArgs,aSpec)); + } + + cSpecMMVII_Appli TheSpec_TestGdal + ( + "TestGdal", + Alloc_TestGdal, + "Test avec GDAL", + {eApF::GCP,eApF::Ori}, + {eApDT::Orient}, + {eApDT::Xml}, + __FILE__ + ); + +} \ No newline at end of file diff --git a/MMVII/src/ImagesBase/FileImages.cpp b/MMVII/src/ImagesBase/FileImages.cpp new file mode 100644 index 0000000000..84f127d0e7 --- /dev/null +++ b/MMVII/src/ImagesBase/FileImages.cpp @@ -0,0 +1,527 @@ +#include "V1VII.h" +#include "MMVII_Stringifier.h" +#include "MMVII_util.h" +#include "MMVII_Image2D.h" +#include "MMVII_DeclareCste.h" +#include "cMMVII_Appli.h" +#include "MMVII_Sys.h" +#include "StdAfx.h" +#include "MMVII_Ptxd.h" +#include "gdal/gdal_priv.h" + + +using namespace MMVII; + +namespace{ // Private + eTyNums GdalToMMVII( GDALDataType aType ) + { + switch (aType) + { + case GDT_Unknown : return eTyNums::eTN_UnKnown; + case GDT_Byte : return eTyNums::eTN_U_INT1 ; + case GDT_UInt16 : return eTyNums::eTN_U_INT2 ; + case GDT_Int16 : return eTyNums::eTN_INT2 ; + case GDT_UInt32 : return eTyNums::eTN_U_INT4 ; + case GDT_Int32 : return eTyNums::eTN_INT4 ; + case GDT_Float32 : return eTyNums::eTN_REAL4 ; + case GDT_Float64 : return eTyNums::eTN_REAL8 ; + + case GDT_CInt16 : MMVII_INTERNAL_ERROR("GdalToMMVII : case GDT_CInt16") ; + case GDT_CInt32 : MMVII_INTERNAL_ERROR("GdalToMMVII : case GDT_CInt32") ; + case GDT_CFloat32 : MMVII_INTERNAL_ERROR("GdalToMMVII : case GDT_CFloat32") ; + case GDT_CFloat64 : MMVII_INTERNAL_ERROR("GdalToMMVII : case GDT_CFloat64") ; + case GDT_TypeCount : MMVII_INTERNAL_ERROR("GdalToMMVII : case GDT_TypeCount") ; + } + return eTyNums::eTN_UnKnown ; + } + + + GDALDataType MMVIIToGdal( eTyNums aType ) + { + switch (aType) + { + + case eTyNums::eTN_INT1 : MMVII_INTERNAL_ERROR("MMVIIToGdal : case eTyNums::eTN_INT1") ; + case eTyNums::eTN_U_INT1 : return GDT_Byte ; + case eTyNums::eTN_INT2 : return GDT_Int16 ; + case eTyNums::eTN_U_INT2 : return GDT_UInt16 ; + case eTyNums::eTN_INT4 : return GDT_Int32 ; + case eTyNums::eTN_U_INT4 : return GDT_UInt32 ; + case eTyNums::eTN_INT8 : MMVII_INTERNAL_ERROR("MMVIIToGdal : case eTyNums::eTN_INT8") ; + case eTyNums::eTN_REAL4 : return GDT_Float32 ; + case eTyNums::eTN_REAL8 : return GDT_Float64 ; + case eTyNums::eTN_REAL16 : MMVII_INTERNAL_ERROR("MMVIIToGdal : case eTyNums::eTN_REAL16") ; + case eTyNums::eTN_UnKnown : MMVII_INTERNAL_ERROR("MMVIIToGdal : case eTyNums::eTN_UnKnown") ; + case eTyNums::eNbVals : MMVII_INTERNAL_ERROR("MMVIIToGdal : case eTyNums::eNbVals") ; + } + return GDT_Unknown ; + } + + + std::string ExtToGdalDriver( std::string aName ) + { + auto aLowerName = ToLower(aName); + if (ends_with(aLowerName,".tif") || ends_with(aLowerName,".tiff")) + return "GTiff"; + if (ends_with(aLowerName,".jpg") || ends_with(aLowerName,".jpeg")) + return "JPEG"; + if (ends_with(aLowerName,".png")) + return "PNG"; + MMVII_INTERNAL_ERROR("MMVIITOGDal: Unsupported image format for " + aName); + return ""; + } + + + GDALDataset * OpenDataset(std::string aName) + { + // Open image with Gdal + const GDALAccess eAccess = GA_Update; + GDALDataset * aGdalDataset = GDALDataset::FromHandle(GDALOpen( aName.c_str(), eAccess )); + return aGdalDataset; + } + + template void GdalReadData(GDALDataset* aDataset,const cPt2di & aP0,double aDyn,const cPixBox<2>& aR2, int band, cDataIm2D * aDataIm2D, GDALDataType aGDALDataType){ + + // Get first band + GDALRasterBand* aBand = aDataset->GetRasterBand(band); + + cRect2 aRectFullIm (cPt2di(0,0),aDataIm2D->Sz()); + cRect2 aRectIm = (aR2== cRect2::TheEmptyBox) ? + aRectFullIm : + aR2 ; + // aRectIm est dans le repère d'origine P0 + cPt2di aTrans = aDataIm2D->P0() + aP0; + + // Read image according to Gdal tutorial + TypeOut *pafScanline; + pafScanline = (TypeOut *) cMemManager::Calloc(1, sizeof(TypeOut)*aRectIm.Sz().x()*aRectIm.Sz().y()); + CPLErr cplErr2 = aBand->RasterIO( GF_Read, aRectIm.P0().x() + aTrans.x(), aRectIm.P0().y() + aTrans.y(), aRectIm.Sz().x(), aRectIm.Sz().y(), pafScanline, aRectIm.Sz().x(), aRectIm.Sz().y(), aGDALDataType, 0, 0 ); + MMVII_INTERNAL_ASSERT_strong(cplErr2 == 0 || cplErr2 == 1,"Error in writing image"); + + // Copy of data in mRawData2D. Is there a way to complete mRawData2D directly in aBand->RasterIO()? + // Image is read in float 32, and the conversion is done here + for (int aY = 0; aY < aRectIm.Sz().y(); aY++) + { + for (int aX = 0; aX < aRectIm.Sz().x(); aX++) + { + aDataIm2D->SetVTrunc(cPt2di(aX, aY) + aDataIm2D->P0(), pafScanline[aY * aRectIm.Sz().x() + aX] * aDyn); + } + } + + cMemManager::Free(pafScanline); + + } + + + template void GdalWriteData(GDALDataset * poDstDS,const cPt2di & aP0,double aDyn,const cPixBox<2>& aR2, int band, const cDataIm2D * aDataIm2D, GDALDataType aGDALDataType){ + + // get the raster band + GDALRasterBand *poBand; + poBand = poDstDS->GetRasterBand(band); + + cRect2 aRectFullIm (cPt2di(0,0),aDataIm2D->Sz()); + cRect2 aRectIm = (aR2== cRect2::TheEmptyBox) ? + aRectFullIm : + aR2 ; + // aRectIm est dans le repère d'origine P0 + cPt2di aTrans = aDataIm2D->P0() + aP0; + + TypeOut * abyRaster; + abyRaster = (TypeOut *) cMemManager::Calloc(1, sizeof(TypeOut)*aRectIm.Sz().x()*aRectIm.Sz().y()); + + for (int aY = 0; aY < aRectIm.Sz().y(); aY++) + { + for (int aX = 0; aX < aRectIm.Sz().x(); aX++) + { + abyRaster[aY * aRectIm.Sz().x() + aX] = tNumTrait::Trunc(aDataIm2D->GetV(cPt2di(aX, aY) + aDataIm2D->P0() + aR2.P0()) * aDyn); + } + } + // Write data in file + CPLErr cplErr2 = poBand->RasterIO( GF_Write, aRectIm.P0().x() + aTrans.x(), aRectIm.P0().y() + aTrans.y(), aRectIm.Sz().x(), aRectIm.Sz().y(), abyRaster, aRectIm.Sz().x(), aRectIm.Sz().y(), aGDALDataType, 0, 0 ); + MMVII_INTERNAL_ASSERT_strong(cplErr2 == 0 || cplErr2 == 1,"Error in writing image"); + + cMemManager::Free(abyRaster); + + } + + + + template void GdalRead + ( + std::vector*>& aVecImV2, + const cDataFileIm2D &aDF, + const cPt2di & aP0File, + double aDyn, + const cRect2& aR2Init + ) + { + GDALDataset * aGdalDataset = OpenDataset(aDF.Name()); + int i = 0; + for (auto & element : aVecImV2) + { + switch (aDF.Type()) + { + case eTyNums::eTN_INT1 : MMVII_INTERNAL_ERROR("cDataIm2D::Read : case eTyNums::eTN_INT1") ; break ; + case eTyNums::eTN_U_INT1 : GdalReadData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_INT2 : GdalReadData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_U_INT2 : GdalReadData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_INT4 : GdalReadData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_U_INT4 : GdalReadData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_INT8 : MMVII_INTERNAL_ERROR("cDataIm2D::Read : case eTyNums::eTN_INT8") ; break ; + case eTyNums::eTN_REAL4 : GdalReadData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_REAL8 : GdalReadData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_REAL16 : MMVII_INTERNAL_ERROR("cDataIm2D::Read : case eTyNums::eTN_REAL16") ; break ; + case eTyNums::eTN_UnKnown : MMVII_INTERNAL_ERROR("cDataIm2D::Read : case eTyNums::eTN_UnKnown") ; break ; + case eTyNums::eNbVals : MMVII_INTERNAL_ERROR("cDataIm2D::Read : case eTyNums::eNbVals") ; break ; + } + i++; + } + GDALClose( (GDALDatasetH) aGdalDataset ); + } + + + template void GdalWrite + ( + std::vector*>& aVecImV2, + const cDataFileIm2D &aDF, + const cPt2di & aP0File, + double aDyn, + const cRect2& aR2Init + ) + { + GDALDataset * aGdalDataset = OpenDataset(aDF.Name()); + int i = 0; + for (auto & element : aVecImV2) + { + switch (aDF.Type()) + { + case eTyNums::eTN_INT1 : MMVII_INTERNAL_ERROR("cDataIm2D::Write : case eTyNums::eTN_INT1") ; break ; + case eTyNums::eTN_U_INT1 : GdalWriteData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_INT2 : GdalWriteData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_U_INT2 : GdalWriteData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_INT4 : GdalWriteData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_U_INT4 : GdalWriteData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_INT8 : MMVII_INTERNAL_ERROR("cDataIm2D::Write : case eTyNums::eTN_INT8") ; break ; + case eTyNums::eTN_REAL4 : GdalWriteData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_REAL8 : GdalWriteData(aGdalDataset, aP0File, aDyn, aR2Init, i+1, element, MMVIIToGdal(aDF.Type())) ; break ; + case eTyNums::eTN_REAL16 : MMVII_INTERNAL_ERROR("cDataIm2D::Write : case eTyNums::eTN_REAL16") ; break ; + case eTyNums::eTN_UnKnown : MMVII_INTERNAL_ERROR("cDataIm2D::Write : case eTyNums::eTN_UnKnown") ; break ; + case eTyNums::eNbVals : MMVII_INTERNAL_ERROR("cDataIm2D::Write : case eTyNums::eNbVals") ; break ; + } + i++; + } + GDALClose( (GDALDatasetH) aGdalDataset ); + } + +}// Private + + + + +namespace MMVII +{ + + +std::string V1NameMasqOfIm(const std::string & aName) +{ + return LastPrefix(aName) + "_Masq.tif"; +} + +/* =========================== */ +/* cDataFileIm2D */ +/* =========================== */ + +cDataFileIm2D::cDataFileIm2D(const std::string & aName,eTyNums aType,const cPt2di & aSz,int aNbChannel) : + cPixBox<2> (cPt2di(0,0),aSz), + mName (aName), + mType (aType), + mNbChannel (aNbChannel) +{ + +} + + +cDataFileIm2D::cDataFileIm2D(const std::string & aName, const cPt2di & aSz) : + cPixBox<2> (cPt2di(0,0), aSz), + mName (aName) +{ + const GDALAccess eAccess = GA_Update; + GDALDataset * aDataset = GDALDataset::FromHandle(GDALOpen( aName.c_str(), eAccess )); + mNbChannel = aDataset->GetRasterCount(); + mType = GdalToMMVII( aDataset->GetRasterBand( 1 )->GetRasterDataType()); +} + + + +cDataFileIm2D cDataFileIm2D::Empty() +{ + return cDataFileIm2D( MMVII_NONE, eTyNums::eNbVals, cPt2di(1,1), -1); +} + +bool cDataFileIm2D::IsEmpty() const +{ + return mNbChannel<=0; +} + + +void cDataFileIm2D::AssertNotEmpty() const +{ + MMVII_INTERNAL_ASSERT_strong((!IsEmpty()),"cDataFileIm2D was not initialized"); +} + + +cDataFileIm2D cDataFileIm2D::Create(const std::string & aName,bool aForceGray) +{ + + // Create a cDataFileIm2D on an existing image + + // Open a first time with gdal to have access to the size and then to create a cDataFileIm2D object + GDALAllRegister(); + const GDALAccess eAccess = GA_Update; + GDALDataset * aDataset = GDALDataset::FromHandle(GDALOpen( aName.c_str(), eAccess )); + cPt2di aSz = cPt2di(aDataset->GetRasterXSize(), aDataset->GetRasterYSize()); + + return cDataFileIm2D(aName, aSz); +} + +cDataFileIm2D cDataFileIm2D::Create(const std::string & aName,eTyNums aType,const cPt2di & aSz,int aNbChan) +{ + + // Create an image and a cDataFileIm2D + + remove(aName.c_str()); + + // Check that aNbChan is 1 or 3 + if (aNbChan!=1 && aNbChan!=3) + { + MMVII_INTERNAL_ASSERT_strong(false,"Incoherent channel number"); + } + + // Create a driver + GDALAllRegister(); + auto pszFormat = ExtToGdalDriver(aName); + GDALDriver *poDriver; + poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat.c_str()); + + // Create a dataset + GDALDataset *poDstDS; + char **papszOptions = NULL; + poDstDS = poDriver->Create( aName.c_str(), aSz.x(), aSz.y(), aNbChan, MMVIIToGdal(aType), papszOptions ); + + double * abyRaster; + abyRaster = (double *) cMemManager::Calloc(1, sizeof(double)*aSz.x()*aSz.y()); + + for (int aK = 0; aK < aSz.x()*aSz.y(); aK++) + { + abyRaster[aK] = 0; + } + + // Initialize the dataset + GDALRasterBand *poBand; + for (int i = 1; i < aNbChan+1; i++) + { + poBand = poDstDS->GetRasterBand(i); + CPLErr cplErr2 = poBand->RasterIO( GF_Write, 0, 0, aSz.x(), aSz.y(), abyRaster, aSz.x(), aSz.y(), MMVIIToGdal(aType), 0, 0 ); + MMVII_INTERNAL_ASSERT_strong(cplErr2 == 0 || cplErr2 == 1,"Error in writing image"); + } + + cMemManager::Free(abyRaster); + + GDALClose( (GDALDatasetH) poDstDS ); + + return cDataFileIm2D(aName, aSz); +} + + +cDataFileIm2D::~cDataFileIm2D() +{ +} + +const cPt2di & cDataFileIm2D::Sz() const {return cPixBox<2>::Sz();} +const std::string & cDataFileIm2D::Name() const { return mName; } +const int & cDataFileIm2D::NbChannel () const { return mNbChannel; } +const eTyNums & cDataFileIm2D::Type () const {return mType;} + + +bool cDataFileIm2D::IsPostFixNameImage(const std::string & aPost) +{ + static std::vector aVNames({"jpg","jpeg","tif","tiff"}); + + return UCaseMember(aVNames,aPost); +} + +bool cDataFileIm2D::IsNameWith_PostFixImage(const std::string & aName) +{ + return IsPostFixNameImage(LastPostfix(aName)); +} + + + + + +template void cDataIm2D::Read(const cDataFileIm2D & aFile,const cPt2di & aP0,double aDyn,const cPixBox<2>& aR2) +{ + std::vector aVIms({this}); + GdalRead(aVIms, aFile, aP0, aDyn, aR2); + +} + +template void cDataIm2D::Read(const cDataFileIm2D & aFile,tIm &aImG,tIm &aImB,const cPt2di & aP0,double aDyn,const cPixBox<2>& aR2) +{ + std::vector aVIms({this,&aImG,&aImB}); + GdalRead(aVIms, aFile, aP0, aDyn, aR2); +} + + +template void cDataIm2D::Write(const cDataFileIm2D & aFile,const cPt2di & aP0,double aDyn,const cPixBox<2>& aR2) const +{ + std::vector aVIms({this}); + GdalWrite(aVIms, aFile, aP0, aDyn, aR2); +} + +template void cDataIm2D::Write(const cDataFileIm2D & aFile,const tIm &aImG,const tIm &aImB,const cPt2di & aP0,double aDyn,const cPixBox<2>& aR2) const +{ + std::vector aVIms({this,&aImG,&aImB}); + GdalWrite(aVIms, aFile, aP0, aDyn, aR2); +} + + + + +template void cIm2D::Read(const cDataFileIm2D & aFile,const cPt2di & aP0,double aDyn,const cPixBox<2>& aR2) +{ + DIm().Read(aFile,aP0,aDyn,aR2); +} +template void cIm2D::Write(const cDataFileIm2D & aFile,const cPt2di & aP0,double aDyn,const cPixBox<2>& aR2) const +{ + DIm().Write(aFile,aP0,aDyn,aR2); +} + + + +GenIm::type_el ToMMV1(eTyNums aV2) +{ + switch (aV2) + { + case eTyNums::eTN_INT1 : return GenIm::int1 ; + case eTyNums::eTN_INT2 : return GenIm::int2 ; + case eTyNums::eTN_INT4 : return GenIm::int4 ; + case eTyNums::eTN_U_INT1 : return GenIm::u_int1 ; + case eTyNums::eTN_U_INT2 : return GenIm::u_int2 ; + case eTyNums::eTN_U_INT4 : return GenIm::u_int4 ; + case eTyNums::eTN_REAL4 : return GenIm::real4 ; + case eTyNums::eTN_REAL8 : return GenIm::real8 ; + default: ; + } + MMVII_INTERNAL_ERROR("GenIm::type_el ToMMV1(eTyNums)"); + return GenIm::int1; +} + +eTyNums ToMMVII( GenIm::type_el aV1 ) +{ + switch (aV1) + { + case GenIm::int1 : return eTyNums::eTN_INT1 ; + case GenIm::int2 : return eTyNums::eTN_INT2 ; + case GenIm::int4 : return eTyNums::eTN_INT4 ; + + case GenIm::u_int1 : return eTyNums::eTN_U_INT1 ; + case GenIm::u_int2 : return eTyNums::eTN_U_INT2 ; + case GenIm::u_int4 : return eTyNums::eTN_U_INT4 ; + + case GenIm::real4 : return eTyNums::eTN_REAL4 ; + case GenIm::real8 : return eTyNums::eTN_REAL8 ; + + default: ; + } + return eTyNums::eTN_UnKnown ; +/* + MMVII_INTERNAL_ASSERT_bench(false,"eTyNums ToMMVII( GenIm::type_el aV1 )"); + return eTyNums::eTN_INT1 ; +*/ +} + + + + + + + +double DifAbsInVal(const std::string & aN1,const std::string & aN2,double aDef) +{ + Tiff_Im aF1(aN1.c_str()); + Tiff_Im aF2(aN2.c_str()); + double aSom; + + if (aF1.sz()!=aF2.sz()) + { + MMVII_INTERNAL_ASSERT_always(aDef!=0.0,"Diff sz and bad def in DifAbsInVal"); + return aDef; + } + + ELISE_COPY(aF1.all_pts(),Abs(aF1.in()-aF2.in()),sigma(aSom)); + + return aSom; +} + +template cIm2D BitsV1ToV2(const Im2D_Bits & aImV1) +{ + cIm2D aImV2(ToMMVII(aImV1.sz())); + cDataIm2D& aDImV2 = aImV2.DIm(); + + for (const auto & aPixV2 : aDImV2) + { + aDImV2.SetV(aPixV2,aImV1.GetI(ToMMV1(aPixV2))); + } + + + return aImV2; +} + + +cIm2D ImageOfString_10x8(const std::string & aStr ,int aSpace) +{ + Im2D_Bits<1> aImV1 = cElBitmFont::BasicFont_10x8().BasicImageString(aStr,aSpace); + return BitsV1ToV2(aImV1); +} + +cIm2D ImageOfString_DCT(const std::string & aStr ,int aSpace) +{ + Im2D_Bits<1> aImV1 = cElBitmFont::FontCodedTarget().BasicImageString(aStr,aSpace); + return BitsV1ToV2(aImV1); +} + +void Convert_JPG(const std::string & aNameIm,bool DeleteAfter,tREAL8 aQuality,const std::string & aPost) +{ + cParamCallSys aCom("convert","-quality",ToStr(aQuality), + aNameIm, + LastPrefix(aNameIm) + "." + aPost + ); + + int aResult = GlobSysCall(aCom,true); + + if ( (aResult==EXIT_SUCCESS) && DeleteAfter) + { + RemoveFile(aNameIm,false); + } + +} + + +// INSTANTIATION + +#define MACRO_INSTANTIATE_READ_FILE(Type)\ +template class cDataIm2D;\ +template class cIm2D; + +MACRO_INSTANTIATE_READ_FILE(tINT1) +MACRO_INSTANTIATE_READ_FILE(tINT2) +MACRO_INSTANTIATE_READ_FILE(tINT4) +// MACRO_INSTANTIATE_READ_FILE(tINT8) +MACRO_INSTANTIATE_READ_FILE(tU_INT1) +MACRO_INSTANTIATE_READ_FILE(tU_INT2) +MACRO_INSTANTIATE_READ_FILE(tU_INT4) +MACRO_INSTANTIATE_READ_FILE(tREAL4) +MACRO_INSTANTIATE_READ_FILE(tREAL8) +MACRO_INSTANTIATE_READ_FILE(tREAL16) +}; diff --git a/MMVII/src/MMV1/FileImagesMMV1.cpp b/MMVII/src/MMV1/FileImagesMMV1.cpp.obsolete similarity index 100% rename from MMVII/src/MMV1/FileImagesMMV1.cpp rename to MMVII/src/MMV1/FileImagesMMV1.cpp.obsolete diff --git a/MMVII/src/Utils/uti_string.cpp b/MMVII/src/Utils/uti_string.cpp index da9cc0bd2f..1d312da65a 100755 --- a/MMVII/src/Utils/uti_string.cpp +++ b/MMVII/src/Utils/uti_string.cpp @@ -660,6 +660,16 @@ bool starts_with(const std::string & aFullStr,const std::string & aPrefix) return anItPref==aPrefix.end(); } +bool ends_with(const std::string & aFullStr,const std::string & aEnding) +{ + if (aFullStr.size() < aEnding.size()) + return false; + auto it = aEnding.begin(); + return std::all_of(std::next(aFullStr.begin(),aFullStr.size()-aEnding.size()), aFullStr.end(), + [&it](const char& c) { return c == *(it++);}); + +} + bool IsPrefixed(const std::string & aStr,char aSep) { return aStr.find(aSep) != std::string::npos;