Re: Stuck with design & template
Fabio Fracassi wrote:
On 10 Sep., 19:05, mast4as <mast...@yahoo.com> wrote:
Hi everyone
I am trying to design some code but can't seem to find the best way of
doing this. Basically I am trying to create an image class. The class
has 4 member variables, the number of channels (how many planes define
the image, for example if it's a B&W image m_numChannels = 1 & if it's
an RGB image then m_numChannels = 3). There's also its width, height
and finally a pointer to the data (stored as float).
Have you evaluated existing image processing libraries? There are some
very sophisticated libraries out there which solve this exact problem
(and probably quite some others which you haven't even considered
yet.)
Take a look at boost GIL (http://www.boost.org/doc/libs/1_40_0/libs/
gil/doc/index.html look at the Tutorial and Design Pages) and VIGRA
(http://hci.iwr.uni-heidelberg.de/vigra/).
If nothing else it will give you the answers you need to design your
own class.
HTH
Fabio
Might want to take a look at the image implementation in ITK while
you're at it (www.itk.org).
I found something like this worked alright for 2D image stuff, for what
it's worth (apologies for the slightly lengthy code dump):
/**
This class represents 8-bit pixels.
*/
class Pixel8
{
private:
unsigned char m_data;
public:
// Note: Pixel types must be default constructible to make blank
// image construction easy.
Pixel8() : m_data(0) {}
Pixel8(unsigned char data) : m_data(data) {}
Pixel8(int data) { set_from_int(data); }
Pixel8& operator=(unsigned char data)
{
m_data = data;
return *this;
}
Pixel8& operator=(int data)
{
set_from_int(data);
return *this;
}
operator const unsigned char() const
{ return m_data; }
bool operator==(const Pixel8& rhs) const
{ return m_data == rhs.m_data; }
static int maximum()
{ return 255; }
static int minimum()
{ return 0; }
private:
void set_from_int(int data)
{
if(data < 0) data = 0;
else if(data > 255) data = 255;
m_data = static_cast<unsigned char>(data);
}
};
/**
This class represents 24-bit RGB pixels.
*/
class Pixel24
{
private:
unsigned char m_r, m_g, m_b;
public:
// Note: Pixel types must be default constructible to make blank
// image construction easy.
Pixel24() : m_r(0), m_g(0), m_b(0) {}
Pixel24(unsigned char r, unsigned char g, unsigned char b)
: m_r(r), m_g(g), m_b(b)
{}
bool operator==(const Pixel24& rhs) const
{
return m_r == rhs.m_r && m_g == rhs.m_g && m_b == rhs.m_b;
}
const unsigned char r() const { return m_r; }
const unsigned char g() const { return m_g; }
const unsigned char b() const { return m_b; }
};
//~~~~~
/**
This class template allows users to create images with a pixel type of
their choosing. Several simple pixel types, such as 8-bit and 24-bit
pixels, are provided as a starting point.
*/
template <typename Pixel>
class Image
{
protected:
typedef shared_ptr<Image> Image_Ptr;
typedef shared_ptr<const Image> Image_CPtr;
public:
typedef Pixel Pixel;
protected:
int m_width, m_height;
Image()
: m_width(0), m_height(0)
{}
public:
Image(int width, int height)
: m_width(width), m_height(height)
{}
virtual ~Image() {}
virtual const Pixel operator()(int n) const = 0;
virtual const Pixel operator()(int x, int y) const = 0;
virtual void set(int n, const Pixel& pixel) = 0;
virtual void set(int x, int y, const Pixel& pixel) = 0;
int height() const { return m_height; }
int width() const { return m_width; }
};
typedef Image<class Pixel8> Image8;
typedef Image<class Pixel24> Image24;
typedef shared_ptr<Image8> Image8_Ptr;
typedef shared_ptr<const Image8> Image8_CPtr;
typedef shared_ptr<Image24> Image24_Ptr;
typedef shared_ptr<const Image24> Image24_CPtr;
//~~~~~
/**
This class template provides a simple implementation of Image.
*/
template <typename Pixel>
class SimpleImage : public Image<Pixel>
{
private:
shared_array<Pixel> m_pixels;
public:
SimpleImage(int width, int height);
SimpleImage(Pixel *pixels, int width, int height);
SimpleImage(const shared_array<Pixel>& pixels, int width, int height);
explicit SimpleImage(const Image_CPtr& rhs);
private:
SimpleImage(const SimpleImage&);
SimpleImage& operator=(const SimpleImage&);
public:
const Pixel operator()(int n) const;
const Pixel operator()(int x, int y) const;
void set(int n, const Pixel& pixel);
void set(int x, int y, const Pixel& pixel);
};
typedef SimpleImage<Pixel8> SimpleImage8;
typedef SimpleImage<Pixel24> SimpleImage24;
//~~~~~
/**
Constructs a blank SimpleImage with the specified width and height.
@param width The width of the image to construct
@param height The height of the image to construct
*/
template <typename Pixel>
SimpleImage<Pixel>::SimpleImage(int width, int height)
: Image(width, height)
{
int size = width * height;
Pixel *pixels = new Pixel[size](); // <-- Note that this *default
constructs* every Pixel in the array.
m_pixels.reset(pixels);
}
/**
Constructs a SimpleImage from the specified pixel data, which should be
interpreted as being an image of size width * height, laid out in rows
in memory.
@param pixels A pointer to the start of the pixel data
@param width The width of the source image
@param height The height of the source image
*/
template <typename Pixel>
SimpleImage<Pixel>::SimpleImage(Pixel *pixels, int width, int height)
: Image(width, height), m_pixels(pixels)
{}
/**
Constructs a SimpleImage from the specified pixel data, which should be
interpreted as being an image of size width * height, laid out in rows
in memory.
@param pixels The pixel data as a shared_array
@param width The width of the source image
@param height The height of the source image
*/
template <typename Pixel>
SimpleImage<Pixel>::SimpleImage(const shared_array<Pixel>& pixels, int
width, int height)
: Image(width, height), m_pixels(pixels)
{}
/**
Constructs a SimpleImage from another image with the same pixel type
(note that this is effectively a more useful version of what would be
the copy constructor).
@param rhs The image to copy
*/
template <typename Pixel>
SimpleImage<Pixel>::SimpleImage(const Image_CPtr& rhs)
: Image(rhs->width(), rhs->height())
{
int size = m_width * m_height;
Pixel *pixels = new Pixel[size];
for(int i=0; i<size; ++i) pixels[i] = rhs(i);
m_pixels.reset(pixels);
}
template <typename Pixel>
const Pixel SimpleImage<Pixel>::operator()(int n) const
{
return m_pixels[n];
}
template <typename Pixel>
const Pixel SimpleImage<Pixel>::operator()(int x, int y) const
{
return m_pixels[y*m_width+x];
}
template <typename Pixel>
void SimpleImage<Pixel>::set(int n, const Pixel& pixel)
{
m_pixels[n] = pixel;
}
template <typename Pixel>
void SimpleImage<Pixel>::set(int x, int y, const Pixel& pixel)
{
m_pixels[y*m_width+x] = pixel;
}
Cheers,
Stu