我正在尝试提取大型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
答案 0 :(得分:2)
我无法下载您的图片进行任何测试,但您可以考虑使用vips
,它非常快速且节省时间,特别是对于大图像 - 我认为是你的,否则你可能不会使用BigTIFF
。
所以,如果我们使用 ImageMagick 制作一个大的10,000 x 10,000 TIF用于测试:
convert -size 10000x10000 gradient:cyan-magenta -compress lzw test.tif
我在这里展示了一个较小的JPEG版本:
您可以像这样使用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
现在它可以寻找和读出它需要的部分。
当然,您可能无法控制图像格式的细节,但如果这样做,您会发现对于这种操作,平铺图像速度更快,所需内存更少。