Skip to content

Commit

Permalink
Separated image loading into its own .h/.cpp
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-pr committed May 10, 2020
1 parent 87321c0 commit 65f94bf
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 104 deletions.
111 changes: 111 additions & 0 deletions src/plugins/opencv/image_loading.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include "image_loading.h"

#include <OpenImageIO/imageio.h>
#include <tbb/parallel_for.h>

namespace possumwood { namespace opencv {

using namespace OIIO;

namespace {

template<typename T>
struct ImageTraits;

template<>
struct ImageTraits<unsigned char> {
static const TypeDesc::BASETYPE oiio_type = TypeDesc::UINT8;
static const int opencv_type = CV_8U;
};

template<>
struct ImageTraits<float> {
static const TypeDesc::BASETYPE oiio_type = TypeDesc::FLOAT;
static const int opencv_type = CV_32F;
};

template<typename T>
void copyData(ImageInput& input, cv::Mat& m) {
const ImageSpec &spec = input.spec();
std::size_t xres = spec.width;
std::size_t yres = spec.height;
std::size_t channels = spec.nchannels;

std::vector<T> pixels(xres*yres*channels);
input.read_image(ImageTraits<T>::oiio_type, pixels.data());
input.close();

m = cv::Mat::zeros(yres, xres, CV_MAKETYPE(ImageTraits<T>::opencv_type, channels));

tbb::parallel_for(std::size_t(0), yres, [&](std::size_t y) {
for(std::size_t x=0; x < xres; ++x) {
T* ptr = m.ptr<T>(y, x);

for(std::size_t c=0; c < channels; ++c) {
// reverse channels - oiio RGB to opencv BGR
std::size_t index = channels - c - 1;

T value = *(pixels.data() + (y*xres+x)*channels + c);
assert(value > 0 || value == 0);
*(ptr + index) = value;
}
}
});
}

}

std::pair<cv::Mat, Exif> load(const boost::filesystem::path& filename) {
std::pair<cv::Mat, Exif> result;

if(!filename.filename().empty() && boost::filesystem::exists(filename.filename())) {
std::unique_ptr<ImageInput> in(ImageInput::open(filename.filename().string()));
if (!in)
throw std::runtime_error("Error loading " + filename.filename().string());

// get the image spec
const ImageSpec &spec = in->spec();

// convert the raw data to a cv::Mat type
if(spec.format == TypeDesc::UINT8)
copyData<unsigned char>(*in, result.first);
else if(spec.format == TypeDesc::FLOAT)
copyData<float>(*in, result.first);
else
throw std::runtime_error("Error loading " + filename.filename().string() + " - only images with 8 or 32 bits per channel are supported at the moment!");

// process metadata (EXIF)
float exposure = 0.0f;
{
auto it = spec.extra_attribs.find("ExposureTime");
if(it != spec.extra_attribs.end())
// exposure = (*static_cast<const float*>(it->data()));
exposure = it->get_float();
}

float fnumber = 0.0f;
{
auto it = spec.extra_attribs.find("FNumber");
if(it != spec.extra_attribs.end())
fnumber = it->get_float();
}

float iso = 100.0f;
{
auto it = spec.extra_attribs.find("Exif:PhotographicSensitivity");
if(it != spec.extra_attribs.end())
iso = it->get_float();
}

// for(auto& a : spec.extra_attribs)
// std::cout << a.name() << " " << a.get_float() << std::endl;

result.second = possumwood::opencv::Exif(exposure, fnumber, iso);
}
else
throw std::runtime_error("Filename '" + filename.filename().string() + "' not found or not accessible!");

return result;
}

} }
13 changes: 13 additions & 0 deletions src/plugins/opencv/image_loading.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include <boost/filesystem.hpp>

#include <opencv2/opencv.hpp>

#include "exif.h"

namespace possumwood { namespace opencv {

std::pair<cv::Mat, Exif> load(const boost::filesystem::path& filename);

} }
108 changes: 4 additions & 104 deletions src/plugins/opencv/nodes/capture/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,65 +3,13 @@

#include <tbb/parallel_for.h>

