SLIP  1.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Tutorial

Introduction

The containers of the same dimension have almost the same interfaces. That is to say when you master the use of one of them, you will easily use the others. Multicomponent containers have further constructors and iterators functions. Mathematic (numeric) containers have some further arithmetical and mathematical functions. In the following, we give examples of use of 2d ones:

Then we explain the principle of masked and predicated algorithms and some other usefull algorithms like slip::iota, slip::statistics. Finally, we give some complementary examples.

GrayscaleImage manipulation

Various way to construct a GrayscaleImage:
//create a GrayscaleImage without allocation
//create a GrayscaleImage with 50 rows and 60 columns
//create a 256x256 GrayscaleImage initialized with 10.0
//create a 3x4 GrayscaleImage initialized by an array
unsigned char tab[] = {1,2,3,4,5,6,7,8,9,10,11,12};
//create a GrayscaleImage initialized by an other container
std::vector<int> v(1200);
slip::GrayscaleImage<float> I5(30,40,v.begin(),v.end());
//create a GrayscaleImage by an other one
//use alias to create a float grayscale image
slip::GrayscaleImage_f I7(10,20,0.0f);
Print GrayscaleImage to terminal:
//print image to terminal using std::cout
std::cout<<"I1 = \n"<<I1<<std::endl;
//print image to terminal using print
slip::print(I1,"I1");
Read/Write GrayscaleImage from file:
//read an image from file
//For integer valued images, ImageMagick impose values of
//the image to be in the range [min(type),max(type)]
//where type is the integer type
I2.read("lena.gif");
//get image dimensions
const std::size_t rows = I2.rows();
const std::size_t cols = I2.cols();
//change dynamic to [0.0,1.0]
//ImageMagick impose float or double image to have values in [0.0,1.0]
//write I3 to file
I2.write("lena_f.png");
I2.write_ascii("lena_f.dat");
I4.read_ascii("lena.dat");
\encode
\subsection subsec_gray_affectation Assignements of a GrayscaleImage
\code
//create a 256x256 GrayscaleImage
//assign 10.0 to each element of the GrayscaleImage
I = 10.0;
//assign 12.0 to each element of the GrayscaleImage
I.fill(12.0);
//create a 3x4 GrayscaleImage
unsigned char tab[] = {1,2,3,4,5,6,7,8,9,10,11,12};
//fill a Grayscale Image with an array
I2.fill(tab);
//fill a GrayscaleImage with an other container
std::vector<int> v(256*256);
I.fill(v.begin(),v.end());
Access to the GrayscaleImage elements
//construct an unsigned char GrayscaleImage of
// heightxwidth = 256x256 which all elements are
//initialized to 128
//get image dimensions
const std::size_t height = I.height();
const std::size_t width = I.width();
//construct a grayscale image with same dimensions as I
slip::GrayscaleImage<float> Result(height,width);
//double loop to iterate values
for(std::size_t i = 0; i < height; ++i)
{
for(std::size_t j = 0; j < width; ++j)
{
//element access using double brackets
Result[i][j] = float(I[i][j] / 2);
// or using parenthesis
Result(i,j) = float(I(i,j) * 2);
}
}
//copy a range of GrayscaleImage in an other one
//define the row range: 1 element over 2 for image height
slip::Range<int> row_range(0,height-1,2);
//define the column range: 1 element over 2 for image width
slip::Range<int> col_range(0,width-1,2);
slip::GrayscaleImage<unsigned char> Irange = I(row_range,col_range);
Arithmetical operations on a GrayscaleImage
#include <iostream>
#include <slip/GrayscaleImage.hpp>
float divide_by_2(float val)
{
return val /2.0f;
}
int main()
{
MM = 5.5;
MM2 = 2.2;
//pointwise += operator equivalent to MM = MM + MM2
MM += MM2;
//pointwise -= operator equivalent to MM = MM - MM2
MM -= MM2;
//pointwise *= operator equivalent to MM = MM * MM2
MM *= MM2;
//pointwise /= operator equivalent to MM = MM / MM2
MM /= MM2;
//pointwise addition of two GrayscaleImage
MM3 = MM + MM2;
//right scalar addition
MM3 = MM + 2.0f;
//left scalar addition
MM3 = 2.0f + MM;
//pointwise subtraction of two GrayscaleImage
MM3 = MM - MM2;
//right scalar subtraction
MM3 = MM - 2.0f;
//left scalar subtraction
MM3 = 2.0f - MM;
//pointwise multiplies of two GrayscaleImage
MM3 = MM * MM2;
//right scalar multiplication
MM3 = MM * 2.0f;
//left scalar multiplication
MM3 = 2.0f * MM;
//pointwise division of two GrayscaleImage
MM3 = MM / MM2;
//right scalar division
MM3 = MM / 2.0f;
//negate a GrayscaleImage
MM3 = -MM2;
//pointwise += operator equivalent to MM2 = MM2 + 2.0f
MM2+=2.0f;
//pointwise -= operator equivalent to MM2 = MM2 - 2.0f
MM2-=2.0f;
//pointwise *= operator equivalent to MM2 = MM2 * 2.0f
MM2*=2.0f;
//pointwise /= operator equivalent to MM2 = MM2 / 2.0f
MM2/=2.0f;
//Compute the min value of MM2
std::cout<<MM2.min()<<std::endl;
//Compute the max value of MM2
std::cout<<MM2.max()<<std::endl;
//apply std::sqrt to all elements of MM2
MM2.apply(std::sqrt);
//apply a C-like function divide_by_2 to all elements of MM2
MM2.apply(divide_by_2);
return 0;
}
GrayscaleImage comparisons
slip::iota(M1.begin(),M1.end(),1);
slip::iota(M3.begin(),M3.end(),2,2);
if(M1 == M3)
{
std::cout<<"M1 egal M3"<<std::endl;
}
else
{
std::cout<<"M1 different M3"<<std::endl;
}
if(M1 != M2)
{
std::cout<<"M1 different M2"<<std::endl;
}
else
{
std::cout<<"M1 egal M2"<<std::endl;
}
Various way to iterate a GrayscaleImage
I1.read("lena.gif");
const std::size_t height = I1.height();
const std::size_t width = I1.width();
//----------------------------------------
// Global iterators
//----------------------------------------
//apply the function divide_by_2 from I1.begin() to I1.end()
//and put the result from Result.begin() to Result.begin()+I1.size()
slip::GrayscaleImage<float> Result(height,width);
std::transform(I1.begin(),I1.end(),Result.begin(),divide_by_2());
Result.write("lena_d2.gif");
//in the reverse order
//apply the function divide_by_2 from (I1.end()-1) to I1.begin()
//and put the result from Result2.begin() to Result2.begin()+I1.size()
slip::GrayscaleImage<float> Result2(height,width);
std::transform(I1.rbegin(),I1.rend(),Result2.begin(),divide_by_2());
Result2.write("lena_inv.gif");
//----------------------------------------
// Rows and columns iterators
//----------------------------------------
//computes the horizontal flip of I1
slip::GrayscaleImage<float> Hflip(height,width);
for(std::size_t i = 0; i < height; ++i)
{
std::copy(I1.row_begin(i),I1.row_end(i),Hflip.row_rbegin(i));
}
Hflip.write("Hflip.png");
//computes the vertical flip of I1
slip::GrayscaleImage<float> Vflip(height,width);
for(std::size_t j = 0; j < width; ++j)
{
std::copy(I1.col_begin(j),I1.col_end(j),Vflip.col_rbegin(j));
}
Vflip.write("Vflip.png");
//----------------------------------------
// Box iterators
//----------------------------------------
//define the image first quarter box
slip::Box2d<int> box(0,0,height/2-1,width/2-1);
//construct the box image
slip::GrayscaleImage<float> I1_box(height/2,width/2);
//copy element in the box to the box image
std::copy(I1.upper_left(box),I1.bottom_right(box),I1_box.upper_left());
//write box image on disk
I1_box.write("lena_box.png");
//----------------------------------------
// Range iterators
//----------------------------------------
//define the row range: 1 element over 2 for image height
slip::Range<int> row_range(0,height-1,2);
const std::size_t row_iterations = row_range.iterations();
//define the column range: 1 element over 2 for image width
slip::Range<int> col_range(0,width-1,2);
const std::size_t col_iterations = col_range.iterations();
//construct the range image (subsampled image)
slip::GrayscaleImage<float> I1_range(row_iterations+1,col_iterations+1);
std::copy(I1.upper_left(row_range,col_range),
I1.bottom_right(row_range,col_range),
I1_range.upper_left());
//write box image on disk
I1_range.write("lena_subsample.png");

