OpenImageIO: открыть изображение с разрешением окна дисплея вместо разрешения данных
Я работаю с OpenImage Denoiser, который загружает файлы EXR с помощью OpenImageIO.
Изображения загружаются так:
std::shared_ptr<ImageBuffer> loadImageOIIO(const std::string& filename, int channels)
{
auto in = OIIO::ImageInput::open(filename);
if (!in)
throw std::runtime_error("cannot open image file: " + filename);
const OIIO::ImageSpec& spec = in->spec();
if (channels == 0)
channels = spec.nchannels;
else if (spec.nchannels < channels)
throw std::runtime_error("not enough image channels");
auto image = std::make_shared<ImageBuffer>(spec.width, spec.height, channels);
if (!in->read_image(0, 0, 0, channels, OIIO::TypeDesc::FLOAT, image->getData()))
throw std::runtime_error("failed to read image data");
in->close();
#if OIIO_VERSION < 10903
OIIO::ImageInput::destroy(in);
#endif
return image;
}
Однако это обрезает изображение до ограничивающей рамки окна данных. Поскольку у моего изображения 0 значений, это изображение меньше фактического входного изображения.
Как я могу получить ImageBuffer с полным разрешением окна дисплея?
1 ответ
Приведенные выше строки выделяют изображение шириной x высотой x каналами, но проблема в том, что с точки зрения OIIO, spec.width и height описывают окно данных. Итак, вы хотите начать с
auto image = std::make_shared<ImageBuffer>(spec.full_width, spec.full_height, channels);
Это выделяет буфер для «полного» (отображаемого) окна.
Затем вы хотите вызвать read_image, используя некоторые дополнительные параметры, которые вы оставили по умолчанию, те, которые позволяют вам указывать явные шаги. Без шагов предполагается, что вы читаете в буфер, который является непрерывным и имеет размер, подходящий для окна данных. Предоставление шагов запишет смещение пикселей в правильные позиции с правильным интервалом, а также вы хотите правильно сместить в буфер. Я думаю, вы хотите этого:
size_t pixelsize = channels * sizeof(float);
size_t scanlinesize = pixelsize * spec.full_width;
if (!in->read_image(/*subimage*/ 0, /*miplevel*/ 0, /*chbegin*/ 0, /*chend*/ channels,
OIIO::TypeDesc::FLOAT,
image->getData() + spec.x * pixelsize + spec.y * scanlinesize,
/*xstride*/ pixelsize, /*ystride*/ scanlinesize)
Не забудьте сначала обнулить свой буфер, потому что теперь вызов read_image не будет записывать все значения буфера, а только те, которые имеют пиксели данных!
Теперь даже это не совсем общее. Я упростил, предполагая, что ваше окно отображения (то, что OIIO называет «полным») имеет свое происхождение как (0,0) и будет таким же, как окно данных для изображения, которое не имеет черных пикселей, то есть данные и полный различаются только из-за «обрезки» ненулевой области. Но на самом деле возможно (и часто в производстве) иметь окна данных, которые больше , чем окно отображения, а это означает, что вы вычисляете области «за пределами сканирования» (включая то, что окно данных может расширяться до отрицательных индексов пикселей). Если это может быть так, и вам нужно охватить все возможные базы, то вам, возможно, нужно выделить изображение, которое представляет собой объединение перекрытия между окнами дисплея и данных, и настроить приведенный выше код, чтобы правильно обрабатывать это.