[gdal-dev] Boundary Artifact with ChunkAndWarpImage

Even Rouault even.rouault at spatialys.com
Fri Apr 17 12:42:28 PDT 2015


Le vendredi 17 avril 2015 20:00:36, Michael Aschenbeck a écrit :
> Hey guys,
> 
> I realize this is borderline impossible to debug with what I've given you.
> So I managed to reproduce it with the C++ code at the bottom of the email.
> The image i used is:
> https://www.dropbox.com/s/i9fxstyuf8eqe8t/testsingleband.tif?dl=0
> 
> Something that is a little weird is that I cropped this image so recreating
> the problem is less clunky. When I did that, the artifacts were not
> present!  So, that's the reason i'm including a 65mb image.  (Perhaps Matt
> was on to something when he thought about gdal chunking bigger images.)
>  Using this code and this image, you should see the first nonzero row is
> too dark, and the second row is too bright.
> 
> Let me know if anyone can recreate the issue and/or has any further ideas.

I can now reproduce and finally found the reason. When you do :

psWarpOptions->padfSrcNoDataReal = (double
*)CPLMalloc(psWarpOptions->nBandCount*sizeof(double));

nBandCount has not yet been set, so it is at its default value 0, and there's 
no nodata declared...

If you do the following instead, it will work:

psWarpOptions->nBandCount = GDALGetRasterCount(poDataset);
psWarpOptions->padfSrcNoDataReal = (double
*)CPLCalloc(psWarpOptions->nBandCount, sizeof(double));
psWarpOptions->padfSrcNoDataImag = (double
*)CPLCalloc(psWarpOptions->nBandCount, sizeof(double));

(note that since you did CreateCopy() before, the original lines will remain 
above the area touched by your warped imagery. So you might want to erase 
everything with ((GDALDataset*)hDstDS)->GetRasterBand(1)->Fill(0); before)

