如何为非地理来源的传单制作平铺的图像金字塔



假设我有一个非地理图像,而不是一个普通的地图。举个例子,比如x光、MRI扫描或显微镜图像,我想使用传单,这样我就可以放大、缩小并在一些预定的点上放置一些标记。

我读过非地理地图的例子,但这个例子演示了使用一个单独的图像而不是平铺。我更喜欢瓷砖,因为我的图像会比较大。有没有其他东西适合我上面描述的那种箱子?我正在研究光栅门,但我还没有明确这是否适用于任何光栅文件。这只适用于普通地图。

以下是我如何从PDF、高分辨率图像或非滑动地图等来源创建滑动地图的经验。无论如何,我想写一篇关于这方面的文章,所以让这个答案是尚未写的文章的草图。

举个例子,这里有一张带有矢量图形的欧洲内陆水道PDF地图,还有一张很滑的地图

基本上,最合理的方法是制作一个标准的瓷砖集,并让传单展示它。也就是说,为每个缩放级别制作256x256大小的瓷砖
您不希望将巨大的图像作为图层,因为这对浏览器来说太重了。您也不希望在浏览器中调整大小,这将导致质量下降。

幸运的是,使用ImageMagick创建平铺非常容易。我就是这样做的。

决定您想要的缩放级别

首先,决定需要多少缩放级别。这取决于地图,根据我的经验,你最多需要5-7个缩放级别。让我们以5个缩放级别为例。您生产的级别越多,对硬件的要求就越高。下面的方法可能不适合7-8倍以上的变焦级别。

渲染或调整源图像的大小

接下来,针对每个缩放级别渲染图像或调整图像大小。你必须生成一个尺寸等于的图像

  • 0级256像素
  • 1级512像素
  • 级别2上的1024像素
  • 3级2048像素
  • 4级4096像素
  • 等等

注意:这一步的结果是巨大的图像。级别5大约为10 MB,级别6大约为20 MB,级别7大约为40 MB。请小心尝试在"正常"工具中打开这些图像。

调整普通高分辨率图像的大小

如果源是高分辨率图像,只需将convert -resizex*256**256*x:一起使用

convert imagessource.jpg -resize   x256 images.jpg
convert imagessource.jpg -resize   x512 images1.jpg
convert imagessource.jpg -resize  x1024 images2.jpg
convert imagessource.jpg -resize  x2048 images3.jpg
convert imagessource.jpg -resize  x4096 images4.jpg
convert imagessource.jpg -resize  x8192 images5.jpg

如果您有多个不同缩放级别的缩放图像(我想MRI扫描也是如此),请选择最接近的缩放源图像。

使用已平铺的图像

在某些情况下,源图像已经在瓦片中剪切。这是典型的"老"地图客户端,你想滑。这是一个例子,瓷砖被称为vk-X-Y.jpg,并以一些重叠的方式进行切割。在这种情况下,您首先必须裁剪图像:

magick datavk-0-0.jpg  -crop 522x373+0x0 imagest-0-0.jpg
magick datavk-1-0.jpg  -crop 522x373+0x0 imagest-1-0.jpg
magick datavk-2-0.jpg  -crop 522x373+0x0 imagest-2-0.jpg
magick datavk-3-0.jpg  -crop 522x373+0x0 imagest-3-0.jpg
magick datavk-4-0.jpg  -crop 522x373+0x0 imagest-4-0.jpg
magick datavk-5-0.jpg  -crop 650x373+0x0 imagest-5-0.jpg
...

要计算裁剪参数,请将垂直和水平相邻瓷砖加载到图形编辑器中,尝试匹配它们并检查偏移坐标。

然后,当瓦片被裁剪时,将它们附加到一个大图像上:

magick imagest-0-0.jpg imagest-1-0.jpg imagest-2-0.jpg imagest-3-0.jpg imagest-4-0.jpg imagest-5-0.jpg +append imagest-0.jpg
...
magick imagest-0.jpg imagest-1.jpg imagest-2.jpg imagest-3.jpg imagest-4.jpg imagest-5.jpg imagest-6.jpg imagest-7.jpg imagest-8.jpg imagest-9.jpg imagest-10.jpg -append imagest.jpg

