void GDALProxyDataset::FlushCache() { GDALDataset* poUnderlyingDataset = RefUnderlyingDataset(); if (poUnderlyingDataset) { poUnderlyingDataset->FlushCache(); UnrefUnderlyingDataset(poUnderlyingDataset); } }
static GDALDataset* createDataSetFromImage(const osg::Image* image, double minX, double minY, double maxX, double maxY, const std::string &projection) { //Clone the incoming image osg::ref_ptr<osg::Image> clonedImage = new osg::Image(*image); //Flip the image clonedImage->flipVertical(); GDALDataset* srcDS = createMemDS(image->s(), image->t(), minX, minY, maxX, maxY, projection); //Write the image data into the memory dataset //If the image is already RGBA, just read all 4 bands in one call if (image->getPixelFormat() == GL_RGBA) { srcDS->RasterIO(GF_Write, 0, 0, clonedImage->s(), clonedImage->t(), (void*)clonedImage->data(), clonedImage->s(), clonedImage->t(), GDT_Byte, 4, NULL, 4, 4 * image->s(), 1); } else if (image->getPixelFormat() == GL_RGB) { //OE_NOTICE << "[osgEarth::GeoData] Reprojecting RGB " << std::endl; //Read the read, green and blue bands srcDS->RasterIO(GF_Write, 0, 0, clonedImage->s(), clonedImage->t(), (void*)clonedImage->data(), clonedImage->s(), clonedImage->t(), GDT_Byte, 3, NULL, 3, 3 * image->s(), 1); //Initialize the alpha values to 255. unsigned char *alpha = new unsigned char[clonedImage->s() * clonedImage->t()]; memset(alpha, 255, clonedImage->s() * clonedImage->t()); GDALRasterBand* alphaBand = srcDS->GetRasterBand(4); alphaBand->RasterIO(GF_Write, 0, 0, clonedImage->s(), clonedImage->t(), alpha, clonedImage->s(),clonedImage->t(), GDT_Byte, 0, 0); delete[] alpha; } else { OE_WARN << LC << "createDataSetFromImage: unsupported pixel format " << std::hex << image->getPixelFormat() << std::endl; } srcDS->FlushCache(); return srcDS; }
CPLErr GTIFFBuildOverviews( const char * pszFilename, int nBands, GDALRasterBand **papoBandList, int nOverviews, int * panOverviewList, const char * pszResampling, GDALProgressFunc pfnProgress, void * pProgressData ) { TIFF *hOTIFF; int nBitsPerPixel=0, nCompression=COMPRESSION_NONE, nPhotometric=0; int nSampleFormat=0, nPlanarConfig, iOverview, iBand; int nXSize=0, nYSize=0; if( nBands == 0 || nOverviews == 0 ) return CE_None; if (!GTiffOneTimeInit()) return CE_Failure; /* -------------------------------------------------------------------- */ /* Verify that the list of bands is suitable for emitting in */ /* TIFF file. */ /* -------------------------------------------------------------------- */ for( iBand = 0; iBand < nBands; iBand++ ) { int nBandBits, nBandFormat; GDALRasterBand *hBand = papoBandList[iBand]; switch( hBand->GetRasterDataType() ) { case GDT_Byte: nBandBits = 8; nBandFormat = SAMPLEFORMAT_UINT; break; case GDT_UInt16: nBandBits = 16; nBandFormat = SAMPLEFORMAT_UINT; break; case GDT_Int16: nBandBits = 16; nBandFormat = SAMPLEFORMAT_INT; break; case GDT_UInt32: nBandBits = 32; nBandFormat = SAMPLEFORMAT_UINT; break; case GDT_Int32: nBandBits = 32; nBandFormat = SAMPLEFORMAT_INT; break; case GDT_Float32: nBandBits = 32; nBandFormat = SAMPLEFORMAT_IEEEFP; break; case GDT_Float64: nBandBits = 64; nBandFormat = SAMPLEFORMAT_IEEEFP; break; case GDT_CInt16: nBandBits = 32; nBandFormat = SAMPLEFORMAT_COMPLEXINT; break; case GDT_CInt32: nBandBits = 64; nBandFormat = SAMPLEFORMAT_COMPLEXINT; break; case GDT_CFloat32: nBandBits = 64; nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP; break; case GDT_CFloat64: nBandBits = 128; nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP; break; default: CPLAssert( FALSE ); return CE_Failure; } if( hBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) ) { nBandBits = atoi(hBand->GetMetadataItem("NBITS","IMAGE_STRUCTURE")); if( nBandBits == 1 && EQUALN(pszResampling,"AVERAGE_BIT2",12) ) nBandBits = 8; } if( iBand == 0 ) { nBitsPerPixel = nBandBits; nSampleFormat = nBandFormat; nXSize = hBand->GetXSize(); nYSize = hBand->GetYSize(); } else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support a mixture of band" " data types." ); return CE_Failure; } else if( hBand->GetColorTable() != NULL ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support building" " overviews of multiple colormapped bands." ); return CE_Failure; } else if( hBand->GetXSize() != nXSize || hBand->GetYSize() != nYSize ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support building" " overviews of different sized bands." ); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Use specified compression method. */ /* -------------------------------------------------------------------- */ const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", NULL ); if( pszCompress != NULL && pszCompress[0] != '\0' ) { nCompression = GTIFFGetCompressionMethod(pszCompress, "COMPRESS_OVERVIEW"); if (nCompression < 0) return CE_Failure; } if( nCompression == COMPRESSION_JPEG && nBitsPerPixel > 8 ) { if( nBitsPerPixel > 16 ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support building" " JPEG compressed overviews of nBitsPerPixel > 16." ); return CE_Failure; } nBitsPerPixel = 12; } /* -------------------------------------------------------------------- */ /* Figure out the planar configuration to use. */ /* -------------------------------------------------------------------- */ if( nBands == 1 ) nPlanarConfig = PLANARCONFIG_CONTIG; else nPlanarConfig = PLANARCONFIG_SEPARATE; const char* pszInterleave = CPLGetConfigOption( "INTERLEAVE_OVERVIEW", NULL ); if (pszInterleave != NULL && pszInterleave[0] != '\0') { if( EQUAL( pszInterleave, "PIXEL" ) ) nPlanarConfig = PLANARCONFIG_CONTIG; else if( EQUAL( pszInterleave, "BAND" ) ) nPlanarConfig = PLANARCONFIG_SEPARATE; else { CPLError( CE_Failure, CPLE_AppDefined, "INTERLEAVE_OVERVIEW=%s unsupported, value must be PIXEL or BAND. ignoring", pszInterleave ); } } /* -------------------------------------------------------------------- */ /* Figure out the photometric interpretation to use. */ /* -------------------------------------------------------------------- */ if( nBands == 3 ) nPhotometric = PHOTOMETRIC_RGB; else if( papoBandList[0]->GetColorTable() != NULL && !EQUALN(pszResampling,"AVERAGE_BIT2",12) ) { nPhotometric = PHOTOMETRIC_PALETTE; /* should set the colormap up at this point too! */ } else nPhotometric = PHOTOMETRIC_MINISBLACK; const char* pszPhotometric = CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", NULL ); if (pszPhotometric != NULL && pszPhotometric[0] != '\0') { if( EQUAL( pszPhotometric, "MINISBLACK" ) ) nPhotometric = PHOTOMETRIC_MINISBLACK; else if( EQUAL( pszPhotometric, "MINISWHITE" ) ) nPhotometric = PHOTOMETRIC_MINISWHITE; else if( EQUAL( pszPhotometric, "RGB" )) { nPhotometric = PHOTOMETRIC_RGB; } else if( EQUAL( pszPhotometric, "CMYK" )) { nPhotometric = PHOTOMETRIC_SEPARATED; } else if( EQUAL( pszPhotometric, "YCBCR" )) { nPhotometric = PHOTOMETRIC_YCBCR; /* Because of subsampling, setting YCBCR without JPEG compression leads */ /* to a crash currently. Would need to make GTiffRasterBand::IWriteBlock() */ /* aware of subsampling so that it doesn't overrun buffer size returned */ /* by libtiff */ if ( nCompression != COMPRESSION_JPEG ) { CPLError(CE_Failure, CPLE_NotSupported, "Currently, PHOTOMETRIC_OVERVIEW=YCBCR requires COMPRESS_OVERVIEW=JPEG"); return CE_Failure; } if (pszInterleave != NULL && pszInterleave[0] != '\0' && nPlanarConfig == PLANARCONFIG_SEPARATE) { CPLError(CE_Failure, CPLE_NotSupported, "PHOTOMETRIC_OVERVIEW=YCBCR requires INTERLEAVE_OVERVIEW=PIXEL"); return CE_Failure; } else { nPlanarConfig = PLANARCONFIG_CONTIG; } /* YCBCR strictly requires 3 bands. Not less, not more */ /* Issue an explicit error message as libtiff one is a bit cryptic : */ /* JPEGLib:Bogus input colorspace */ if ( nBands != 3 ) { CPLError(CE_Failure, CPLE_NotSupported, "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster with only 3 bands (RGB)"); return CE_Failure; } } else if( EQUAL( pszPhotometric, "CIELAB" )) { nPhotometric = PHOTOMETRIC_CIELAB; } else if( EQUAL( pszPhotometric, "ICCLAB" )) { nPhotometric = PHOTOMETRIC_ICCLAB; } else if( EQUAL( pszPhotometric, "ITULAB" )) { nPhotometric = PHOTOMETRIC_ITULAB; } else { CPLError( CE_Warning, CPLE_IllegalArg, "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.\n", pszPhotometric ); } } /* -------------------------------------------------------------------- */ /* Figure out the predictor value to use. */ /* -------------------------------------------------------------------- */ int nPredictor = PREDICTOR_NONE; if ( nCompression == COMPRESSION_LZW || nCompression == COMPRESSION_ADOBE_DEFLATE ) { const char* pszPredictor = CPLGetConfigOption( "PREDICTOR_OVERVIEW", NULL ); if( pszPredictor != NULL ) { nPredictor = atoi( pszPredictor ); } } /* -------------------------------------------------------------------- */ /* Create the file, if it does not already exist. */ /* -------------------------------------------------------------------- */ VSIStatBufL sStatBuf; VSILFILE* fpL = NULL; if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 ) { /* -------------------------------------------------------------------- */ /* Compute the uncompressed size. */ /* -------------------------------------------------------------------- */ double dfUncompressedOverviewSize = 0; int nDataTypeSize = GDALGetDataTypeSize(papoBandList[0]->GetRasterDataType())/8; for( iOverview = 0; iOverview < nOverviews; iOverview++ ) { int nOXSize, nOYSize; nOXSize = (nXSize + panOverviewList[iOverview] - 1) / panOverviewList[iOverview]; nOYSize = (nYSize + panOverviewList[iOverview] - 1) / panOverviewList[iOverview]; dfUncompressedOverviewSize += nOXSize * ((double)nOYSize) * nBands * nDataTypeSize; } if( nCompression == COMPRESSION_NONE && dfUncompressedOverviewSize > 4200000000.0 ) { #ifndef BIGTIFF_SUPPORT CPLError( CE_Failure, CPLE_NotSupported, "The overview file would be larger than 4GB\n" "but this is the largest size a TIFF can be, and BigTIFF is unavailable.\n" "Creation failed." ); return CE_Failure; #endif } /* -------------------------------------------------------------------- */ /* Should the file be created as a bigtiff file? */ /* -------------------------------------------------------------------- */ const char *pszBIGTIFF = CPLGetConfigOption( "BIGTIFF_OVERVIEW", NULL ); if( pszBIGTIFF == NULL ) pszBIGTIFF = "IF_NEEDED"; int bCreateBigTIFF = FALSE; if( EQUAL(pszBIGTIFF,"IF_NEEDED") ) { if( nCompression == COMPRESSION_NONE && dfUncompressedOverviewSize > 4200000000.0 ) bCreateBigTIFF = TRUE; } else if( EQUAL(pszBIGTIFF,"IF_SAFER") ) { /* Look at the size of the base image and suppose that */ /* the added overview levels won't be more than 1/2 of */ /* the size of the base image. The theory says 1/3 of the */ /* base image size if the overview levels are 2, 4, 8, 16... */ /* Thus take 1/2 as the security margin for 1/3 */ double dfUncompressedImageSize = nXSize * ((double)nYSize) * nBands * nDataTypeSize; if( dfUncompressedImageSize * .5 > 4200000000.0 ) bCreateBigTIFF = TRUE; } else { bCreateBigTIFF = CSLTestBoolean( pszBIGTIFF ); if (!bCreateBigTIFF && nCompression == COMPRESSION_NONE && dfUncompressedOverviewSize > 4200000000.0 ) { CPLError( CE_Failure, CPLE_NotSupported, "The overview file will be larger than 4GB, so BigTIFF is necessary.\n" "Creation failed."); return CE_Failure; } } #ifndef BIGTIFF_SUPPORT if( bCreateBigTIFF ) { CPLError( CE_Warning, CPLE_NotSupported, "BigTIFF requested, but GDAL built without BigTIFF\n" "enabled libtiff, request ignored." ); bCreateBigTIFF = FALSE; } #endif if( bCreateBigTIFF ) CPLDebug( "GTiff", "File being created as a BigTIFF." ); fpL = VSIFOpenL( pszFilename, "w+" ); if( fpL == NULL ) hOTIFF = NULL; else hOTIFF = VSI_TIFFOpen( pszFilename, (bCreateBigTIFF) ? "w+8" : "w+", fpL ); if( hOTIFF == NULL ) { if( CPLGetLastErrorNo() == 0 ) CPLError( CE_Failure, CPLE_OpenFailed, "Attempt to create new tiff file `%s'\n" "failed in VSI_TIFFOpen().\n", pszFilename ); if( fpL != NULL ) VSIFCloseL(fpL); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Otherwise just open it for update access. */ /* -------------------------------------------------------------------- */ else { fpL = VSIFOpenL( pszFilename, "r+" ); if( fpL == NULL ) hOTIFF = NULL; else hOTIFF = VSI_TIFFOpen( pszFilename, "r+", fpL ); if( hOTIFF == NULL ) { if( CPLGetLastErrorNo() == 0 ) CPLError( CE_Failure, CPLE_OpenFailed, "Attempt to create new tiff file `%s'\n" "failed in VSI_TIFFOpen().\n", pszFilename ); if( fpL != NULL ) VSIFCloseL(fpL); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Do we have a palette? If so, create a TIFF compatible version. */ /* -------------------------------------------------------------------- */ unsigned short *panRed=NULL, *panGreen=NULL, *panBlue=NULL; if( nPhotometric == PHOTOMETRIC_PALETTE ) { GDALColorTable *poCT = papoBandList[0]->GetColorTable(); int nColorCount; if( nBitsPerPixel <= 8 ) nColorCount = 256; else nColorCount = 65536; panRed = (unsigned short *) CPLCalloc(nColorCount,sizeof(unsigned short)); panGreen = (unsigned short *) CPLCalloc(nColorCount,sizeof(unsigned short)); panBlue = (unsigned short *) CPLCalloc(nColorCount,sizeof(unsigned short)); for( int iColor = 0; iColor < nColorCount; iColor++ ) { GDALColorEntry sRGB; if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) ) { panRed[iColor] = (unsigned short) (257 * sRGB.c1); panGreen[iColor] = (unsigned short) (257 * sRGB.c2); panBlue[iColor] = (unsigned short) (257 * sRGB.c3); } } } /* -------------------------------------------------------------------- */ /* Do we need some metadata for the overviews? */ /* -------------------------------------------------------------------- */ CPLString osMetadata; GDALDataset *poBaseDS = papoBandList[0]->GetDataset(); GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata ); /* -------------------------------------------------------------------- */ /* Loop, creating overviews. */ /* -------------------------------------------------------------------- */ int nOvrBlockXSize, nOvrBlockYSize; GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize); for( iOverview = 0; iOverview < nOverviews; iOverview++ ) { int nOXSize, nOYSize; nOXSize = (nXSize + panOverviewList[iOverview] - 1) / panOverviewList[iOverview]; nOYSize = (nYSize + panOverviewList[iOverview] - 1) / panOverviewList[iOverview]; GTIFFWriteDirectory(hOTIFF, FILETYPE_REDUCEDIMAGE, nOXSize, nOYSize, nBitsPerPixel, nPlanarConfig, nBands, nOvrBlockXSize, nOvrBlockYSize, TRUE, nCompression, nPhotometric, nSampleFormat, nPredictor, panRed, panGreen, panBlue, 0, NULL, /* FIXME? how can we fetch extrasamples */ osMetadata ); } if (panRed) { CPLFree(panRed); CPLFree(panGreen); CPLFree(panBlue); panRed = panGreen = panBlue = NULL; } XTIFFClose( hOTIFF ); VSIFCloseL(fpL); fpL = NULL; /* -------------------------------------------------------------------- */ /* Open the overview dataset so that we can get at the overview */ /* bands. */ /* -------------------------------------------------------------------- */ GDALDataset *hODS; CPLErr eErr = CE_None; hODS = (GDALDataset *) GDALOpen( pszFilename, GA_Update ); if( hODS == NULL ) return CE_Failure; /* -------------------------------------------------------------------- */ /* Do we need to set the jpeg quality? */ /* -------------------------------------------------------------------- */ TIFF *hTIFF = (TIFF*) hODS->GetInternalHandle(NULL); if( nCompression == COMPRESSION_JPEG && CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", NULL ) != NULL ) { int nJpegQuality = atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75")); TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality ); GTIFFSetJpegQuality((GDALDatasetH)hODS, nJpegQuality); } /* -------------------------------------------------------------------- */ /* Loop writing overview data. */ /* -------------------------------------------------------------------- */ if (nCompression != COMPRESSION_NONE && nPlanarConfig == PLANARCONFIG_CONTIG && GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) == FALSE && papoBandList[0]->GetColorTable() == NULL && (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS") || EQUAL(pszResampling, "CUBIC") || EQUAL(pszResampling, "CUBICSPLINE") || EQUAL(pszResampling, "LANCZOS") || EQUAL(pszResampling, "BILINEAR"))) { /* In the case of pixel interleaved compressed overviews, we want to generate */ /* the overviews for all the bands block by block, and not band after band, */ /* in order to write the block once and not loose space in the TIFF file */ GDALRasterBand ***papapoOverviewBands; papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands); for( iBand = 0; iBand < nBands && eErr == CE_None; iBand++ ) { GDALRasterBand *hSrcBand = papoBandList[iBand]; GDALRasterBand *hDstBand = hODS->GetRasterBand( iBand+1 ); papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews); papapoOverviewBands[iBand][0] = hDstBand; int bHasNoData; double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData); if (bHasNoData) hDstBand->SetNoDataValue(noDataValue); for( int i = 0; i < nOverviews-1 && eErr == CE_None; i++ ) { papapoOverviewBands[iBand][i+1] = hDstBand->GetOverview(i); if (papapoOverviewBands[iBand][i+1] == NULL) eErr = CE_Failure; else { if (bHasNoData) papapoOverviewBands[iBand][i+1]->SetNoDataValue(noDataValue); } } } if (eErr == CE_None) eErr = GDALRegenerateOverviewsMultiBand(nBands, papoBandList, nOverviews, papapoOverviewBands, pszResampling, pfnProgress, pProgressData ); for( iBand = 0; iBand < nBands; iBand++ ) { CPLFree(papapoOverviewBands[iBand]); } CPLFree(papapoOverviewBands); } else { GDALRasterBand **papoOverviews; papoOverviews = (GDALRasterBand **) CPLCalloc(sizeof(void*),128); for( iBand = 0; iBand < nBands && eErr == CE_None; iBand++ ) { GDALRasterBand *hSrcBand = papoBandList[iBand]; GDALRasterBand *hDstBand; int nDstOverviews; hDstBand = hODS->GetRasterBand( iBand+1 ); int bHasNoData; double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData); if (bHasNoData) hDstBand->SetNoDataValue(noDataValue); papoOverviews[0] = hDstBand; nDstOverviews = hDstBand->GetOverviewCount() + 1; CPLAssert( nDstOverviews < 128 ); nDstOverviews = MIN(128,nDstOverviews); for( int i = 0; i < nDstOverviews-1 && eErr == CE_None; i++ ) { papoOverviews[i+1] = hDstBand->GetOverview(i); if (papoOverviews[i+1] == NULL) eErr = CE_Failure; else { if (bHasNoData) papoOverviews[i+1]->SetNoDataValue(noDataValue); } } void *pScaledProgressData; pScaledProgressData = GDALCreateScaledProgress( iBand / (double) nBands, (iBand+1) / (double) nBands, pfnProgress, pProgressData ); if (eErr == CE_None) eErr = GDALRegenerateOverviews( (GDALRasterBandH) hSrcBand, nDstOverviews, (GDALRasterBandH *) papoOverviews, pszResampling, GDALScaledProgress, pScaledProgressData); GDALDestroyScaledProgress( pScaledProgressData ); } CPLFree( papoOverviews ); } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ if (eErr == CE_None) hODS->FlushCache(); delete hODS; pfnProgress( 1.0, NULL, pProgressData ); return eErr; }
int meaningful_change(string cd_map_file, string result_file) { GdalRasterApp cd_map; cd_map.open(cd_map_file.c_str()); int iBandCount = cd_map.nBand(); int iTileCountX = cd_map.getTileCountX(); int iTileCountY = cd_map.getTileCountY(); int iWidth = cd_map.width(); int iHeight = cd_map.height(); GDALDriver *poDriver; //驱动,用于创建新的文件 poDriver=GetGDALDriverManager()->GetDriverByName("GTIFF"); char **papszMetadata = poDriver->GetMetadata();//获取格式类型 GDALDataset *poDatasetNew; // 输出栅格 poDatasetNew = poDriver->Create(result_file.c_str(), iWidth, iHeight, 1, GDT_Byte, papszMetadata);//根据文件路径文件名,图像宽,高,波段数,数据类型,文件类型,创建新的数据集 poDatasetNew->SetProjection(cd_map.getGetProjectionRef()); poDatasetNew->SetGeoTransform(cd_map.getGeoTransform());//坐标赋值,与全色相同 int nCount = 0; double norm_threshold = 20.0; int bgColor = 0; int fgColor = 255; for (int i = 0;i < iTileCountX;++i) { for (int j = 0;j < iTileCountY;++j) { GdalRasterApp::RasterBuf *pBuf = cd_map.getTileData(i, j, iBandCount); int bufWidth = pBuf->iBufWidth; int bufHeight = pBuf->iBufHeight; int bufBand = pBuf->iBandCount; int offsetX, offsetY; cd_map.getTileOffset(i, j, offsetX, offsetY); cv::Mat change_image(cv::Size(bufWidth, bufHeight), CV_8UC1, cv::Scalar(fgColor)); //cv::Mat lbp_change(cv::Size(bufWidth, bufHeight), CV_8UC1); cv::Mat lbp_change = img_int2byte_band(pBuf, 0); //cv::Mat lbp_change = img_float2byte_band(pBuf, 0); //memcpy(lbp_change.data, pBuf->data, bufWidth*bufHeight); //cv::imwrite("E:\\minus.tif", lbp_change); int lbp_change_threshold = cvThresholdOtsu(lbp_change); int step = change_image.step; // change detection for (int row = 0; row < bufHeight; ++row) { for (int col = 0; col < bufWidth; ++col) { int lbp_change_ = lbp_change.data[row*lbp_change.step+col]; // 判断是否变化很小 if (lbp_change_ < lbp_change_threshold) { change_image.data[row*step+col] = bgColor; continue; } std::vector<double> change_vector(pFeatureBuf->iBandCount); for (int k = 0;k < pFeatureBuf->iBandCount;++k) { int pos = row * bufWidth * pFeatureBuf->iBandCount + col*pFeatureBuf->iBandCount + k; change_vector[k] = ((float*)pFeatureBuf->data)[pos]; } //如果变化是否和样本相似 for (int m = 0; m < (int)samples.size(); m++) { double angle_ = samples[m][0] - change_vector[0]; double norm_ = samples[m][1] - change_vector[1]; //double similarity = VectorSimilarity(samples[m], change_vector); //double distance = VectorDistance(samples[m], change_vector); //double angle = VectorAngle(samples[m], change_vector); //if (fabs(similarity) > similarityThreshold && distance < 15.0) //if (fabs(angle) < 10.0 && distance < 20.0) //if (fabs(similarity) < similarityThreshold) if (fabs(angle_) < similarityThreshold && fabs(norm_) < 10.0) //if (fabs(norm) < 10.0) { change_image.data[row*step+col] = bgColor; break; } } } } //RasterBuf2Opencv(pBuf, change_image); //cv::Mat change_image(bufHeight, bufWidth, CV_8U(bufBand)); //int nBandDataSize = GDALGetDataTypeSize( pBuf->eDataType ) / 8; //memcpy(change_image.data, (GByte*)(pBuf->data), bufWidth*bufHeight*bufBand*nBandDataSize); //cvtColor( change_image, change_image, CV_BGR2GRAY ); //int threshold = cvThresholdOtsu(change_image); //threshold = 60; //cv::threshold( change_image, change_image, threshold, 255, CV_THRESH_BINARY); //cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3)); //cv::morphologyEx(change_image, change_image, cv::MORPH_CLOSE, element); //element = cv::getStructuringElement(cv::MORPH_CROSS , cv::Size(7, 7)); //cv::morphologyEx(change_image, change_image, cv::MORPH_OPEN, element); //element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7)); //cv::morphologyEx(change_image, change_image, cv::MORPH_OPEN, element); //cv::GaussianBlur(change_image, change_image, cv::Size(5,5), 1.5); //cv::morphologyEx(change_image, change_image, cv::MORPH_CLOSE, element); //cv::imwrite("E:\\test0.tif", change_image); cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(2,2)); //cv::morphologyEx(change_image, change_image, cv::MORPH_CLOSE, element); int nTemplate = sqrt(smallArea); nTemplate = nTemplate / 2 * 2 + 1; cv::medianBlur(change_image, change_image, nTemplate); //cv::imwrite("E:\\test1.tif", change_image); // 先闭运算 nTemplate = nTemplate / 2; element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5,5)); cv::morphologyEx(change_image, change_image, cv::MORPH_CLOSE, element); // 再开运算 //element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(10, 10)); //cv::morphologyEx(change_image, change_image, cv::MORPH_OPEN, element); //cv::imwrite("E:\\test2.tif", change_image); BinaryRemoveSmall(change_image, change_image, smallArea, bgColor, fgColor); //cv::Mat tmpMat = change_image.clone(); ////cv::GaussianBlur(tmpMat, tmpMat, cv::Size(5,5), 1.5); //std::vector<std::vector<cv::Point> > contours; //std::vector<cv::Vec4i> hierarchy; //cv::findContours(tmpMat, contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); ////for (std::vector<std::vector<cv::Point> >::iterator iter_Contours = contours.begin(); iter_Contours != contours.end();++iter_Contours) //int nContours = (int)contours.size(); //for (int iContours = 0; iContours < nContours;++iContours) //{ // std::vector<cv::Point> contour = contours[iContours]; // double tempArea = fabs(cv::contourArea(contour)); // cv::Rect rect = cv::boundingRect(contour); // //当连通域的中心点为白色,而且面积较小时,用黑色进行填充 // if (tempArea < miniArea) // { // int pos_center = step*(rect.y+rect.height/2)+rect.x+rect.width/2; // //if (255 == change_image.data[pos_center]) // { // for(int y = rect.y;y<rect.y+rect.height;y++) // { // for(int x =rect.x;x<rect.x+rect.width;x++) // { // int pos_ = y*step+x; // if(255 == change_image.data[pos_]) // { // change_image.data[pos_] = 0; // } // } // } // } // } //} //cv::imwrite("E:\\test3.tif", change_image); ////cv::imwrite("E:\\test.tif", change_image); if (_changeOutType::raster == outType) { // 输出栅格 CPLErr gdal_err = poDatasetNew->RasterIO(GF_Write, offsetX, offsetY, bufWidth, bufHeight, change_image.data, bufWidth, bufHeight,\ GDT_Byte, 1, 0, 0, 0, 0); } else if (_changeOutType::vector == outType) { // 输出矢量 std::vector<std::vector<cv::Point> > contours; std::vector<cv::Vec4i> hierarchy; cv::findContours(change_image, contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); addContour2ShapeArea(contours, out_layer_file, raster_minus.getGeoTransform(), raster_minus.getGetProjectionRef(), nCount, raster_minus.getBufInfo()->iBufOffsetX, raster_minus.getBufInfo()->iBufOffsetY); nCount += (int)contours.size(); } pBuf = NULL; } } raster_minus.close(); raster_feature.close(); poDatasetNew->FlushCache(); GDALClose(poDatasetNew); }
CPLErr GTIFFBuildOverviews( const char * pszFilename, int nBands, GDALRasterBand **papoBandList, int nOverviews, int * panOverviewList, const char * pszResampling, GDALProgressFunc pfnProgress, void * pProgressData ) { TIFF *hOTIFF; int nBitsPerPixel=0, nCompression=COMPRESSION_NONE, nPhotometric=0; int nSampleFormat=0, nPlanarConfig, iOverview, iBand; int nXSize=0, nYSize=0; if( nBands == 0 || nOverviews == 0 ) return CE_None; GTiffOneTimeInit(); /* -------------------------------------------------------------------- */ /* Verify that the list of bands is suitable for emitting in */ /* TIFF file. */ /* -------------------------------------------------------------------- */ for( iBand = 0; iBand < nBands; iBand++ ) { int nBandBits, nBandFormat; GDALRasterBand *hBand = papoBandList[iBand]; switch( hBand->GetRasterDataType() ) { case GDT_Byte: nBandBits = 8; nBandFormat = SAMPLEFORMAT_UINT; break; case GDT_UInt16: nBandBits = 16; nBandFormat = SAMPLEFORMAT_UINT; break; case GDT_Int16: nBandBits = 16; nBandFormat = SAMPLEFORMAT_INT; break; case GDT_UInt32: nBandBits = 32; nBandFormat = SAMPLEFORMAT_UINT; break; case GDT_Int32: nBandBits = 32; nBandFormat = SAMPLEFORMAT_INT; break; case GDT_Float32: nBandBits = 32; nBandFormat = SAMPLEFORMAT_IEEEFP; break; case GDT_Float64: nBandBits = 64; nBandFormat = SAMPLEFORMAT_IEEEFP; break; case GDT_CInt16: nBandBits = 32; nBandFormat = SAMPLEFORMAT_COMPLEXINT; break; case GDT_CFloat32: nBandBits = 64; nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP; break; case GDT_CFloat64: nBandBits = 128; nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP; break; default: CPLAssert( FALSE ); return CE_Failure; } if( iBand == 0 ) { nBitsPerPixel = nBandBits; nSampleFormat = nBandFormat; nXSize = hBand->GetXSize(); nYSize = hBand->GetYSize(); } else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support a mixture of band" " data types." ); return CE_Failure; } else if( hBand->GetColorTable() != NULL ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support building" " overviews of multiple colormapped bands." ); return CE_Failure; } else if( hBand->GetXSize() != nXSize || hBand->GetYSize() != nYSize ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support building" " overviews of different sized bands." ); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Use specified compression method. */ /* -------------------------------------------------------------------- */ const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", NULL ); if( pszCompress != NULL && pszCompress[0] != '\0' ) { if( EQUAL( pszCompress, "JPEG" ) ) nCompression = COMPRESSION_JPEG; else if( EQUAL( pszCompress, "LZW" ) ) nCompression = COMPRESSION_LZW; else if( EQUAL( pszCompress, "PACKBITS" )) nCompression = COMPRESSION_PACKBITS; else if( EQUAL( pszCompress, "DEFLATE" ) || EQUAL( pszCompress, "ZIP" )) nCompression = COMPRESSION_ADOBE_DEFLATE; else CPLError( CE_Warning, CPLE_IllegalArg, "COMPRESS_OVERVIEW=%s value not recognised, ignoring.", pszCompress ); } /* -------------------------------------------------------------------- */ /* Figure out the planar configuration to use. */ /* -------------------------------------------------------------------- */ if( nBands == 1 ) nPlanarConfig = PLANARCONFIG_CONTIG; else nPlanarConfig = PLANARCONFIG_SEPARATE; const char* pszInterleave = CPLGetConfigOption( "INTERLEAVE_OVERVIEW", NULL ); if (pszInterleave != NULL && pszInterleave[0] != '\0') { if( EQUAL( pszInterleave, "PIXEL" ) ) nPlanarConfig = PLANARCONFIG_CONTIG; else if( EQUAL( pszInterleave, "BAND" ) ) nPlanarConfig = PLANARCONFIG_SEPARATE; else { CPLError( CE_Failure, CPLE_AppDefined, "INTERLEAVE_OVERVIEW=%s unsupported, value must be PIXEL or BAND. ignoring", pszInterleave ); } } /* -------------------------------------------------------------------- */ /* Figure out the photometric interpretation to use. */ /* -------------------------------------------------------------------- */ if( nBands == 3 ) nPhotometric = PHOTOMETRIC_RGB; else if( papoBandList[0]->GetColorTable() != NULL && !EQUALN(pszResampling,"AVERAGE_BIT2",12) ) { nPhotometric = PHOTOMETRIC_PALETTE; /* should set the colormap up at this point too! */ } else nPhotometric = PHOTOMETRIC_MINISBLACK; const char* pszPhotometric = CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", NULL ); if (pszPhotometric != NULL && pszPhotometric[0] != '\0') { if( EQUAL( pszPhotometric, "MINISBLACK" ) ) nPhotometric = PHOTOMETRIC_MINISBLACK; else if( EQUAL( pszPhotometric, "MINISWHITE" ) ) nPhotometric = PHOTOMETRIC_MINISWHITE; else if( EQUAL( pszPhotometric, "RGB" )) { nPhotometric = PHOTOMETRIC_RGB; } else if( EQUAL( pszPhotometric, "CMYK" )) { nPhotometric = PHOTOMETRIC_SEPARATED; } else if( EQUAL( pszPhotometric, "YCBCR" )) { nPhotometric = PHOTOMETRIC_YCBCR; } else if( EQUAL( pszPhotometric, "CIELAB" )) { nPhotometric = PHOTOMETRIC_CIELAB; } else if( EQUAL( pszPhotometric, "ICCLAB" )) { nPhotometric = PHOTOMETRIC_ICCLAB; } else if( EQUAL( pszPhotometric, "ITULAB" )) { nPhotometric = PHOTOMETRIC_ITULAB; } else { CPLError( CE_Warning, CPLE_IllegalArg, "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.\n", pszPhotometric ); } } /* -------------------------------------------------------------------- */ /* Create the file, if it does not already exist. */ /* -------------------------------------------------------------------- */ VSIStatBuf sStatBuf; if( VSIStat( pszFilename, &sStatBuf ) != 0 ) { hOTIFF = XTIFFOpen( pszFilename, "w+" ); if( hOTIFF == NULL ) { if( CPLGetLastErrorNo() == 0 ) CPLError( CE_Failure, CPLE_OpenFailed, "Attempt to create new tiff file `%s'\n" "failed in XTIFFOpen().\n", pszFilename ); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Otherwise just open it for update access. */ /* -------------------------------------------------------------------- */ else { hOTIFF = XTIFFOpen( pszFilename, "r+" ); if( hOTIFF == NULL ) { if( CPLGetLastErrorNo() == 0 ) CPLError( CE_Failure, CPLE_OpenFailed, "Attempt to create new tiff file `%s'\n" "failed in XTIFFOpen().\n", pszFilename ); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Do we have a palette? If so, create a TIFF compatible version. */ /* -------------------------------------------------------------------- */ unsigned short *panRed=NULL, *panGreen=NULL, *panBlue=NULL; if( nPhotometric == PHOTOMETRIC_PALETTE ) { GDALColorTable *poCT = papoBandList[0]->GetColorTable(); int nColorCount; if( nBitsPerPixel <= 8 ) nColorCount = 256; else nColorCount = 65536; panRed = (unsigned short *) CPLCalloc(nColorCount,sizeof(unsigned short)); panGreen = (unsigned short *) CPLCalloc(nColorCount,sizeof(unsigned short)); panBlue = (unsigned short *) CPLCalloc(nColorCount,sizeof(unsigned short)); for( int iColor = 0; iColor < nColorCount; iColor++ ) { GDALColorEntry sRGB; if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) ) { panRed[iColor] = (unsigned short) (257 * sRGB.c1); panGreen[iColor] = (unsigned short) (257 * sRGB.c2); panBlue[iColor] = (unsigned short) (257 * sRGB.c3); } } } /* -------------------------------------------------------------------- */ /* Do we need some metadata for the overviews? */ /* -------------------------------------------------------------------- */ CPLString osMetadata; GDALDataset *poBaseDS = papoBandList[0]->GetDataset(); GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata ); /* -------------------------------------------------------------------- */ /* Loop, creating overviews. */ /* -------------------------------------------------------------------- */ for( iOverview = 0; iOverview < nOverviews; iOverview++ ) { int nOXSize, nOYSize; uint32 nDirOffset; nOXSize = (nXSize + panOverviewList[iOverview] - 1) / panOverviewList[iOverview]; nOYSize = (nYSize + panOverviewList[iOverview] - 1) / panOverviewList[iOverview]; nDirOffset = GTIFFWriteDirectory(hOTIFF, FILETYPE_REDUCEDIMAGE, nOXSize, nOYSize, nBitsPerPixel, nPlanarConfig, nBands, 128, 128, TRUE, nCompression, nPhotometric, nSampleFormat, panRed, panGreen, panBlue, 0, NULL, /* FIXME ? how can we fetch extrasamples from here */ osMetadata ); } if (panRed) { CPLFree(panRed); CPLFree(panGreen); CPLFree(panBlue); panRed = panGreen = panBlue = NULL; } XTIFFClose( hOTIFF ); /* -------------------------------------------------------------------- */ /* Open the overview dataset so that we can get at the overview */ /* bands. */ /* -------------------------------------------------------------------- */ GDALDataset *hODS; hODS = (GDALDataset *) GDALOpen( pszFilename, GA_Update ); if( hODS == NULL ) return CE_Failure; /* -------------------------------------------------------------------- */ /* Loop writing overview data. */ /* -------------------------------------------------------------------- */ if (nCompression != COMPRESSION_NONE && nPlanarConfig == PLANARCONFIG_CONTIG && GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) == FALSE && papoBandList[0]->GetColorTable() == NULL && (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS"))) { /* In the case of pixel interleaved compressed overviews, we want to generate */ /* the overviews for all the bands block by block, and not band after band, */ /* in order to write the block once and not loose space in the TIFF file */ GDALRasterBand ***papapoOverviewBands; papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands); for( iBand = 0; iBand < nBands; iBand++ ) { GDALRasterBand *hDstBand = hODS->GetRasterBand( iBand+1 ); papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews); papapoOverviewBands[iBand][0] = hDstBand; for( int i = 0; i < nOverviews-1; i++ ) { papapoOverviewBands[iBand][i+1] = hDstBand->GetOverview(i); } } GDALRegenerateOverviewsMultiBand(nBands, papoBandList, nOverviews, papapoOverviewBands, pszResampling, pfnProgress, pProgressData ); for( iBand = 0; iBand < nBands; iBand++ ) { CPLFree(papapoOverviewBands[iBand]); } CPLFree(papapoOverviewBands); } else { GDALRasterBand **papoOverviews; papoOverviews = (GDALRasterBand **) CPLCalloc(sizeof(void*),128); for( iBand = 0; iBand < nBands; iBand++ ) { GDALRasterBand *hSrcBand = papoBandList[iBand]; GDALRasterBand *hDstBand; int nDstOverviews; CPLErr eErr; hDstBand = hODS->GetRasterBand( iBand+1 ); papoOverviews[0] = hDstBand; nDstOverviews = hDstBand->GetOverviewCount() + 1; CPLAssert( nDstOverviews < 128 ); nDstOverviews = MIN(128,nDstOverviews); for( int i = 0; i < nDstOverviews-1; i++ ) { papoOverviews[i+1] = hDstBand->GetOverview(i); } void *pScaledProgressData; pScaledProgressData = GDALCreateScaledProgress( iBand / (double) nBands, (iBand+1) / (double) nBands, pfnProgress, pProgressData ); eErr = GDALRegenerateOverviews( (GDALRasterBandH) hSrcBand, nDstOverviews, (GDALRasterBandH *) papoOverviews, pszResampling, GDALScaledProgress, pScaledProgressData); GDALDestroyScaledProgress( pScaledProgressData ); if( eErr != CE_None ) { delete hODS; return eErr; } } CPLFree( papoOverviews ); } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ hODS->FlushCache(); delete hODS; pfnProgress( 1.0, NULL, pProgressData ); return CE_None; }
CPLErr GTIFFBuildOverviews( const char * pszFilename, int nBands, GDALRasterBand **papoBandList, int nOverviews, int * panOverviewList, const char * pszResampling, GDALProgressFunc pfnProgress, void * pProgressData ) { if( nBands == 0 || nOverviews == 0 ) return CE_None; if( !GTiffOneTimeInit() ) return CE_Failure; TIFF *hOTIFF = nullptr; int nBitsPerPixel = 0; int nCompression = COMPRESSION_NONE; int nPhotometric = 0; int nSampleFormat = 0; int nPlanarConfig = 0; int iOverview = 0; int nXSize = 0; int nYSize = 0; /* -------------------------------------------------------------------- */ /* Verify that the list of bands is suitable for emitting in */ /* TIFF file. */ /* -------------------------------------------------------------------- */ for( int iBand = 0; iBand < nBands; iBand++ ) { int nBandBits = 0; int nBandFormat = 0; GDALRasterBand *hBand = papoBandList[iBand]; switch( hBand->GetRasterDataType() ) { case GDT_Byte: nBandBits = 8; nBandFormat = SAMPLEFORMAT_UINT; break; case GDT_UInt16: nBandBits = 16; nBandFormat = SAMPLEFORMAT_UINT; break; case GDT_Int16: nBandBits = 16; nBandFormat = SAMPLEFORMAT_INT; break; case GDT_UInt32: nBandBits = 32; nBandFormat = SAMPLEFORMAT_UINT; break; case GDT_Int32: nBandBits = 32; nBandFormat = SAMPLEFORMAT_INT; break; case GDT_Float32: nBandBits = 32; nBandFormat = SAMPLEFORMAT_IEEEFP; break; case GDT_Float64: nBandBits = 64; nBandFormat = SAMPLEFORMAT_IEEEFP; break; case GDT_CInt16: nBandBits = 32; nBandFormat = SAMPLEFORMAT_COMPLEXINT; break; case GDT_CInt32: nBandBits = 64; nBandFormat = SAMPLEFORMAT_COMPLEXINT; break; case GDT_CFloat32: nBandBits = 64; nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP; break; case GDT_CFloat64: nBandBits = 128; nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP; break; default: CPLAssert( false ); return CE_Failure; } if( hBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) ) { nBandBits = atoi(hBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE")); if( nBandBits == 1 && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2") ) nBandBits = 8; } if( iBand == 0 ) { nBitsPerPixel = nBandBits; nSampleFormat = nBandFormat; nXSize = hBand->GetXSize(); nYSize = hBand->GetYSize(); } else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support a mixture of band" " data types." ); return CE_Failure; } else if( hBand->GetColorTable() != nullptr ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support building" " overviews of multiple colormapped bands." ); return CE_Failure; } else if( hBand->GetXSize() != nXSize || hBand->GetYSize() != nYSize ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support building" " overviews of different sized bands." ); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Use specified compression method. */ /* -------------------------------------------------------------------- */ const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", nullptr ); if( pszCompress != nullptr && pszCompress[0] != '\0' ) { nCompression = GTIFFGetCompressionMethod(pszCompress, "COMPRESS_OVERVIEW"); if( nCompression < 0 ) return CE_Failure; } if( nCompression == COMPRESSION_JPEG && nBitsPerPixel > 8 ) { if( nBitsPerPixel > 16 ) { CPLError( CE_Failure, CPLE_NotSupported, "GTIFFBuildOverviews() doesn't support building" " JPEG compressed overviews of nBitsPerPixel > 16." ); return CE_Failure; } nBitsPerPixel = 12; } /* -------------------------------------------------------------------- */ /* Figure out the planar configuration to use. */ /* -------------------------------------------------------------------- */ if( nBands == 1 ) nPlanarConfig = PLANARCONFIG_CONTIG; else nPlanarConfig = PLANARCONFIG_SEPARATE; bool bSourceIsPixelInterleaved = false; bool bSourceIsJPEG2000 = false; if( nBands > 1 ) { GDALDataset* poSrcDS = papoBandList[0]->GetDataset(); if( poSrcDS ) { const char* pszSrcInterleave = poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE"); if( pszSrcInterleave && EQUAL(pszSrcInterleave, "PIXEL") ) { bSourceIsPixelInterleaved = true; } } const char* pszSrcCompression = papoBandList[0]->GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE"); if( pszSrcCompression ) { bSourceIsJPEG2000 = EQUAL(pszSrcCompression, "JPEG2000"); } if( bSourceIsPixelInterleaved && bSourceIsJPEG2000 ) { nPlanarConfig = PLANARCONFIG_CONTIG; } } const char* pszInterleave = CPLGetConfigOption( "INTERLEAVE_OVERVIEW", nullptr ); if( pszInterleave != nullptr && pszInterleave[0] != '\0' ) { if( EQUAL( pszInterleave, "PIXEL" ) ) nPlanarConfig = PLANARCONFIG_CONTIG; else if( EQUAL( pszInterleave, "BAND" ) ) nPlanarConfig = PLANARCONFIG_SEPARATE; else { CPLError( CE_Failure, CPLE_AppDefined, "INTERLEAVE_OVERVIEW=%s unsupported, " "value must be PIXEL or BAND. ignoring", pszInterleave ); } } /* -------------------------------------------------------------------- */ /* Figure out the photometric interpretation to use. */ /* -------------------------------------------------------------------- */ if( nBands == 3 ) nPhotometric = PHOTOMETRIC_RGB; else if( papoBandList[0]->GetColorTable() != nullptr && !STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2") ) { nPhotometric = PHOTOMETRIC_PALETTE; // Should set the colormap up at this point too! } else if( nBands >= 3 && papoBandList[0]->GetColorInterpretation() == GCI_RedBand && papoBandList[1]->GetColorInterpretation() == GCI_GreenBand && papoBandList[2]->GetColorInterpretation() == GCI_BlueBand ) { nPhotometric = PHOTOMETRIC_RGB; } else nPhotometric = PHOTOMETRIC_MINISBLACK; const char* pszPhotometric = CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", nullptr ); if( pszPhotometric != nullptr && pszPhotometric[0] != '\0' ) { if( EQUAL( pszPhotometric, "MINISBLACK" ) ) nPhotometric = PHOTOMETRIC_MINISBLACK; else if( EQUAL( pszPhotometric, "MINISWHITE" ) ) nPhotometric = PHOTOMETRIC_MINISWHITE; else if( EQUAL( pszPhotometric, "RGB" )) { nPhotometric = PHOTOMETRIC_RGB; } else if( EQUAL( pszPhotometric, "CMYK" )) { nPhotometric = PHOTOMETRIC_SEPARATED; } else if( EQUAL( pszPhotometric, "YCBCR" )) { nPhotometric = PHOTOMETRIC_YCBCR; // Because of subsampling, setting YCBCR without JPEG compression // leads to a crash currently. Would need to make // GTiffRasterBand::IWriteBlock() aware of subsampling so that it // doesn't overrun buffer size returned by libtiff. if( nCompression != COMPRESSION_JPEG ) { CPLError( CE_Failure, CPLE_NotSupported, "Currently, PHOTOMETRIC_OVERVIEW=YCBCR requires " "COMPRESS_OVERVIEW=JPEG" ); return CE_Failure; } if( pszInterleave != nullptr && pszInterleave[0] != '\0' && nPlanarConfig == PLANARCONFIG_SEPARATE ) { CPLError( CE_Failure, CPLE_NotSupported, "PHOTOMETRIC_OVERVIEW=YCBCR requires " "INTERLEAVE_OVERVIEW=PIXEL" ); return CE_Failure; } else { nPlanarConfig = PLANARCONFIG_CONTIG; } // YCBCR strictly requires 3 bands. Not less, not more // Issue an explicit error message as libtiff one is a bit cryptic: // JPEGLib:Bogus input colorspace. if( nBands != 3 ) { CPLError( CE_Failure, CPLE_NotSupported, "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster " "with only 3 bands (RGB)" ); return CE_Failure; } } else if( EQUAL( pszPhotometric, "CIELAB" )) { nPhotometric = PHOTOMETRIC_CIELAB; } else if( EQUAL( pszPhotometric, "ICCLAB" )) { nPhotometric = PHOTOMETRIC_ICCLAB; } else if( EQUAL( pszPhotometric, "ITULAB" )) { nPhotometric = PHOTOMETRIC_ITULAB; } else { CPLError( CE_Warning, CPLE_IllegalArg, "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.", pszPhotometric ); } } /* -------------------------------------------------------------------- */ /* Figure out the predictor value to use. */ /* -------------------------------------------------------------------- */ int nPredictor = PREDICTOR_NONE; if( nCompression == COMPRESSION_LZW || nCompression == COMPRESSION_ADOBE_DEFLATE ) { const char* pszPredictor = CPLGetConfigOption( "PREDICTOR_OVERVIEW", nullptr ); if( pszPredictor != nullptr ) { nPredictor = atoi( pszPredictor ); } } /* -------------------------------------------------------------------- */ /* Create the file, if it does not already exist. */ /* -------------------------------------------------------------------- */ VSIStatBufL sStatBuf; VSILFILE* fpL = nullptr; if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 ) { /* -------------------------------------------------------------------- */ /* Compute the uncompressed size. */ /* -------------------------------------------------------------------- */ double dfUncompressedOverviewSize = 0; int nDataTypeSize = GDALGetDataTypeSizeBytes(papoBandList[0]->GetRasterDataType()); for( iOverview = 0; iOverview < nOverviews; iOverview++ ) { const int nOXSize = (nXSize + panOverviewList[iOverview] - 1) / panOverviewList[iOverview]; const int nOYSize = (nYSize + panOverviewList[iOverview] - 1) / panOverviewList[iOverview]; dfUncompressedOverviewSize += nOXSize * static_cast<double>(nOYSize) * nBands * nDataTypeSize; } if( nCompression == COMPRESSION_NONE && dfUncompressedOverviewSize > 4200000000.0 ) { #ifndef BIGTIFF_SUPPORT CPLError( CE_Failure, CPLE_NotSupported, "The overview file would be larger than 4GB, " "but this is the largest size a TIFF can be, " "and BigTIFF is unavailable. " "Creation failed." ); return CE_Failure; #endif } /* -------------------------------------------------------------------- */ /* Should the file be created as a bigtiff file? */ /* -------------------------------------------------------------------- */ const char *pszBIGTIFF = CPLGetConfigOption( "BIGTIFF_OVERVIEW", nullptr ); if( pszBIGTIFF == nullptr ) pszBIGTIFF = "IF_SAFER"; bool bCreateBigTIFF = false; if( EQUAL(pszBIGTIFF,"IF_NEEDED") ) { if( nCompression == COMPRESSION_NONE && dfUncompressedOverviewSize > 4200000000.0 ) bCreateBigTIFF = true; } else if( EQUAL(pszBIGTIFF,"IF_SAFER") ) { // Look at the size of the base image and suppose that // the added overview levels won't be more than 1/2 of // the size of the base image. The theory says 1/3 of the // base image size if the overview levels are 2, 4, 8, 16. // Thus take 1/2 as the security margin for 1/3. const double dfUncompressedImageSize = nXSize * static_cast<double>(nYSize) * nBands * nDataTypeSize; if( dfUncompressedImageSize * 0.5 > 4200000000.0 ) bCreateBigTIFF = true; } else { bCreateBigTIFF = CPLTestBool( pszBIGTIFF ); if( !bCreateBigTIFF && nCompression == COMPRESSION_NONE && dfUncompressedOverviewSize > 4200000000.0 ) { CPLError( CE_Failure, CPLE_NotSupported, "The overview file will be larger than 4GB, " "so BigTIFF is necessary. " "Creation failed."); return CE_Failure; } } #ifndef BIGTIFF_SUPPORT if( bCreateBigTIFF ) { CPLError( CE_Warning, CPLE_NotSupported, "BigTIFF requested, but GDAL built without BigTIFF " "enabled libtiff, request ignored." ); bCreateBigTIFF = false; } #endif if( bCreateBigTIFF ) CPLDebug( "GTiff", "File being created as a BigTIFF." ); fpL = VSIFOpenL( pszFilename, "w+" ); if( fpL == nullptr ) hOTIFF = nullptr; else hOTIFF = VSI_TIFFOpen( pszFilename, bCreateBigTIFF ? "w+8" : "w+", fpL ); if( hOTIFF == nullptr ) { if( CPLGetLastErrorNo() == 0 ) CPLError( CE_Failure, CPLE_OpenFailed, "Attempt to create new tiff file `%s' " "failed in VSI_TIFFOpen().", pszFilename ); if( fpL != nullptr ) CPL_IGNORE_RET_VAL(VSIFCloseL(fpL)); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Otherwise just open it for update access. */ /* -------------------------------------------------------------------- */ else { fpL = VSIFOpenL( pszFilename, "r+" ); if( fpL == nullptr ) hOTIFF = nullptr; else hOTIFF = VSI_TIFFOpen( pszFilename, "r+", fpL ); if( hOTIFF == nullptr ) { if( CPLGetLastErrorNo() == 0 ) CPLError( CE_Failure, CPLE_OpenFailed, "Attempt to create new tiff file `%s' " "failed in VSI_TIFFOpen().", pszFilename ); if( fpL != nullptr ) CPL_IGNORE_RET_VAL(VSIFCloseL(fpL)); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Do we have a palette? If so, create a TIFF compatible version. */ /* -------------------------------------------------------------------- */ unsigned short *panRed = nullptr; unsigned short *panGreen = nullptr; unsigned short *panBlue = nullptr; if( nPhotometric == PHOTOMETRIC_PALETTE ) { GDALColorTable *poCT = papoBandList[0]->GetColorTable(); int nColorCount = 65536; if( nBitsPerPixel <= 8 ) nColorCount = 256; panRed = static_cast<unsigned short *>( CPLCalloc(nColorCount, sizeof(unsigned short)) ); panGreen = static_cast<unsigned short *>( CPLCalloc(nColorCount, sizeof(unsigned short)) ); panBlue = static_cast<unsigned short *>( CPLCalloc(nColorCount, sizeof(unsigned short)) ); for( int iColor = 0; iColor < nColorCount; iColor++ ) { GDALColorEntry sRGB = { 0, 0, 0, 0 }; if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) ) { // TODO(schwehr): Check for underflow. // Going from signed short to unsigned short. panRed[iColor] = static_cast<unsigned short>(257 * sRGB.c1); panGreen[iColor] = static_cast<unsigned short>(257 * sRGB.c2); panBlue[iColor] = static_cast<unsigned short>(257 * sRGB.c3); } } } /* -------------------------------------------------------------------- */ /* Do we need some metadata for the overviews? */ /* -------------------------------------------------------------------- */ CPLString osMetadata; GDALDataset *poBaseDS = papoBandList[0]->GetDataset(); GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata ); /* -------------------------------------------------------------------- */ /* Loop, creating overviews. */ /* -------------------------------------------------------------------- */ int nOvrBlockXSize = 0; int nOvrBlockYSize = 0; GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize); CPLString osNoData; // don't move this in inner scope const char* pszNoData = nullptr; int bNoDataSet = FALSE; const double dfNoDataValue = papoBandList[0]->GetNoDataValue(&bNoDataSet); if( bNoDataSet ) { osNoData = GTiffFormatGDALNoDataTagValue(dfNoDataValue); pszNoData = osNoData.c_str(); } std::vector<uint16> anExtraSamples; for( int i = GTIFFGetMaxColorChannels(nPhotometric)+1; i <= nBands; i++ ) { if( papoBandList[i-1]->GetColorInterpretation() == GCI_AlphaBand ) { anExtraSamples.push_back( GTiffGetAlphaValue(CPLGetConfigOption("GTIFF_ALPHA", nullptr), DEFAULT_ALPHA_TYPE)); } else { anExtraSamples.push_back(EXTRASAMPLE_UNSPECIFIED); } } for( iOverview = 0; iOverview < nOverviews; iOverview++ ) { const int nOXSize = (nXSize + panOverviewList[iOverview] - 1) / panOverviewList[iOverview]; const int nOYSize = (nYSize + panOverviewList[iOverview] - 1) / panOverviewList[iOverview]; GTIFFWriteDirectory( hOTIFF, FILETYPE_REDUCEDIMAGE, nOXSize, nOYSize, nBitsPerPixel, nPlanarConfig, nBands, nOvrBlockXSize, nOvrBlockYSize, TRUE, nCompression, nPhotometric, nSampleFormat, nPredictor, panRed, panGreen, panBlue, static_cast<int>(anExtraSamples.size()), anExtraSamples.empty() ? nullptr : anExtraSamples.data(), osMetadata, CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", nullptr ), CPLGetConfigOption( "JPEG_TABLESMODE_OVERVIEW", nullptr ), pszNoData, nullptr ); } if( panRed ) { CPLFree(panRed); CPLFree(panGreen); CPLFree(panBlue); panRed = nullptr; panGreen = nullptr; panBlue = nullptr; } XTIFFClose( hOTIFF ); if( VSIFCloseL(fpL) != 0 ) return CE_Failure; fpL = nullptr; /* -------------------------------------------------------------------- */ /* Open the overview dataset so that we can get at the overview */ /* bands. */ /* -------------------------------------------------------------------- */ GDALDataset *hODS = GDALDataset::Open( pszFilename, GDAL_OF_RASTER | GDAL_OF_UPDATE ); if( hODS == nullptr ) return CE_Failure; /* -------------------------------------------------------------------- */ /* Do we need to set the jpeg quality? */ /* -------------------------------------------------------------------- */ TIFF *hTIFF = static_cast<TIFF *>( hODS->GetInternalHandle(nullptr) ); if( nCompression == COMPRESSION_JPEG && CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", nullptr ) != nullptr ) { const int nJpegQuality = atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75")); TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality ); GTIFFSetJpegQuality(GDALDataset::ToHandle(hODS), nJpegQuality); } if( nCompression == COMPRESSION_JPEG && CPLGetConfigOption( "JPEG_TABLESMODE_OVERVIEW", nullptr ) != nullptr ) { const int nJpegTablesMode = atoi(CPLGetConfigOption("JPEG_TABLESMODE_OVERVIEW", CPLSPrintf("%d", knGTIFFJpegTablesModeDefault))); TIFFSetField( hTIFF, TIFFTAG_JPEGTABLESMODE, nJpegTablesMode ); GTIFFSetJpegTablesMode(GDALDataset::ToHandle(hODS), nJpegTablesMode); } /* -------------------------------------------------------------------- */ /* Loop writing overview data. */ /* -------------------------------------------------------------------- */ int *panOverviewListSorted = static_cast<int*>(CPLMalloc(sizeof(int) * nOverviews)); memcpy( panOverviewListSorted, panOverviewList, sizeof(int) * nOverviews); std::sort(panOverviewListSorted, panOverviewListSorted + nOverviews); GTIFFSetInExternalOvr(true); CPLErr eErr = CE_None; if( ((bSourceIsPixelInterleaved && bSourceIsJPEG2000) || (nCompression != COMPRESSION_NONE)) && nPlanarConfig == PLANARCONFIG_CONTIG && !GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) && papoBandList[0]->GetColorTable() == nullptr && (STARTS_WITH_CI(pszResampling, "NEAR") || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS") || EQUAL(pszResampling, "CUBIC") || EQUAL(pszResampling, "CUBICSPLINE") || EQUAL(pszResampling, "LANCZOS") || EQUAL(pszResampling, "BILINEAR")) ) { // In the case of pixel interleaved compressed overviews, we want to // generate the overviews for all the bands block by block, and not // band after band, in order to write the block once and not loose // space in the TIFF file. GDALRasterBand ***papapoOverviewBands = static_cast<GDALRasterBand ***>( CPLCalloc(sizeof(void *), nBands) ); for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ ) { GDALRasterBand *poSrcBand = papoBandList[iBand]; GDALRasterBand *poDstBand = hODS->GetRasterBand( iBand + 1 ); papapoOverviewBands[iBand] = static_cast<GDALRasterBand **>( CPLCalloc(sizeof(void *), nOverviews) ); int bHasNoData = FALSE; const double noDataValue = poSrcBand->GetNoDataValue(&bHasNoData); if( bHasNoData ) poDstBand->SetNoDataValue(noDataValue); for( int i = 0; i < nOverviews && eErr == CE_None; i++ ) { for( int j = -1; j < poDstBand->GetOverviewCount() && eErr == CE_None; j++ ) { GDALRasterBand * poOverview = (j < 0 ) ? poDstBand : poDstBand->GetOverview( j ); if( poOverview == nullptr ) { eErr = CE_Failure; continue; } const int nOvFactor = GDALComputeOvFactor(poOverview->GetXSize(), poSrcBand->GetXSize(), poOverview->GetYSize(), poSrcBand->GetYSize()); if( nOvFactor == panOverviewListSorted[i] || nOvFactor == GDALOvLevelAdjust2( panOverviewListSorted[i], poSrcBand->GetXSize(), poSrcBand->GetYSize() ) ) { papapoOverviewBands[iBand][i] = poOverview; if( bHasNoData ) poOverview->SetNoDataValue(noDataValue); break; } } CPLAssert( papapoOverviewBands[iBand][i] != nullptr ); } } if( eErr == CE_None ) eErr = GDALRegenerateOverviewsMultiBand( nBands, papoBandList, nOverviews, papapoOverviewBands, pszResampling, pfnProgress, pProgressData ); for( int iBand = 0; iBand < nBands; iBand++ ) { CPLFree(papapoOverviewBands[iBand]); } CPLFree(papapoOverviewBands); } else { GDALRasterBand **papoOverviews = static_cast<GDALRasterBand **>( CPLCalloc( sizeof(void*), knMaxOverviews ) ); for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ ) { GDALRasterBand *hSrcBand = papoBandList[iBand]; GDALRasterBand *hDstBand = hODS->GetRasterBand( iBand + 1 ); int bHasNoData = FALSE; const double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData); if( bHasNoData ) hDstBand->SetNoDataValue(noDataValue); // FIXME: this logic regenerates all overview bands, not only the // ones requested. papoOverviews[0] = hDstBand; int nDstOverviews = hDstBand->GetOverviewCount() + 1; CPLAssert( nDstOverviews < knMaxOverviews ); nDstOverviews = std::min(knMaxOverviews, nDstOverviews); // TODO(schwehr): Convert to starting with i = 1 and remove +1. for( int i = 0; i < nDstOverviews - 1 && eErr == CE_None; i++ ) { papoOverviews[i+1] = hDstBand->GetOverview(i); if( papoOverviews[i+1] == nullptr ) { eErr = CE_Failure; } else { if( bHasNoData ) papoOverviews[i+1]->SetNoDataValue(noDataValue); } } void *pScaledProgressData = GDALCreateScaledProgress( iBand / static_cast<double>( nBands ), (iBand + 1) / static_cast<double>( nBands ), pfnProgress, pProgressData ); if( eErr == CE_None ) eErr = GDALRegenerateOverviews( hSrcBand, nDstOverviews, reinterpret_cast<GDALRasterBandH *>( papoOverviews ), pszResampling, GDALScaledProgress, pScaledProgressData ); GDALDestroyScaledProgress( pScaledProgressData ); } CPLFree( papoOverviews ); } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ if( eErr == CE_None ) hODS->FlushCache(); delete hODS; GTIFFSetInExternalOvr(false); CPLFree(panOverviewListSorted); pfnProgress( 1.0, nullptr, pProgressData ); return eErr; }