c++ - 使用二进制(每像素 1 位)图像 C++

标签 c++ image monochrome

问题如下。有必要处理非常大的二进制图像(100000x100000 像素)。最初是使用 Qt 的 QImage 类完成的,它支持将图像存储为每像素 1 位的 Format_Mono 格式。总的来说,一切都很好,直到事实证明 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 像素的黑色图像,然后将命令行中的所有图像粘贴到随机位置:

#!/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 或命令行。它与所有 Linux 和 BSD 一起提供,它在自制软件、MacPorts 和 fink 上,还有一个 Windows 二进制文件。

关于c++ - 使用二进制(每像素 1 位)图像 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42000742/

相关文章:

c++ - Failed with error 87 : The parameter is incorrect. 如何确定哪个参数不正确?

c++ - 如何清除进程命令行?

android - Google 相册应用程序风格的图像裁剪、拉直和平移

css - Bxslider:图像 slider 底部的灰色区域

c++ - 避免复制重复使用的特征 block

c++ - Visual C++ - 从链接器>输入>附加依赖项中排除文件

ios - 将图像保存到数据库并从服务器加载

linux - 用于在 Linux 中读/写双色 (1bpp) 图像的库?

c++ - 从 bitset 创建单色 BMP

java - 在 Java 中显示矩阵的灰度图像