代码之家  ›  专栏  ›  技术社区  ›  Aenaon

如何从非地理来源制作传单的瓷砖图像金字塔

  •  2
  • Aenaon  · 技术社区  · 7 年前

    假设我有一个非地理图像而不是普通的地图。比如说一张X光片,核磁共振扫描或者显微镜图像,我想用传单,这样我可以放大,缩小,并在一些预定的点上放置一些标记。

    我读过这个例子 Non-geographical maps 但本例演示了使用单个图像而不是平铺。我更喜欢瓷砖,因为我的图像会比较大。还有其他适合我上面描述的那种箱子的吗?我正在调查 rastercoords 但我还没有具体说明这是否适用于任何光栅文件,这只是为了平面地图。

    2 回复  |  直到 7 年前
        1
  •  6
  •   lexicore    7 年前

    以下是我在如何从以下来源创建Slippy地图方面的经验: PDFs 或高分辨率图像或 non-slippy maps . 不管怎样,我想写一篇关于这方面的文章,所以让这个答案成为一篇尚未撰写的文章的草图。

    举个例子,这里是 PDF map of European inland waterways 用矢量图形,这里是 slippy map 其中。

    基本上,最合理的方法是制作一套标准的瓷砖,让传单展示出来。即,为每个缩放级别生成大小为256x256的瓷砖。
    你不想让巨大的图像作为层,因为这将是沉重的浏览器。您也不希望在浏览器中调整任何大小,这将导致质量下降。

    幸运的是,创建瓷砖非常容易 ImageMagick . 我就是这样做的。

    决定需要多少缩放级别

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

    渲染或调整源图像的大小

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

    • 256 0级像素
    • 512 一级像素
    • 1024 2级像素
    • 2048 3级像素
    • 4096 4级像素
    • 等等。

    注意:这个步骤的结果是巨大的图像。级别5大约为10 MB,级别6大约为20 MB,级别7大约为40 MB。小心尝试在“普通”工具中打开这些图像。

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

    如果您的源是高分辨率图像,只需使用 convert -resize 有任何一个 x*256* *256*x :

    convert images\source.jpg -resize   x256 images\0.jpg
    convert images\source.jpg -resize   x512 images\1.jpg
    convert images\source.jpg -resize  x1024 images\2.jpg
    convert images\source.jpg -resize  x2048 images\3.jpg
    convert images\source.jpg -resize  x4096 images\4.jpg
    convert images\source.jpg -resize  x8192 images\5.jpg
    

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

    使用已平铺的图像

    在某些情况下,源图像已经被分片剪切。这在“旧”地图客户机中是很典型的,您想让它们滑倒。 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\0.png
    convert -verbose -density 43.78147268408551 source.pdf        images\1.png
    convert -verbose -density 87.56294536817103 source.pdf        images\2.png
    convert -verbose -density 175.1258907363421 source.pdf        images\3.png
    convert -verbose -density 350.2517814726841 source.pdf        images\4.png
    

    在更高的层次上,这可能需要很多时间。

    在瓷砖中剪切水平图像

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

    convert -verbose images\0.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles\0_%%[filename:tile].png"
    convert -verbose images\1.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles\1_%%[filename:tile].png"
    convert -verbose images\2.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles\2_%%[filename:tile].png"
    convert -verbose images\3.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles\3_%%[filename:tile].png"
    convert -verbose images\4.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles\4_%%[filename:tile].png"
    convert -verbose images\5.png -crop 256x256 +adjoin -background white -extent 256x256 -set filename:tile "%%[fx:floor(page.x/256)]_%%[fx:floor(page.y/256)]" +repage "tiles\5_%%[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文件在 ../tiles 目录相对于HTML文件,它只是:

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

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


    以下是其中一个项目的示例:

        2
  •  3
  •   jcupitt    7 年前

    libvips 有一个操作可以在一个命令中为传单生成一个Slippy Map Tileset。

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

    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
    

    当然,压缩包上传到服务器更简单。

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