使用二进制(每像素 1 位)图像 C++
work with binary (1 bit per pixel) images c++
问题如下。有必要处理非常大的二进制图像(100000x100000 像素)。最初是使用 Qt 的 QImage class 实现的,它支持 Format_Mono 格式,将图像存储为每像素 1 位。总的来说,一切都很好,直到事实证明 QPainter 的光栅化器有限并且无法在尺寸更短 (32767x32767) 的图像上绘制,它只是被切断了。
我无法合并超过 32767x32767 的图像。然后,我开始仔细观察各个库。据我了解,OpenCV 不支持这种格式。关于ImageMagick,它支持将图像构建为每像素一位,并以相同的格式保存。然而,在处理图像时,图像仍然以每像素 8 位的形式存储,因此会出现 RAM 不足的情况。然后我决定尝试CImg,但据我了解它不支持1bbp格式:
the overall size of the used memory for one instance image (in bytes)
is then 'width x height x depth x dim x sizeof (T)
其中sizeof(T)当然不能小于sizeof(char)...
有趣的是 QImage 原则上如何使用其 Format_Mono 格式,但老实说,我对源代码很纠结。
所以,我有下一个问题。是否有一个库实现了创建和使用二进制图像的能力,在这种情况下,它们真的以每像素 1 位的形式存储在 RAM 中?
libvips 可以处理巨大的 1 位图像。它将它们解压缩为每个字节一个像素以进行处理,但它只将当前正在处理的图像部分保留在内存中,所以你应该没问题。
例如,这个小程序制作了一个 100,000 x 100,000 像素的黑色图像,然后将 command-line 中的所有图像粘贴到随机位置:
#!/usr/bin/env python
import sys
import random
import gi
gi.require_version('Vips', '8.0')
from gi.repository import Vips
# this makes a 8-bit, mono image of 100,000 x 100,000 pixels, each pixel zero
im = Vips.Image.black(100000, 100000)
for filename in sys.argv[2:]:
tile = Vips.Image.new_from_file(filename, access = Vips.Access.SEQUENTIAL)
im = im.insert(tile,
random.randint(0, im.width - tile.width),
random.randint(0, im.height - tile.height))
im.write_to_file(sys.argv[1])
我可以运行这样的程序:
$ vipsheader wtc.tif
wtc.tif: 9372x9372 uchar, 1 band, b-w, tiffload
$ mkdir test
$ for i in {1..1000}; do cp wtc.tif test/$i.tif; done
$ time ./insert.py x.tif[bigtiff,squash,compression=ccittfax4] test/*.tif
real 1m31.034s
user 3m24.320s
sys 0m7.440s
peak mem: 6.7gb
输出文件名上的[]
设置图像写入选项。我在这里启用传真压缩并设置 squash
选项。这意味着 8 位单波段图像应压缩为 1 位以进行写入。
最高内存结果来自 top
中的 RES 观察。不幸的是,6.7gb 相当大,因为它必须为 1,000 个输入图像中的每一个保留输入缓冲区。
如果您使用平铺的 1 位 tiff,您可以删除 access =
选项并使用需要随机访问的运算符,例如旋转。如果您尝试旋转一个带状 tiff,vips 将不得不将整个图像解压缩到一个临时磁盘文件,您可能不希望这样。
vips 拥有一系列合理的标准图像处理运算符,因此您只需将它们粘合在一起就可以做您想做的事情。如果需要,您可以在 C 或 C++ 中添加新的运算符。
为简洁起见,该示例位于 Python 中,但您可以使用 Ruby、PHP、C、C++、Go、JavaScript 或 command-line 如果你比较喜欢。它与所有 Linux 和 BSD 一起提供,它在自制软件、MacPorts 和 fink 上,并且有一个 Windows 二进制文件。
问题如下。有必要处理非常大的二进制图像(100000x100000 像素)。最初是使用 Qt 的 QImage class 实现的,它支持 Format_Mono 格式,将图像存储为每像素 1 位。总的来说,一切都很好,直到事实证明 QPainter 的光栅化器有限并且无法在尺寸更短 (32767x32767) 的图像上绘制,它只是被切断了。
我无法合并超过 32767x32767 的图像。然后,我开始仔细观察各个库。据我了解,OpenCV 不支持这种格式。关于ImageMagick,它支持将图像构建为每像素一位,并以相同的格式保存。然而,在处理图像时,图像仍然以每像素 8 位的形式存储,因此会出现 RAM 不足的情况。然后我决定尝试CImg,但据我了解它不支持1bbp格式:
the overall size of the used memory for one instance image (in bytes) is then 'width x height x depth x dim x sizeof (T)
其中sizeof(T)当然不能小于sizeof(char)...
有趣的是 QImage 原则上如何使用其 Format_Mono 格式,但老实说,我对源代码很纠结。
所以,我有下一个问题。是否有一个库实现了创建和使用二进制图像的能力,在这种情况下,它们真的以每像素 1 位的形式存储在 RAM 中?
libvips 可以处理巨大的 1 位图像。它将它们解压缩为每个字节一个像素以进行处理,但它只将当前正在处理的图像部分保留在内存中,所以你应该没问题。
例如,这个小程序制作了一个 100,000 x 100,000 像素的黑色图像,然后将 command-line 中的所有图像粘贴到随机位置:
#!/usr/bin/env python
import sys
import random
import gi
gi.require_version('Vips', '8.0')
from gi.repository import Vips
# this makes a 8-bit, mono image of 100,000 x 100,000 pixels, each pixel zero
im = Vips.Image.black(100000, 100000)
for filename in sys.argv[2:]:
tile = Vips.Image.new_from_file(filename, access = Vips.Access.SEQUENTIAL)
im = im.insert(tile,
random.randint(0, im.width - tile.width),
random.randint(0, im.height - tile.height))
im.write_to_file(sys.argv[1])
我可以运行这样的程序:
$ vipsheader wtc.tif
wtc.tif: 9372x9372 uchar, 1 band, b-w, tiffload
$ mkdir test
$ for i in {1..1000}; do cp wtc.tif test/$i.tif; done
$ time ./insert.py x.tif[bigtiff,squash,compression=ccittfax4] test/*.tif
real 1m31.034s
user 3m24.320s
sys 0m7.440s
peak mem: 6.7gb
输出文件名上的[]
设置图像写入选项。我在这里启用传真压缩并设置 squash
选项。这意味着 8 位单波段图像应压缩为 1 位以进行写入。
最高内存结果来自 top
中的 RES 观察。不幸的是,6.7gb 相当大,因为它必须为 1,000 个输入图像中的每一个保留输入缓冲区。
如果您使用平铺的 1 位 tiff,您可以删除 access =
选项并使用需要随机访问的运算符,例如旋转。如果您尝试旋转一个带状 tiff,vips 将不得不将整个图像解压缩到一个临时磁盘文件,您可能不希望这样。
vips 拥有一系列合理的标准图像处理运算符,因此您只需将它们粘合在一起就可以做您想做的事情。如果需要,您可以在 C 或 C++ 中添加新的运算符。
为简洁起见,该示例位于 Python 中,但您可以使用 Ruby、PHP、C、C++、Go、JavaScript 或 command-line 如果你比较喜欢。它与所有 Linux 和 BSD 一起提供,它在自制软件、MacPorts 和 fink 上,并且有一个 Windows 二进制文件。