I'm trying to move towards Boost GIL to replace some similar functionality I've implemented that is reaching the end of its maintainable life.
I have existing code that works with 24 BPP, 8bit RGB images using uint8_t*
. I can't change that as the same interface is used to expose images from different places (e.g. OpenGL buffers) and there's already quite a lot of code.
Therefore I'm trying to use GIL in small steps, starting by reading a file and copying the pixels byte by byte into a std::vector<uint8_t>
which I can use to manage the storage, but still get a uint8_t*
by using &vector[0]
.
This can be dropped in transparently behind the existing interfaces until it's at a point where refactoring makes sense.
I thought this should be a simple case of using copy_pixels()
with two appropriately constructed views.
I've put together a minimal, complete example that illustrates the sum of what I've manage to achieve by looking over the documents and trying things out:
#include <boost/gil/rgb.hpp>
#include <boost/gil/extension/io/png_dynamic_io.hpp>
#include <stdint.h>
#include <vector>
int main() {
std::vector<uint8_t> storage;
{
using namespace boost::gil;
rgb8_image_t img;
png_read_image("test.png", img);
// what should replace 3 here to be more "generic"?
storage.resize(img.width()*img.height()*3);
// doesn't work, the type of the images aren't compatible.
copy_pixels(const_view(img),
interleaved_view(img.width(), img.height(), &storage[0], 3*img.width()));
}
}
This doesn't compile:
error: cannot convert ‘const boost::gil::pixel<unsigned char, boost::gil::layout<boost::mpl::vector3<boost::gil::red_t, boost::gil::green_t, boost::gil::blue_t> > >’ to ‘unsigned char’ in assignment
Which is fairly self-explanatory - an RGB pixel can't be converted to a single unsigned char
automatically. I thought I'd try using copy_and_convert_pixels()
to fix this, but I can't see a way around the 3:1 (i.e. I have 3 unsigned char
s in the output for every pixel in the source image) problem with these conversions. Conversion seems to be more aimed at colourspace conversions (e.g. RGB->HSV) or packing changes.
I would just push_back each color of the rgb8_pixel_t individually:
struct PixelInserter{
std::vector<uint8_t>* storage;
PixelInserter(std::vector<uint8_t>* s) : storage(s) {}
void operator()(boost::gil::rgb8_pixel_t p) const {
storage->push_back(boost::gil::at_c<0>(p));
storage->push_back(boost::gil::at_c<1>(p));
storage->push_back(boost::gil::at_c<2>(p));
}
};
int main() {
std::vector<uint8_t> storage;
{
using namespace boost::gil;
rgb8_image_t img;
png_read_image("test.png", img);
storage.reserve(img.width() * img.height() * num_channels<rgb8_image_t>());
for_each_pixel(const_view(img), PixelInserter(&storage));
}
...
}
...but I'm not an expert on GIL either.