Matrix mathematical funtions

slip::iota(M4.begin(),M4.end(),1.0,1.0);
std::cout<<"M4.min() = "<<M4.min()<<std::endl;
std::cout<<"M4.max() = "<<M4.max()<<std::endl;
std::cout<<"M4.sum() = "<<M4.sum()<<std::endl;
std::cout<<"M4.trace() = "<<M4.trace()<<std::endl;
std::cout<<"M4.det() = "<<M4.det()<<std::endl;
std::cout<<"M4.cond() = "<<M4.cond()<<std::endl;
std::cout<<"M4.rank() = "<<M4.rank()<<std::endl;
std::cout<<"M4.inv() = \n"<<M4.inv()<<std::endl;
std::cout<<"M4.L1_norm() = "<<M4.L1_norm()<<std::endl;
std::cout<<"M4.L2_norm() = "<<M4.L2_norm()<<std::endl;
std::cout<<"M4.infinite_norm() = "<<M4.infinite_norm()<<std::endl;
std::cout<<"M4.frobenius_norm() = "<<M4.frobenius_norm()<<std::endl;
std::cout<<"min(M4) = "<<min(M4)<<std::endl;
std::cout<<"max(M4) = "<<max(M4)<<std::endl;
M4.apply(std::sqrt);
std::cout<<"M4.apply(std::sqrt):\n"<<M4;
std::cout<<"abs(-M4) = \n"<<abs(-M4)<<std::endl;
std::cout<<"sqrt(M4) = \n"<<sqrt(M4)<<std::endl;
std::cout<<"cos(M4) = \n"<<cos(M4)<<std::endl;
std::cout<<"sin(M4) = \n"<<sin(M4)<<std::endl;
std::cout<<"tan(M4) = \n"<<tan(M4)<<std::endl;
std::cout<<"atan(M4) = \n"<<atan(M4)<<std::endl;
std::cout<<"exp(M4) = \n"<<exp(M4)<<std::endl;
std::cout<<"log(M4) = \n"<<log(M4)<<std::endl;
std::cout<<"cosh(M4) = \n"<<cosh(M4)<<std::endl;
std::cout<<"sinh(M4) = \n"<<sinh(M4)<<std::endl;
std::cout<<"tanh(M4) = \n"<<tanh(M4)<<std::endl;
std::cout<<"log10(M4) = \n"<<log10(M4)<<std::endl;