#include <boost/filesystem.hpp>
#include <opencv2/opencv.hpp>
#include <OpenImageIO/imageio.h>

#include <actions/traits.h>

#include "frame.h"
#include "exif.h"
#include "image_loading.h"

namespace {

using namespace OIIO;

template<typename T>
struct ImageTraits;

template<>
struct ImageTraits<unsigned char> {
static const TypeDesc::BASETYPE oiio_type = TypeDesc::UINT8;
static const int opencv_type = CV_8U;
};

template<>
struct ImageTraits<float> {
static const TypeDesc::BASETYPE oiio_type = TypeDesc::FLOAT;
static const int opencv_type = CV_32F;
};

template<typename T>
void copyData(ImageInput& input, cv::Mat& m) {
const ImageSpec &spec = input.spec();
std::size_t xres = spec.width;
std::size_t yres = spec.height;
std::size_t channels = spec.nchannels;

std::vector<T> pixels(xres*yres*channels);
input.read_image(ImageTraits<T>::oiio_type, pixels.data());
input.close();

m = cv::Mat::zeros(yres, xres, CV_MAKETYPE(ImageTraits<T>::opencv_type, channels));

tbb::parallel_for(std::size_t(0), yres, [&](std::size_t y) {
for(std::size_t x=0; x < xres; ++x) {
T* ptr = m.ptr<T>(y, x);

for(std::size_t c=0; c < channels; ++c) {
// reverse channels - oiio RGB to opencv BGR
std::size_t index = channels - c - 1;

T value = *(pixels.data() + (y*xres+x)*channels + c);
assert(value > 0 || value == 0);
*(ptr + index) = value;
}
}
});
}

/////////////////////////////

dependency_graph::InAttr<possumwood::Filename> a_filename;
dependency_graph::OutAttr<possumwood::opencv::Frame> a_frame;
dependency_graph::OutAttr<possumwood::opencv::Exif> a_exif;
Expand All @@ -72,58 +20,10 @@ dependency_graph::State compute(dependency_graph::Values& data) {
// native reader - cannot read or understand EXIF information
// data.set(a_frame, possumwood::opencv::Frame(cv::imread(filename.filename().string())));

cv::Mat result;
possumwood::opencv::Exif exif;

if(!filename.filename().empty() && boost::filesystem::exists(filename.filename())) {
std::unique_ptr<ImageInput> in(ImageInput::open(filename.filename().string()));
if (!in)
throw std::runtime_error("Error loading " + filename.filename().string());

// get the image spec
const ImageSpec &spec = in->spec();

// convert the raw data to a cv::Mat type
if(spec.format == TypeDesc::UINT8)
copyData<unsigned char>(*in, result);
else if(spec.format == TypeDesc::FLOAT)
copyData<float>(*in, result);
else
throw std::runtime_error("Error loading " + filename.filename().string() + " - only images with 8 or 32 bits per channel are supported at the moment!");

// process metadata (EXIF)
float exposure = 0.0f;
{
auto it = spec.extra_attribs.find("ExposureTime");
if(it != spec.extra_attribs.end())
// exposure = (*static_cast<const float*>(it->data()));
exposure = it->get_float();
}

float fnumber = 0.0f;
{
auto it = spec.extra_attribs.find("FNumber");
if(it != spec.extra_attribs.end())
fnumber = it->get_float();
}

float iso = 100.0f;
{
auto it = spec.extra_attribs.find("Exif:PhotographicSensitivity");
if(it != spec.extra_attribs.end())
iso = it->get_float();
}

// for(auto& a : spec.extra_attribs)
// std::cout << a.name() << " " << a.get_float() << std::endl;

exif = possumwood::opencv::Exif(exposure, fnumber, iso);
data.set(a_exif, exif);
}
else
throw std::runtime_error("Filename '" + filename.filename().string() + "' not found or not accessible!");
auto img = possumwood::opencv::load(filename.filename());

data.set(a_frame, possumwood::opencv::Frame(result));
data.set(a_exif, img.second);
data.set(a_frame, possumwood::opencv::Frame(img.first));

return dependency_graph::State();
}
Expand Down

0 comments on commit 65f94bf

Please sign in to comment.