-
Notifications
You must be signed in to change notification settings - Fork 164
Code Samples
Gil strength is its expressiveness by using concepts and plenty of meta-programming. This makes gil hard to learn and worse hard to extend without creating a mess.
This wiki will show some of the power of gil.
// Always assume
#include <vector>
#include <boost/gil/gil_all.hpp>
using namespace std;
using namespace boost::gil;
How to get the color space type from an image/view?
typedef rgb8_image_t image_t;
typedef typename color_space_type<image_t::view_t::value_type>::type colour_space_t;
There are rgb8_pixel_t
, bgr8_pixel_t
, and any other number of channel combinations. So, how do you get the red channel value?
auto get_red(pixel_t p)
{
return get_color(p, red_t());
}
Each pixel type is defined with a bunch of channel types. Look here for the correct way of defining a new pixel type.
Damn it, my image is interleaved but I only want the red values!
argb8_image_t img( 640, 480 );
fill_pixels(view(img), argb8_pixel_t(0, 255, 0, 0 ));
// get a view to the first channel
auto v = nth_channel_view( view(img), 1 );
// convert the first channel view to gray8
auto c = color_converted_view<gray8_pixel_t>( v );
Such a pixel has a bunch of channels which might be a different data type. For instance, for a color space like rgb we want red to be uint8
but need more space for green and blue, maybe uint32_t
?
bit aligned image example
#include <boost\gil\extension\toolbox\gil_extensions.hpp>
typedef bit_aligned_image4_type<4, 2, 2, 4, bgra_layout_t>::type image_t;
typedef image_t::view_t view_t;
image_t img( 640, 480 );
auto x_it = view(img).row_begin(0);
auto data = (uint8_t*) &at_c<0>(*it);
Create your own bit aligned image
typedef bit_aligned_pixel_reference< uint64_t // needs to be at least 40bits hence uint64_t
, mpl::vector4_c<uint16_t, 10, 10, 10, 10>
, rgba_layout_t
, true
> rgba10_ref_t;
// A mutable iterator over RGBA10 pixels
typedef bit_aligned_pixel_iterator< rgba10_ref_t > rgba10_ptr_t;
typedef std::iterator_traits< rgba10_ptr_t >::value_type rgba10_pixel_t;
rgba10_pixel_t src_10( 20, 30, 40, 50 );
assert( get_color( src_10, red_t() ) == 20 );
assert( get_color( src_10, green_t() ) == 30 );
assert( get_color( src_10, blue_t() ) == 40 );
assert( get_color( src_10, alpha_t() ) == 50 );
Create a pixel type from a bunch of channels with each different ranges (aka different type).
struct double_0 { static double apply() { return 0.0; } };
struct double_1 { static double apply() { return 1.0; } };
struct double_100 { static double apply() { return 100.0; } };
struct double_255 { static double apply() { return 255.0; } };
typedef scoped_channel_value<double, double_0, double_1> channel_0_1_t;
typedef scoped_channel_value<double, double_0, double_255> channel_0_255_t;
typedef scoped_channel_value<double, double_0, double_100> channel_0_100_t;
//color space
typedef mpl::vector3< channel_0_1_t, channel_0_255_t, channel_0_100_t> my_cs_t;
//layout
typedef layout<my_cs_t> my_layout_t;
//pixel
typedef pixel< double, my_layout_t > my_pixel_t; my_pixel_t op;
Be sure to define the correct integral data type when defining a bit aligned image. It must be able to contain all channels
typedef mpl::vector5_c<unsigned, 16, 16, 16, 8, 8> CBSV;
int sum = mpl::accumulate< CBSV, mpl::int_<0>, mpl::plus<mpl::_1, mpl::_2> >::type::value;
static_assert(mpl::accumulate< CBSV, mpl::int_<0>, mpl::plus<mpl::_1, mpl::_2> >::type::value < sizeof(uint64_t));
You got memory and need to run through in an orderly fashion? gil got you covered!
Create a bit_aligned iterator from raw memory
std::vector<uint8_t> buf( 100 );
typedef bit_aligned_image1_type<1, gray_layout_t>::type::view_t view1_t;
typedef color_converted_view_type< view1_t, view1_t::reference >::type cc_view_t;
typedef cc_view_t::x_iterator cc_it_t;
auto cc_it = cc_it_t( view1_t::x_iterator(buf.date()) );
int Width = 640;
int Height = 480;
// create a rgb float buffer
float* src_buffer = new float[ 3 * Width * Height ];
// create a gil view of the src buffer
rgb32f_view_t v = interleaved_view(
Width
, Height
, (rgb32f_pixel_t*) src_buffer
, 3 * 4 * Width // row length in bytes
);
// set pixel values
fill_pixels(v, rgb32f_pixel_t( 1.f ));
// let's create a rgb8 view
typedef color_converted_view_type<rgb32f_view_t, rgb8_pixel_t>::type ccv_t;
ccv_t dst = color_converted_view<rgb8_pixel_t>(v);
// all channels should be 255 which is gil's default behavior
rgb8_pixel_t p = *dst.xy_at(0,0);
Can be tricky
// bits32f is a scoped value channel
typedef pixel<bits32f, gray_layout_t> pixel_t;
gray8_pixel_t src(23);
pixel_t dst(0);
// 23 / 255 <-- uint8 max value
color_convert(src, dst);
// dst[0] is ~0.09..
Generic way for hashing pixels. We are using static_for_each()
to loop through all channels of a pixel.
#include <unordered_map>
template< typename Pixel >
struct pixel_hasher
{
std::size_t operator()( const Pixel& p ) const
{
typedef channel_type<Pixel>::type channel_t;
std::size_t hash = 0;
static_for_each( p, [&] ( const channel_t& c )
{
boost::hash_combine(hash, c);
});
return hash;
}
};
void test()
{
typedef rgb8_pixel_t pixel_t;
pixel_t p( 1,2,3);
unordered_map< pixel_t, int, pixel_hasher< pixel_t > > n;
n[p] = 99;
}
#include <SFML/Graphics.hpp>
#include <cassert>
#include <complex>
#include <iostream>
#include <boost/gil/gil_all.hpp>
#include <boost/gil/extension/toolbox/color_spaces/hsv.hpp>
#ifdef _DEBUG
const int width = 640; //1024;
const int height = 480; //768;
#else
const int width = 1024;
const int height = 768;
#endif
template< typename T = double >
struct coloring_info
{
coloring_info()
: _inside( true )
{}
coloring_info( bool inside, const std::complex< T >& value, int iterations, int max_iterations )
: _inside( inside )
, _value( value )
, _iterations( iterations )
, _max_iterations( max_iterations )
{}
sf::Color get_color() const
{
sf:: Color color;
color.a = 255;
using namespace boost;
using namespace gil;
hsv32f_pixel_t src( ( _iterations % 256 ) / 255.f // hue
, 1.f // (full) saturation
, ( _iterations < _max_iterations ) ? 1.f : 0.f // value
);
rgb8_pixel_t dst;
color_convert(src, dst);
color.r = gil::get_color(dst, red_t());
color.g = gil::get_color(dst, green_t());
color.b = gil::get_color(dst, blue_t());
if( _inside )
{
color = sf::Color::Black;
}
else
{
if( _iterations < _max_iterations )
{
// point does not belong to Mandelbrot set
int r = static_cast<int>(( 255.0 / _max_iterations ) * _iterations );
if( _iterations < ( _max_iterations / 2 ))
{
color.r = r;
color.g = 0;
color.b = 0;
}
else
{
color.r = r;
color.g = 255;
color.b = 255;
}
color.r;
color.g;
color.b;
}
}
return color;
}
bool _inside;
std::complex< T > _value;
int _iterations;
int _max_iterations;
};
template< typename T = double >
struct fractal_parameters
{
// set all parameters by hand
fractal_parameters( T r_min, T r_max, T i_min, T i_max, int max_iterations, int width , int height )
: _real_min(r_min)
, _real_max(r_max)
, _imag_min(i_min)
, _imag_max(i_max)
, _max_iterations( max_iterations )
, _real( 0 )
, _imag( 0 )
{
// real_max = 1.0
// real_min = -2.0
// imag_max = 2.0
// imag_min = -1.2
// width = 640
// height = 480
// x_step = ( 1 + 2 ) / 639 = 0.005
// y_step = ( 2 + 1.2 ) / 479 = 0.007
_x_step = ( _real_max - _real_min ) / ( width - 1 );
_y_step = ( _imag_max - _imag_min ) / ( height - 1 );
}
// scales to include aspect ration
fractal_parameters( T r_min, T r_max, T i_min, int max_iterations, int width , int height )
: _real_min(r_min)
, _real_max(r_max)
, _imag_min(i_min)
, _max_iterations( max_iterations )
, _real( 0 )
, _imag( 0 )
{
_imag_max = _imag_min + ( _real_max - _real_min ) * height / width;
_x_step = ( _real_max - _real_min ) / ( width - 1 );
_y_step = ( _imag_max - _imag_min ) / ( height - 1 );
}
// real_min represents x = 0 or the left boundary of the image
void set_x( int x ) { _real = _real_min + x * _x_step; }
// imag_max represents y = 0 or the upper boundary of the image
void set_y( int y ) { _imag = _imag_max - y * _y_step; }
coloring_info<> calc() const
{
coloring_info<> ci;
std:: complex< T> c( _real, _imag );
std:: complex< T> Z( c );
int n;
for( n = 0; n < _max_iterations; ++n )
{
if( std::abs( Z ) > 2.0 )
{
ci._inside = false;
break;
}
Z = Z * Z + c;
}
ci._iterations = n;
ci._max_iterations = _max_iterations;
return ci;
}
T _real_min;
T _real_max;
T _imag_min;
T _imag_max;
T _x_step;
T _y_step;
int _max_iterations;
T _real;
T _imag;
};
// upper left is 0,0
void set_pixel( sf::Image & image , int x , int y , unsigned char r = 255, unsigned char g = 255, unsigned char b = 255 )
{
image.setPixel( x, y, sf:: Color( r, g, b, 255));
}
void set_pixel( sf::Image & image , int x , int y , sf::Color c )
{
image.setPixel( x, y, c );
}
void paint( sf::Image & image , sf::Color c )
{
for( int y = 0; y < height; ++y )
{
for( int x = 0; x < width; ++x )
{
set_pixel( image, x, y, c.r, c.g, c.b );
}
}
}
void redraw( sf::Image & image , fractal_parameters <> mandel_brot )
{
//paint(image, sf::Color::Black);
sf::Color color;
for( int y = 0; y < height; ++y )
{
mandel_brot.set_y( y );
for( int x = 0; x < width; ++x )
{
mandel_brot.set_x( x );
auto ci = mandel_brot.calc();
set_pixel( image, x, y, ci.get_color() );
}
}
}
int main()
{
sf::RenderWindow window(sf:: VideoMode(width, height), "Title");
window.setFramerateLimit( 30 );
sf::Texture texture;
if( !texture.create(width, height))
{
exit(1);
}
sf::Image image;
image.create(width, height);
fractal_parameters<> mandel_brot_1( -2.0, 1.0, -1.2, 50, width, height );
fractal_parameters<> mandel_brot_2( -2.0, 1.0, -1.2, 300, width, height );
//max_iterations++;
redraw( image, mandel_brot_1 );
while (window.isOpen())
{
sf:: Event event;
while (window.pollEvent(event))
{
switch(event.type)
{
case sf:: Event:: Closed:
{
window.close();
break;
}
case sf:: Event:: KeyPressed:
{
if( sf:: Keyboard::isKeyPressed( sf:: Keyboard:: Right ))
{
std::cout << "right" << std::endl;
std::cout << "begin" << std::endl;
redraw( image, mandel_brot_2 );
std::cout << "end" << std::endl;
}
else if( sf:: Keyboard::isKeyPressed( sf:: Keyboard:: Left ))
{
std::cout << "left" << std::endl;
std::cout << "begin" << std::endl;
redraw( image, mandel_brot_1 );
std::cout << "end" << std::endl;
}
break;
}
}
}
texture.update(image);
sf:: Sprite sprite(texture);
window.clear();
window.draw(sprite);
window.display();
}
return 0;
}
#include <boost/test/unit_test.hpp>
#include <boost/gil/gil_all.hpp>
using namespace std;
unsigned int width = 640;
unsigned int height = 480;
// format is ARGB8888 -> 4 bytes
// scanline size in bytes
unsigned int scanline = width * sizeof( Uint32 );
unsigned int frame_size = scanline * height;
SDL_Renderer* ren = NULL;
SDL_Texture* tex = NULL;
Uint32* pixels = NULL;
Uint32 draw( Uint32 interval, void* param )
{
using namespace boost;
using namespace gil;
argb8_view_t v = interleaved_view( width, height, (argb8_pixel_t*) pixels, scanline );
fill_pixels( v, argb8_pixel_t( 255, 255, 0 , 0 ));
//memset( pixels, 0, frame_size );
SDL_UpdateTexture( tex, NULL, pixels, scanline );
SDL_RenderClear( ren );
SDL_RenderCopy( ren, tex, NULL, NULL );
SDL_RenderPresent( ren );
return interval;
}
BOOST_AUTO_TEST_CASE( sdl_test )
{
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
cout << SDL_GetError() << endl;
}
// Create Window
SDL_Window* win = SDL_CreateWindow( "First"
, 100
, 100
, width
, height
, SDL_WINDOW_SHOWN
);
if( win == NULL )
{
cout << SDL_GetError() << endl;
}
// Create Renderer
ren = SDL_CreateRenderer( win
, -1 // SDL selects video driver
, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
);
if( ren == NULL )
{
cout << SDL_GetError() << endl;
}
tex = SDL_CreateTexture( ren
, SDL_PIXELFORMAT_ARGB8888
, SDL_TEXTUREACCESS_STREAMING
, width
, height
);
if( tex == NULL )
{
cout << SDL_GetError() << endl;
}
pixels = (Uint32*) malloc( frame_size );
// Add Timer
SDL_AddTimer( 100, draw, NULL );
// Wait for user to quit
bool quit = false;
SDL_Event e;
while( quit == false )
{
while( SDL_PollEvent( &e ))
{
if( e.type == SDL_WINDOWEVENT )
{
auto id = e.window.windowID;
break;
}
if( e.type == SDL_QUIT )
{
quit = true;
break;
}
if( e.type == SDL_KEYDOWN )
{
quit = true;
break;
}
}
}
// Clean up
SDL_DestroyTexture( tex );
SDL_DestroyRenderer( ren );
SDL_DestroyWindow( win );
SDL_Quit();
}