Multicomponent containers

Masked and predicated version of algorithms

Most of the algorithms have a masked and a predicated version:

iota: assigns sequentially increasing values to a range

Example 1:
//fill a matrix with 3 4 5...
slip::Matrix<int> Miota(4,5,0);
slip::iota(Miota.begin(),Miota.end(),3);
std::cout<<Miota<<std::endl;
//display the matrix
//3 4 5 6 7
//8 9 10 11 12
//13 14 15 16 17
//18 19 20 21 22
Example 2:
//fill a matrix with 0.0 0.05 0.10...
slip::Matrix<double> Miota(4,5,0.0);
slip::iota(Miota.begin(),Miota.end(),0.0,0.05);
std::cout<<Miota<<std::endl;
//display the matrix
//0 0.05 0.1 0.15 0.2
//0.25 0.3 0.35 0.4 0.45
//0.5 0.55 0.6 0.65 0.7
//0.75 0.8 0.85 0.9 0.95
Example 3:
slip::iota(VF.begin(),VF.end(),slip::Vector2d<double>(1.0,2.0),slip::Vector2d<double>(1.0,1.0));
std::cout<<VF<<std::endl;
//display the vector field
//init point: (0,0)
//grid step: (1,1)
//data:
//(1,2) (2,3)
//(3,4) (4,5)
//(5,6) (6,7)

Computes statistics on containers

The slip::statistics algorithms permit to computes the statistics on a range and to store them in the slip::Statistics container. In the following, we give examples of use of the algorithm.