这种裁剪和附加操作的结果是地图的大的高分辨率图像。如上所述,将其调整为每个级别。

调整PDF的大小

渲染PDF时,我更喜欢使用density调整大小。要计算每个缩放级别的密度(这是Windows命令,针对Linux进行相应修改):

identify -precision 16 -format "%%[fx:((256/max(w,h))*72)]n%%[fx:((512/max(w,h))*72)]n%%[fx:((1024/max(w,h))*72)]n%%[fx:((2048/max(w,h))*72)]n%%[fx:((4096/max(w,h))*72)]" source.pdf

这会给你一些类似的东西:

21.89073634204276
43.78147268408551
87.56294536817103
175.1258907363421
350.2517814726841

(4096/max(w,h))*72表达式的魔力很简单:(目标大小/源大小)*标准DPI。

使密度渲染图像:

convert -verbose -density 21.89073634204276 source.pdf        images.png
convert -verbose -density 43.78147268408551 source.pdf        images1.png
convert -verbose -density 87.56294536817103 source.pdf        images2.png
convert -verbose -density 175.1258907363421 source.pdf        images3.png
convert -verbose -density 350.2517814726841 source.pdf        images4.png

在更高级别上,这可能需要花费大量时间。

剪切瓷砖中的水平图像

此时,每层应该有一个图像。现在我们可以把它们切成瓷砖:

convert -verbose images.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles_%%[filename:tile].png"
convert -verbose images1.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles1_%%[filename:tile].png"
convert -verbose images2.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles2_%%[filename:tile].png"
convert -verbose images3.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles3_%%[filename:tile].png"
convert -verbose images4.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles4_%%[filename:tile].png"
convert -verbose images5.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles5_%%[filename:tile].png"

这会生成如下文件:

  • tiles/0_0_0.png
  • tiles/1_0_0.png
  • tiles/1_0_1.png
  • tiles/1_1_0.png
  • tiles/1_1_1.png
  • 等等

这是一组256x256大小的静态预渲染瓷砖。

配置传单

现在您只需要配置传单。假设tile文件相对于HTML文件位于../tiles目录中,那么它就是:

L.tileLayer('../tiles/{z}_{x}_{y}.png', {
maxZoom: 5,
noWrap: true,                     
attribution: 'Some Attribution'
}).addTo(map);

如果你想设置正确的初始视点,缩放/移动到你想要的位置,打开开发工具中的JavaScript控制台,然后键入:

map.getCenter();
map.getZoom();

然后在初始化地图时使用打印的参数:

var map = L.map('map').setView([-26.3525, -65.0390], 3);

添加标记:

L.marker([-26.3525, -65.0390], {title: "Hi there!"}).addTo(map);

即使在平移或缩放时,标记也将保持在相同的位置。


这里有一个项目作为例子:

  • https://github.com/highsource/unece-maps

libvips有一个操作,可以在一个命令中为传单制作一个光滑的贴图tileset。

例如,有了这张欧洲内陆水道的PDF地图(谢谢@dictire!),你可以输入:

vips dzsave European_inland_waterways_-_2012.pdf[dpi=600] xxx --layout google

它会创建一个名为xxx的目录,其中包含您的所有磁贴,准备上传到您的服务器。这大约需要15秒(无论如何,在这台笔记本电脑上)。

它很快,只需要很少的内存。细节随着文件格式的不同而有所不同,但对于许多格式,它可以并行解码输入、构建所有金字塔层和写入输出瓦片,而无需将整个输入图像加载到内存中。我经常在一台普通的笔记本电脑上渲染超过300000 x 300000像素的金字塔。

它可以做一些有用的文件类型,以及常见的tiff、PNG、JPG等,包括SVG、FITS、DICOM和OpenSlide。它可以制作深度缩放和缩放的金字塔。

Windows主机的一个不错的功能是能够将tileset写入zip文件而不是文件系统。Windows在文件创建方面相当慢——有了一个大金字塔和小瓦片,仅在文件创建上就可以花费几乎75%的CPU时间。改为写入zip文件,您可能会看到3倍的加速:

vips dzsave huge.tif xxx.zip --layout google

当然,zip上传到服务器更简单。

libvips手册中有一章介绍了dzsave并显示了所有选项。

最新更新