работа с двоичными (1 бит на пиксель) изображениями Переполнение стека

Проблема в следующем. Необходимо работать с очень большими двоичными изображениями (100000×100000 пикселей). Изначально это делалось с использованием класса Qt QImage, он поддерживает формат Format_Mono, в котором изображение хранится в виде 1-битного на пиксель. А в целом все было хорошо, пока не оказалось, что QPainter ограничил растеризатор и рисовать на изображениях, размер которых короче (32767×32767) нельзя, его просто обрезали.

Я не смог объединить изображения более чем на 32767×32767. Затем я начал присматриваться к отдельным библиотекам. OpenCV, насколько я понимаю, не поддерживает этот формат. Что касается ImageMagick, он поддерживает построение изображения как один бит на пиксель и сохраняет его в том же формате. Однако при работе с изображением все равно сохраняется 8 бит на пиксель и, следовательно, возникает нехватка оперативной памяти. Тогда я решил попробовать CImg, но он не поддерживает формат 1bbp, как я понимаю:

общий размер используемой памяти для одного экземпляра изображения (в байтах)
тогда ширина ‘высота х глубина х тусклый х sizeof (T)

Где sizeof (T), конечно, не может быть меньше sizeof (char) …

Было интересно, как QImage в принципе работает с его форматом Format_Mono, но, честно говоря, я запутался в исходном коде.

Итак, у меня следующий вопрос. Существует ли библиотека, в которой реализована возможность создания и работы с двоичными изображениями, и в этом случае они действительно хранятся в виде 1-битного пикселя в ОЗУ?

0

Решение

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 бита для записи.

Пиковый результат мем — от просмотра RES в top, К сожалению, 6,7 ГБ довольно велико, поскольку для каждого из 1000 входных изображений приходится хранить входные буферы.

Если вы используете мозаичный 1-битный TIFF, вы можете удалить access = опцию и использовать операторы, которым нужен произвольный доступ, например, поворот. Если вы попытаетесь повернуть полосу, vips придется распаковать весь образ во временный файл на диске, который вам, вероятно, не нужен.

У vips есть ряд стандартных операторов обработки изображений, поэтому вы можете делать то, что хотите, просто склеивая их вместе. Вы можете добавить новые операторы в C или C ++, если хотите.

Этот пример для краткости приведен в Python, но вы можете использовать Ruby, PHP, C, C ++, Go, JavaScript или командную строку, если хотите. Он поставляется со всеми Linux и BSD, на homebrew, MacPorts и fink, и есть бинарный файл Windows.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]