#include <iostream>
#include <slip/ColorImage.hpp>
#include <slip/statistics.hpp>
#include <slip/Block.hpp>
#define N 10
template<typename T>
void myrand(T& a)
{
a = T((double)std::rand()/((double)RAND_MAX+1)*N);
}
int main()
{
typedef double T;
//------------------------------------
//init ColorImage with random values
//------------------------------------
std::for_each(I.begin(0),I.end(0),myrand<T>);
std::for_each(I.begin(1),I.end(1),myrand<T>);
std::for_each(I.begin(2),I.end(2),myrand<T>);
//------------------------------------
//Computes statistics on the red plane
//------------------------------------
slip::statistics(I.begin(0),I.end(0),Sred);
std::cout<<"----------------------"<<std::endl;
std::cout<<"red plane statistics: "<<std::endl;
std::cout<<"----------------------"<<std::endl;
std::cout<<"min = "<<Sred.min()<<std::endl;
std::cout<<"first_quartile = "<<Sred.first_quartile()<<std::endl;
std::cout<<"median = "<<Sred.median()<<std::endl;
std::cout<<"third_quartile = "<<Sred.third_quartile()<<std::endl;
std::cout<<"max = "<<Sred.max()<<std::endl;
std::cout<<"mean = "<<Sred.mean()<<std::endl;
std::cout<<"standard deviation = "<<Sred.std_dev()<<std::endl;
std::cout<<"skewness = "<<Sred.skewness()<<std::endl;
std::cout<<"kurtosis = "<<Sred.kurtosis()<<std::endl;
std::cout<<"cardinal = "<<Sred.cardinal()<<std::endl;
slip::block<double,10> all_red_stat = Sred.all();
slip::statistics(I.begin(1),I.end(1),Sgreen);
std::cout<<"----------------------"<<std::endl;
std::cout<<"green plane statistics: "<<std::endl;
std::cout<<"----------------------"<<std::endl;
std::cout<<"min = "<<Sgreen.min()<<std::endl;
std::cout<<"first_quartile = "<<Sgreen.first_quartile()<<std::endl;
std::cout<<"median = "<<Sgreen.median()<<std::endl;
std::cout<<"third_quartile = "<<Sgreen.third_quartile()<<std::endl;
std::cout<<"max = "<<Sgreen.max()<<std::endl;
std::cout<<"mean = "<<Sgreen.mean()<<std::endl;
std::cout<<"standard deviation = "<<Sgreen.std_dev()<<std::endl;
std::cout<<"skewness = "<<Sgreen.skewness()<<std::endl;
std::cout<<"kurtosis = "<<Sgreen.kurtosis()<<std::endl;
std::cout<<"cardinal = "<<Sgreen.cardinal()<<std::endl;
slip::block<double,10> all_green_stat = Sgreen.all();
slip::statistics(I.begin(2),I.end(2),Sblue);
std::cout<<"----------------------"<<std::endl;
std::cout<<"blue plane statistics: "<<std::endl;
std::cout<<"----------------------"<<std::endl;
std::cout<<"min = "<<Sblue.min()<<std::endl;
std::cout<<"first_quartile = "<<Sblue.first_quartile()<<std::endl;
std::cout<<"median = "<<Sblue.median()<<std::endl;
std::cout<<"third_quartile = "<<Sblue.third_quartile()<<std::endl;
std::cout<<"max = "<<Sblue.max()<<std::endl;
std::cout<<"mean = "<<Sblue.mean()<<std::endl;
std::cout<<"standard deviation = "<<Sblue.std_dev()<<std::endl;
std::cout<<"skewness = "<<Sblue.skewness()<<std::endl;
std::cout<<"kurtosis = "<<Sblue.kurtosis()<<std::endl;
std::cout<<"cardinal = "<<Sblue.cardinal()<<std::endl;
slip::block<double,10> all_blue_stat = Sblue.all();
return 0;
}

An intercorrelation example

//Motif construction
slip::Matrix<float> Motif(8,8,0.0);
slip::iota(Motif.begin(),Motif.end(),8.0,1.0);
//Image construction
slip::Matrix<float> I(128,128,0.0);
slip::iota(Motif.begin(),Motif.end(),0.0,1.0);
//Motif matching
slip::Matrix<float> Result(16,16,0.0);
const std::size_t rows = I.rows();
const std::size_t cols = I.cols();
slip::Box2d<int> box(0,0,7,7);
//-----------------------------------
// computes correlation map
//-----------------------------------
for(std::size_t i = 0; i < rows; i+=8)
{
for(std::size_t j = 0; j < cols; j+=8)
{
//update box coordinates
box.set_coord(i,j,i+7,j+7);
Result[i/8][j/8] =
slip::std_crosscorrelation<float>(I.upper_left(box),I.bottom_right(box),Motif.begin());
}
}
//---------------------------------------
//Get the maximum indices
//---------------------------------------
slip::Matrix<float> Matrix::iterator2d it =
std::max_element(Result.upper_left(),Result.bottom_right());
std::cout<<it->i()<<" "<<it->j()<<std::endl;