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) и будет таким же, как окно данных для изображения, которое не имеет черных пикселей, то есть данные и полный различаются только из-за «обрезки» ненулевой области. Но на самом деле возможно (и часто в производстве) иметь окна данных, которые больше , чем окно отображения, а это означает, что вы вычисляете области «за пределами сканирования» (включая то, что окно данных может расширяться до отрицательных индексов пикселей). Если это может быть так, и вам нужно охватить все возможные базы, то вам, возможно, нужно выделить изображение, которое представляет собой объединение перекрытия между окнами дисплея и данных, и настроить приведенный выше код, чтобы правильно обрабатывать это.

Другие вопросы по тегам