Trying to figure out a better design for this!
Consider that we have a template Image class that inherits from a template matrix library (in this case Eigen but it could be anything)
template <typename T>
class Image : public Eigen::Matrix <T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
Now think of the case that we want to write a function to handle reading images from a file. Of course images can be of different types, i.e. unisnged char, uint16_t, float and even have different channels as in grayscale, RGB or even RGBA.
So we could have of course template classes to easily handle this.As in
Image<RGB<unisgned char>> or Image<RGBA<float>>
Its simple when one knows the type of the image, say monochrome 8bit
Image<unisgned char> image = ReadImage(const char* const filename);
or it could even be
Image<unisgned char> image;
bool b = ReadImage(const char* const filename, Image<unisgned char>& image)
However when reading an image file we never know the type prior to reading the image.For example Tiff and png both support 8bit and 16 bit with tiff even supporting float. In such cases its impossible to use any of the functions mentioned above. However, we can have a temmplate Factory class to sort that out.
For that we first need to introduce a BaseImage class
class BaseImage
{
public:
inline BaseImage() {};
virtual inline ~BaseImage() {};
virtual inline int Width() const = 0;
virtual inline int Height() const = 0;
virtual inline int Depth() const = 0;
etc...
};
template <typename T>
class Image : public BaseImage, public Eigen::Matrix <T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
Then we can have our factory class where we pass our unsigned char*, float*, etc.. and let it handle the creation
class ImageFactory
{
typename <T>
static BaseImage* createImage(const T* const src, const int& width, const int& height, const int& depth)
{
if (depth == 1)
{
return new Image<T>();
}
else if (depth == 3)
{
return new Image<RGB<T>>();
}
etc...
}
}
Of course this forces me to use dynamic allocation and inheritance.
I guess I can get around the dynamic allocation by hiding it inside a class that takes care of it. In the constructor the factory clas will be called
class Image2
{
public:
Image2(const char* const path)
{
// where ReadImage and external function that will call ImageFactory
pBaseImage = ReadImage(path);
}
~Image2();
private:
BaseImage* pBaseImage;
};
In either case my BaseImage class will have to expose all the functionality that I need to use from my matrix library which kinda defies the purpose of inheriting.
The question is then if there is a better design than could be used here cause its becoming quite cumbersome
I'd post this as a comment if I could show code in a comment ... to me, this seems obvious enough, and you probably thought of it. Why isn't it what you're looking for?
class Image
{
public:
Image (int bytesPerPixelIn = 1) { data_ = NULL; bytesPerPixel=bytesPerPixelIn;};
void readImage (int width, int height);
private:
int bytesPerPixel_;
void* data_;
};
void Image::read (int width, int height, ...)
{
data_ = new unsigned char [width*height*pixelSize(imageType_)];
//...
}
//And you can inherit from this if need be to add special functions
//like interleaving in BMP files
Edit: OK, I see. Would this serve better?
template <typename PixelType>
class Image
{
public:
Image () { data_ = NULL; };
virtual void allocateImage (int width, int height)
{
data_ = new PixelType [width*height];
}
virtual void readImage (int width, int height) = 0;
private:
PixelType* data_;
};
template <typename PixelType>
class ImageTIFF: public Image <PixelType> ...
or this:
template <typename PixelType, int WIDTH, int HEIGHT>
class Image
{
public:
Image () { }
virtual void readImage () = 0;
private:
PixelType* data_ [WIDTH][HEIGHT];
};
template <typename PixelType, int WIDTH, int HEIGHT>
class ImageTIFF: public Image <PixelType, WIDTH, HEIGHT> ...
The latter eliminates dynamic memory... but without dynamic memory, you can't have a resize function. I'd use dynamic memory.
You'll need inheritance for different file formats, surely, as they don't read images the same way.
--
OK. How about this? BaseImage here is like a Java "interface," and will ensure that the derived classes have the functions they'll need.
class BaseImage
{
public:
virtual void allocateImage (int width, int height) = 0;
virtual void readImage (int width, int height) = 0;
};
template <typename PixelType>
class Image: public BaseImage ... /* and so on */
BaseImage* myTIFFImage = readTIFFImage (/* whatever goes here */);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With