ImageMagick的Stream无法读取TIFF64?

时间:2017-07-29 15:46:12

标签: imagemagick tiff imagemagick-convert

我正在尝试提取大型BigTIFF图像(TIFF64)的子区域。如果图像不是太大,我可以convert src.tif dst.jpg。但是,如果图像非常大,convert不起作用。我试图使用stream来提取感兴趣的区域而不将完整的图像加载到内存中。但是,结果是一个0字节的文件。我在这里上传了一个BigTIFF:

https://mfr.osf.io/render?url=https://osf.io/kgeqs/?action=download%26mode=render

这个小到足以与convert一起使用,它会生成带有stream的0字节图像:

stream -map rgb -storage-type char '20-07-2017_RecognizedCode-10685.tif[1000x1000+10000+10000]' 1k-crop.dat

有没有办法让stream工作?这是stream中带有TIFF64的这个旧bug的回归吗? http://imagemagick.org/discourse-server/viewtopic.php?t=22046

我正在使用ImageMagick 6.9.2-4 Q16 x86_64 2016-03-17

2 个答案:

答案 0 :(得分:2)

我无法下载您的图片进行任何测试,但您可以考虑使用vips,它非常快速且节省时间,特别是对于大图像 - 我认为是你的,否则你可能不会使用BigTIFF

所以,如果我们使用 ImageMagick 制作一个大的10,000 x 10,000 TIF用于测试:

convert -size 10000x10000 gradient:cyan-magenta -compress lzw test.tif

我在这里展示了一个较小的JPEG版本:

enter image description here

您可以像这样使用vips提取左上角,并显示最大内存使用量(使用--vips-leak):

vips crop test.tif a.jpg 0 0 100 100 --vips-leak

<强>输出

memory: high-water mark 5.76 MB

你可以像这样提取右下角:

vips crop test.tif a.jpg 9000 9000 1000 1000 --vips-leak

<强>输出

memory: high-water mark 517.01 MB

使用 ImageMagick ,同样的操作需要1.2GB的RAM:

/usr/bin/time -l convert test.tif -crop 1000x1000+9000+9000 a.jpg
        2.46 real         2.00 user         0.45 sys
1216008192  maximum resident set size
         0  average shared memory size
         0  average unshared data size
         0  average unshared stack size
    298598  page reclaims

答案 1 :(得分:2)

我同意马克的优秀答案,但我还想说你使用的TIFF格式会有很大的不同。

常规条带TIFF并不真正支持随机访问,但平铺的TIFF可以。例如,这里有一个10k x 10k像素的条带TIFF:

void Mesh::slice(SurfaceMesh &mesh,  double lengthToCut){
  typedef SurfaceMesh::Vertex_index vertex_descriptor;
  typedef SurfaceMesh::Face_index face_descriptor;
  typedef SurfaceMesh::Halfedge_index halfEdge_descriptor;
  typedef SurfaceMesh::Edge_index edge_descriptor;
  double y = findMaxY(mesh) - lengthToCut; // length of a mesh
  //;oops over faces
  BOOST_FOREACH(face_descriptor fd, mesh.faces()){
    int verticesLargerThan = 0;
    //loops over vertices of face
    BOOST_FOREACH(vertex_descriptor vd,vertices_around_face(mesh.halfedge(fd), mesh)){
      if(CGAL::compare ( mesh.point(vd)[1],  y) == CGAL::LARGER){
        verticesLargerThan++;
        // if all vertices y coordinates are larger than double y, then removes face
        if(verticesLargerThan == 3){
          mesh.remove_face(fd);
          //mesh.remove_face(fd);
          int removedFaceCounter = 0;
          BOOST_FOREACH(face_descriptor rfd,faces_around_face(mesh.halfedge(fd), mesh)){
            if(mesh.is_removed(rfd)){
              removedFaceCounter++;
            }
            //remove all edges and vertices of face if face is not linked to any other face
            if(removedFaceCounter == 3){
              //removes edge - puts in infinite loop
              BOOST_FOREACH(halfEdge_descriptor hed, halfedges_around_face(mesh.halfedge(fd), mesh)){
                edge_descriptor ed = mesh.edge(hed);
                mesh.remove_edge(ed);
              }
              //removes vertice
              BOOST_FOREACH(vertex_descriptor rvd,vertices_around_face(mesh.halfedge(fd), mesh)){
                //removes vertice if its not linked to any face
                bool allFacesRemoved = true;
                BOOST_FOREACH(face_descriptor rfvd, faces_around_target(mesh.halfedge(fd), mesh)){

                  if(!mesh.is_removed(rfvd)){
                    allFacesRemoved = false;
                    break;
                  }
                }
                if(allFacesRemoved){
                  mesh.remove_vertex(rvd);
                }
              }
            }
          }
        }
      }
    }
  }

这里TIFF阅读器必须扫描几乎整个图像以获得它所需的位,从而导致相对较高的内存使用。

如果您再次尝试使用平铺图像:

$ vips copy wtc.jpg wtc.tif
$ time vips crop wtc.tif x.tif 8000 8000 100 100 --vips-leak
real    0m0.323s
user    0m0.083s
sys     0m0.185s
memory: high-water mark 230.80 MB

现在它可以寻找和读出它需要的部分。

当然,您可能无法控制图像格式的细节,但如果这样做,您会发现对于这种操作,平铺图像速度更快,所需内存更少。