I have a high-resolution image that I want to use as a tiled map overlay using Google Maps API v3.
I used MapTiler to break it into appropriate tiles at the desired zoom levels. That worked well except that there was a thin grey-black border on the tiles that were the edges of the original image.
Following the suggestion of the second post at http://groups.google.com/group/maptiler/browse_thread/thread/70a4c5610538332a/42fefedb4a0bc6d2, I tried using gdal2tiles.py instead, passing it the -r antialias
option but the thin border persisted.
If I open the actual generated image tiles, the thin border does indeed appear to be part of the generated tile, but it is not part of the original image.
I suspect what is happening is that the portions of the Google Maps tile for which I have no data are being treated as black pixels when the program generates the tile image files and the result is the grey border.
Here's what I believe to be the relevant code from gdal2tiles.py:
# Scaling by PIL (Python Imaging Library) - improved Lanczos
array = numpy.zeros((querysize, querysize, tilebands), numpy.uint8)
for i in range(tilebands):
array[:,:,i] = gdalarray.BandReadAsArray(dsquery.GetRasterBand(i+1), 0, 0, querysize, querysize)
im = Image.fromarray(array, 'RGBA') # Always four bands
im1 = im.resize((tilesize,tilesize), Image.ANTIALIAS)
if os.path.exists(tilefilename):
im0 = Image.open(tilefilename)
im1 = Image.composite(im1, im0, im1)
im1.save(tilefilename,self.tiledriver)
Any idea how to make it so that border isn't there, short of opening the relevant generated tile image files in an image editor and setting the relevant pixels to transparent?
I suspect the answer involves finding some way to represent transparent pixels such that antialiasing ignores them for sampling purposes.
Update: It might not win any awards for elegance or performance, but I'm most of the way there, I think. Of course, the final few yards are also the toughest.
If I change ANTIALIAS to BICUBIC and then process the alpha channel such that any semi-transparent pixels are rendered completely transparent, I get rid of most of the borders on most of the tiles. Some light-colored borderlines persist, however. I'm not sure what to do about that. It's also worth noting that I guess this strategy might not work so well if there were transparent or semi-transparent pixels in the image that were not outside the edges of the actual image area.
Here's the code with these modifications:
# Scaling by PIL (Python Imaging Library) - improved Lanczos
array = numpy.zeros((querysize, querysize, tilebands), numpy.uint8)
for i in range(tilebands):
array[:,:,i] = gdalarray.BandReadAsArray(dsquery.GetRasterBand(i+1), 0, 0, querysize, querysize)
im = Image.fromarray(array, 'RGBA') # Always four bands
im1 = im.resize((tilesize,tilesize), Image.BICUBIC)
if os.path.exists(tilefilename):
im0 = Image.open(tilefilename)
im1 = Image.composite(im1, im0, im1)
im1AsArray = numpy.array(im1)
alpha = im1AsArray[:,:,3]
semiTransparentIndices = alpha < 255
alpha[semiTransparentIndices] = 0
im1AsArray[:,:,3] = alpha
im1 = Image.fromarray(im1AsArray, 'RGBA')
im1.save(tilefilename,self.tiledriver)
The answer is to change the resampling to BILINEAR (and not BICUBIC, which is what I tried in the Update posted to the question), and then make sure to change any semitransparent pixels to completely transparent pixels.
As I said in the Update, the code modifications I made here might not win any awards for elegance or performance, but it works. Here's what the original posted snippet from gdal2tiles.py needs to be changed to:
# Scaling by PIL (Python Imaging Library) - improved Lanczos
array = numpy.zeros((querysize, querysize, tilebands), numpy.uint8)
for i in range(tilebands):
array[:,:,i] = gdalarray.BandReadAsArray(dsquery.GetRasterBand(i+1), 0, 0, querysize, querysize)
im = Image.fromarray(array, 'RGBA') # Always four bands
im1 = im.resize((tilesize,tilesize), Image.BILINEAR)
if os.path.exists(tilefilename):
im0 = Image.open(tilefilename)
im1 = Image.composite(im1, im0, im1)
im1AsArray = numpy.array(im1)
alpha = im1AsArray[:,:,3]
semiTransparentIndices = alpha < 255
alpha[semiTransparentIndices] = 0
im1AsArray[:,:,3] = alpha
im1 = Image.fromarray(im1AsArray, 'RGBA')
im1.save(tilefilename,self.tiledriver)
Note also that the above code will only execute if you pass gdal2tiles.py the -r antialias
flag. Yes, that's right: We changed the -r antialias
code so that it doesn't antialias. But if you're having the problem I was having and just want a solution, there it is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With