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

How to make a tiled image pyramid for leaflet from a non-geographic source

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

我已经阅读了 Non-geographical maps but this case demonstrates the use of one single image instead of tiling. I would rather prefer tiles since my image is going to be fairly large. Is there something else that would fit a case like the one I described above please? I am looking into rastercoords 中的示例,但我还没有具体说明这是否适用于任何光栅文件,这仅适用于普通地图。

以下是我关于如何从 PDFs or high-res images or non-slippy maps 等来源创建滑动地图的经验。反正我想写一篇关于这个的文章,就让这个答案作为未写文章的草图吧。

举个例子,这里有一个 PDF map of European inland waterways with vector graphics and here's a slippy map

基本上最合理的方式就是做一个标准的tile set,让Leaflet展示出来。 IE。为每个缩放级别生成大小为 256x256 的图块。
您不希望将巨大的图像作为图层,因为这对浏览器来说太重了。您也不希望在浏览器中调整大小,这会导致质量不佳。

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

决定你想要多少缩放级别

首先,决定您想要多少缩放级别。这取决于地图,根据我的经验,您最多需要 5-7 个缩放级别。让我们以 5 个缩放级别为例。您制作的关卡越多,对硬件的要求就越高。下面的方法可能不适合超过 7-8 个缩放级别。

渲染或调整源图像的大小

接下来,为每个缩放级别渲染图像或调整图像大小。您必须生成尺寸之一等于:

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

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

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

如果您的来源是高分辨率图片,只需使用 convert -resizex*256**256*x:

convert images\source.jpg -resize   x256 images[=10=].jpg
convert images\source.jpg -resize   x512 images.jpg
convert images\source.jpg -resize  x1024 images.jpg
convert images\source.jpg -resize  x2048 images.jpg
convert images\source.jpg -resize  x4096 images.jpg
convert images\source.jpg -resize  x8192 images.jpg

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

使用已经平铺的图像

在某些情况下,源图像已经切割成图块。这在您想要滑动的 "old" 地图客户端中很典型。 This is an example,瓷砖被称为 vk-X-Y.jpg 并且被切割时有一些重叠。在这种情况下,您首先必须裁剪图像:

magick data\vk-0-0.jpg  -crop 522x373+0x0 images\t-0-0.jpg
magick data\vk-1-0.jpg  -crop 522x373+0x0 images\t-1-0.jpg
magick data\vk-2-0.jpg  -crop 522x373+0x0 images\t-2-0.jpg
magick data\vk-3-0.jpg  -crop 522x373+0x0 images\t-3-0.jpg
magick data\vk-4-0.jpg  -crop 522x373+0x0 images\t-4-0.jpg
magick data\vk-5-0.jpg  -crop 650x373+0x0 images\t-5-0.jpg
...

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

然后,裁剪图块后,将它们附加到大图像上:

magick images\t-0-0.jpg images\t-1-0.jpg images\t-2-0.jpg images\t-3-0.jpg images\t-4-0.jpg images\t-5-0.jpg +append images\t-0.jpg
...
magick images\t-0.jpg images\t-1.jpg images\t-2.jpg images\t-3.jpg images\t-4.jpg images\t-5.jpg images\t-6.jpg images\t-7.jpg images\t-8.jpg images\t-9.jpg images\t-10.jpg -append images\t.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[=15=].png
convert -verbose -density 43.78147268408551 source.pdf        images.png
convert -verbose -density 87.56294536817103 source.pdf        images.png
convert -verbose -density 175.1258907363421 source.pdf        images.png
convert -verbose -density 350.2517814726841 source.pdf        images.png

在更高级别上这可能会花费很多时间。

在平铺中切割关卡图像

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

convert -verbose images[=16=].png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles[=16=]_%%[filename:tile].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 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 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 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 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"

这会生成如下文件:

  • 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 大小的图块。

配置传单

现在你只需要配置Leaflet。假设 tile 文件位于 ../tiles 相对于 HTML 文件的目录中,它很简单:

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

如果您想设置正确的初始视点 zoom/move 到您想要的位置,请在您的开发工具中打开 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);

即使平移或缩放,标记也会保持在同一位置。


以其中一个项目为例:

libvips 有一个操作可以在一个命令中为传单制作一个滑动地图瓦片集。

例如,使用这个PDF map of European inland waterways(谢谢@lexicore!)你可以输入:

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

它会生成一个名为 xxx 的目录,其中包含您所有的图块,随时可以上传到您的服务器。大约需要 15 秒(无论如何在这台笔记本电脑上)。

速度快,占用内存少。细节因文件格式而略有不同,但对于许多格式,它可以解码输入、构建所有金字塔层并写入输出图块,所有这些都是并行的,而无需将整个输入图像加载到记忆。我经常在一台普通笔记本电脑上渲染超过 300,000 x 300,000 像素的金字塔。

它可以处理一些有用的文件类型以及常见的 tiff、PNG、JPG 等,包括 SVG、FITS、DICOM 和 OpenSlide 等。它也可以为 deepzoom 和 zoomify 制作金字塔。

Windows 主机的一个不错的功能是能够将 tileset 写入 zip 文件而不是文件系统。 Windows 在创建文件时相当慢 -- 对于大金字塔和小瓷砖,您可以将近 75% 的 CPU 时间花在创建文件上。改为写入 zip 文件,您可能会看到 3 倍的加速:

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

当然,zip 更容易上传到服务器。

有一个 chapter in the libvips manual introducing dzsave 并显示所有选项。