> 
> Thanks again,
> Mike
> 
> 
> 
> int pushUpToRight(void *hTransforArg, int bDstToSrc, int nPointCount,
> double *x, double *y, double *z, int *panSuccess)
> {
> //First transform to georeferenced units:
> GDALGenImgProjTransform(hTransforArg, 0, nPointCount, x, y, z, panSuccess);
> //Now we are in georeferenced units
> 
>         //push up and to the right
> for (int i = 0; i<nPointCount; i++)
> {
> if (panSuccess[i] != 0)
> {
> x[i] = x[i] + .01;
> y[i] = y[i] + .651;
> }
> }
>  double *geo = new double[6]; //hardcoded for this example
> geo[0] = 451581.6; geo[1] = 0.4; geo[2] = 0.0; geo[3] =
> 2420520.8000000003; geo[4]
> = 0.0; geo[5] = -0.4;
> 
> //Now convert to pixels
> for (int i = 0; i < nPointCount; i++)
> {
> x[i] = convertXToPixel(x[i], geo);
> y[i] = convertYToPixel(y[i], geo);
> }
> 
> return 1;
> }
> double convertXToPixel(double xGeo, double *adfGeoTransform) { return
> ((xGeo - adfGeoTransform[0]) / adfGeoTransform[1]);}
> double convertYToPixel(double yGeo, double *adfGeoTransform) { return
> ((yGeo - adfGeoTransform[3]) / adfGeoTransform[5]);}
> 
> int main()
> {
> GDALDataset *poDataset;
> GDALDriver *hDriver;
> GDALDataset *hDstDS;
> 
> GDALAllRegister();
> 
> // Open the source file
> poDataset = (GDALDataset *)GDALOpen("E:/Test/TestSingleBand.tif",
> GA_ReadOnly);
> CPLAssert(poDataset != NULL);
> 
> // Get output driver (GeoTIFF format)
> hDriver = (GDALDriver*)GDALGetDriverByName("GTiff");
> CPLAssert(hDriver != NULL);
> 
> // Create the output file.
> hDstDS = hDriver->CreateCopy("E:/Test/out.tif",
> poDataset,FALSE,NULL,NULL,NULL);
> CPLAssert(hDstDS != NULL);
> 
> //Create the transformer
> void *hTransformArgForward;
> hTransformArgForward = GDALCreateGenImgProjTransformer2(poDataset, NULL,
> NULL);
> 
>         //Create the warper and set various variables
> GDALWarpOptions *psWarpOptions = GDALCreateWarpOptions();
> 
> psWarpOptions->padfSrcNoDataReal = (double
> *)CPLMalloc(psWarpOptions->nBandCount*sizeof(double));
> for (int ii = 0; ii < psWarpOptions->nBandCount; ii++)
> {
> psWarpOptions->padfSrcNoDataReal[ii] = 0;
> }
> psWarpOptions->hSrcDS = poDataset;
> psWarpOptions->hDstDS = hDstDS;
> psWarpOptions->nBandCount = GDALGetRasterCount(poDataset);
> psWarpOptions->pTransformerArg = hTransformArgForward;
> psWarpOptions->panSrcBands = (int *)CPLMalloc(sizeof(int));
> psWarpOptions->panSrcBands[0] = 1;
> psWarpOptions->panDstBands = (int *)CPLMalloc(sizeof(int));
> psWarpOptions->panDstBands[0] = 1;
> psWarpOptions->eResampleAlg = GRA_Cubic;
> psWarpOptions->pfnProgress = GDALTermProgress;
> 
> // Establish my transformer.
>     GDALTransformerFunc myTransformer = &pushUpToRight;
> psWarpOptions->pfnTransformer = myTransformer;
> 
> // Initialize and execute the warp operation.
> GDALWarpOperation oOperation;
> oOperation.Initialize(psWarpOptions);
> oOperation.ChunkAndWarpImage(0, 0,
> GDALGetRasterXSize(hDstDS),
> GDALGetRasterYSize(hDstDS));
> 
>         //clean
> GDALDestroyWarpOptions(psWarpOptions);
> GDALClose(hDstDS);
> GDALClose(poDataset);
> 
> return 0;
> }
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> On Thu, Apr 16, 2015 at 1:10 PM, Michael Aschenbeck <
> 
> m.g.aschenbeck at gmail.com> wrote:
> > Some good ideas, thanks for the suggestions.
> > 
> > I added padfDstNoDataReal, as well as the imaginary values.  I also set
> > INIT_DEST to NODATA, although from what I read that was more of an option
> > that affected speed.  Unfortunately my output was identical to the
> > previous run and the artifacts remain present.
> > 
> > On Thu, Apr 16, 2015 at 11:59 AM, Matt Hanson <matt.a.hanson at gmail.com>
> > 
> > wrote:
> >> Mike,
> >> Are you setting padfDstNoDataReal as well?     Because GDAL performs the
> >> warp in chunks I'm wondering if previously written data, that should be
> >> NoData, is not recognized as such with later chunks.   However, I'm
> >> still not clear on the exact details of how that works internally, Even
> >> would have a better idea if this even makes sense.
> >> 
> >> The code I'm using to set WarpOptions for doing warping on multiple
> >> input images to a single outout looks like the below.   Also, are you
> >> setting INIT_DEST option to "NODATA" (it's one of the key-value options
> >> that are assigned to psWarpOptions->papszWarpOptions).
> >> 
> >> Hope this helps!
> >> 
> >> GDALWarpOptions *psWarpOptions = GDALCreateWarpOptions();
> >> psWarpOptions->hDstDS = imgout.GetGDALDataset();
> >> psWarpOptions->nBandCount = imgout.NumBands();
> >> psWarpOptions->panSrcBands = (int *) CPLMalloc(sizeof(int) *
> >> psWarpOptions->nBandCount ); psWarpOptions->panDstBands = (int *)
> >> CPLMalloc(sizeof(int) * psWarpOptions->nBandCount );
> >> psWarpOptions->padfSrcNoDataReal = (double *) CPLMalloc(sizeof(double) *
> >> psWarpOptions->nBandCount ); psWarpOptions->padfSrcNoDataImag = (double
> >> *) CPLMalloc(sizeof(double) * psWarpOptions->nBandCount );
> >> psWarpOptions->padfDstNoDataReal = (double *) CPLMalloc(sizeof(double) *
> >> psWarpOptions->nBandCount ); psWarpOptions->padfDstNoDataImag = (double
> >> *) CPLMalloc(sizeof(double) * psWarpOptions->nBandCount ); for (unsigned
> >> int b=0;b<imgout.NumBands();b++) { psWarpOptions->panSrcBands[b] = b+1;
> >> psWarpOptions->panDstBands[b] = b+1; psWarpOptions->padfSrcNoDataReal[b]
> >> = images[0][b].NoDataValue(); psWarpOptions->padfDstNoDataReal[b] =
> >> imgout[b].NoDataValue(); psWarpOptions->padfSrcNoDataImag[b] = 0.0;
> >> psWarpOptions->padfDstNoDataImag[b] = 0.0; }
> >> 
> >> On Thu, Apr 16, 2015 at 1:42 PM, Michael Aschenbeck <
> >> 
> >> m.g.aschenbeck at gmail.com> wrote:
> >>> Thanks for your reply.
> >>> 
> >>> I'm using gdal 1.10.1.  I'm using cubic resampling, but i have noticed
> >>> the dark line artifact with bilinear as well.  I unfortunately do not
> >>> reproduce the problem with a basic gdalwarp with cubic resampling.
> >>> 
> >>> I have written this code to do some registration. It's hard to tell in
> >>> the example, but my transformation actually pushed pixels up a bit. The
> >>> transformation I use handles interior pixels nicely and extends beyond
> >>> the image, so there is nothing 'weird' going on with that near the
> >>> boundary that I can think of.
> >>> 
> >>> I was hoping there is a warp option i have not yet thought of.
> >>> 
> >>> Thanks again,
> >>> Mike
> >>> 
> >>> 
> >>> 
> >>> On Thu, Apr 16, 2015 at 11:10 AM, Even Rouault <
> >>> 
> >>> even.rouault at spatialys.com> wrote:
> >>>> Le jeudi 16 avril 2015 19:01:57, Michael Aschenbeck a écrit :
> >>>> > Hello,
> >>>> > 
> >>>> > I'm using ChunkAndWarpMulti to warp an image.  The warping is
> >>>> > working nicely, however, at the boundary I seem to be getting some
> >>>> > artifacts.
> >>>> > 
> >>>> > The first artifact i see is a DARK boundary of pixels in some
> >>>> 
> >>>> location.  My
> >>>> 
> >>>> > guess is that the interpolator is interpolating with blackfill
> >>>> 
> >>>> (intensity
> >>>> 
> >>>> > zero pixels).  Note that I am using the following setup:
> >>>> > psWarpOptions->padfSrcNoDataReal = (double *)
> >>>> > CPLMalloc(psWarpOptions->nBandCount*sizeof(double));
> >>>> > for (int ii = 0; ii < psWarpOptions->nBandCount; ii++)
> >>>> > {
> >>>> > psWarpOptions->padfSrcNoDataReal[ii] = 0;
> >>>> > }
> >>>> > which i thought was supposed to treat zeros as nodata.  It doesn't
> >>>> 
> >>>> seem to
> >>>> 
> >>>> > be doing what I think it should.
> >>>> > 
> >>>> > In some cases, I am also noticing a BRIGHT band strip of pixels
> >>>> 
> >>>> adjacent to
> >>>> 
> >>>> > the dark boundary pixels.  I don't have any thoughts on where this
> >>>> 
> >>>> artifact
> >>>> 
> >>>> > is coming from.
> >>>> > 
> >>>> > Below you can find links to an example.  The orange you see is just
> >>>> 
> >>>> the
> >>>> 
> >>>> > background color of my viewer.  Zero pixels are set to transparent
> >>>> > so
> >>>> 
> >>>> you
> >>>> 
> >>>> > can see the dark boundary artifact.  (Note that all of the orange
> >>>> 
> >>>> region is
> >>>> 
> >>>> > covered with zero-intensity pixels, so we haven't reached the
> >>>> 
> >>>> boundary of
> >>>> 
> >>>> > the file, just the boundary of the non-zero pixels.)  Sorry if
> >>>> > that's confusing.
> >>>> 
> >>>> > The before image:
> >>>> https://www.dropbox.com/s/3kmyi8wu0qybsq9/before.JPG?dl=0
> >>>> 
> >>>> > The after image with the artifacts:
> >>>> > https://www.dropbox.com/s/fo0m8q95b26s61m/after.JPG?dl=0
> >>>> 
> >>>> Mike,
> >>>> 
> >>>> Which gdal version ? Which resampling method ?
> >>>> Do you reproduce with gdalwarp ?
> >>>> If so, providing input file + full gdalwarp command line would help.
> >>>> 
> >>>> Even
> >>>> 
> >>>> --
> >>>> Spatialys - Geospatial professional services
> >>>> http://www.spatialys.com
> >>> 
> >>> _______________________________________________
> >>> gdal-dev mailing list
> >>> gdal-dev at lists.osgeo.org
> >>> http://lists.osgeo.org/mailman/listinfo/gdal-dev

-- 
Spatialys - Geospatial professional services
http://www.spatialys.com


More information about the gdal-dev mailing list