使用 Python 图像库抗锯齿时,通过透明消除边缘的细边框

发布于 2024-11-06 18:03:01 字数 2716 浏览 6 评论 0原文

我有一张高分辨率图像,想使用 Google Maps API v3 将其用作平铺地图叠加层。

我使用 MapTiler 将其分解为所需缩放级别的适当图块。效果很好,只是在作为原始图像边缘的图块上有一条细细的灰黑色边框。

遵循 http://groups.google.com 上的第二篇文章的建议/group/maptiler/browse_thread/thread/70a4c5610538332a/42fefedb4a0bc6d2,我尝试使用 gdal2tiles.py 代替,向其传递 -r antialias 选项,但细边框仍然存在。

如果我打开实际生成的图像图块,细边框确实看起来是生成图块的一部分,但它不是原始图像的一部分。

我怀疑正在发生的事情是,当程序生成图块图像文件时,我没有数据的 Google 地图图块部分被视为黑色像素,结果是灰色边框。

以下是我认为来自 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)

知道如何制作它以使边框不存在,而不是在图像编辑器中打开相关生成的图块图像文件并将相关像素设置为透明吗?

我怀疑答案涉及找到某种方法来表示透明像素,以便抗锯齿功能在采样时忽略它们。

更新:它可能不会赢得任何优雅或性能奖项,但我认为我已经做到了这一点。当然,最后几码也是最艰难的。

如果我将 ANTIALIAS 更改为 BICUBIC,然后处理 alpha 通道,使任何半透明像素呈现完全透明,我就消除了大多数图块上的大部分边框。然而,一些浅色边界仍然存在。我不知道该怎么办。还值得注意的是,我猜想如果图像中存在不在实际图像区域边缘之外的透明或半透明像素,则此策略可能不会那么有效。

以下是经过这些修改的代码:

                # 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)

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

戏舞 2024-11-13 18:03:01

答案是将重采样更改为 BILINEAR(而不是 BICUBIC,这是我在发布到问题的更新中尝试的),然后确保将任何半透明像素更改为完全透明像素。

正如我在更新中所说,我在这里所做的代码修改可能不会赢得任何优雅或性能奖项,但它确实有效。以下是 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.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)

另请注意,仅当您向 gdal2tiles.py 传递 -r antialias 标志时,上述代码才会执行​​。是的,没错:我们更改了 -r antialias 代码,使其不进行抗锯齿。但如果您遇到了我所遇到的问题并且只是想要一个解决方案,那就是。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文