user2267612
user2267612

Reputation: 41

Templates. No type know during compile time

Probably noob question. I wish to use CImg library to make some processing of images. How ever some of them may be type of (8 bit) and some of them (16 bit). Unfortunately I don't know the type of data until user don't pick file to process. Of course I can do like this:

...  
CImg <unsigned char> img_unisgned_char;  
CImg <unsigned short> img_unisgned_short;  
...  
if (user_pick_8bit) img_unisgned_char.load_raw(fname,img_size_x,img_size_y);  
if (user_pick_16bit) img_unisgned_short.load_raw(fname,img_size_x,img_size_y);  
...

But 99% of CImg methods looks exactly the same for 'unsigned char','int' or 'float' type (like 'load_raw' or 'blur' for example). Is there any way to make - I don't know - pointer? - so when user pick the file I can make magic like:

if (user_pick_8_bit) img = img_unisgned_char;  
if (user_pick_16bit) img = img_unisgned_short;  
... 
//now no mother of what type is picked up by user I simply make:  
img.load_raw(...); 

Upvotes: 3

Views: 199

Answers (3)

user2267612
user2267612

Reputation: 41

Thanks "madcoder" and "didierc". I found both your answers quite useful. I end up with something like this:

#include <CImg.h>
#include <conio.h>
#include <stdio.h>
#include <windows.h>

using namespace cimg_library;

class cimg_base
{
 public:
 virtual int load_bmp(const char *const filename) = 0;
 virtual int save_bmp (const char *const filename) = 0;
 virtual void blur (const float sigma) = 0;
 virtual void sharpen (const float amplitude) = 0;
};

class cimg_unsigned_char : public cimg_base
{
 CImg <unsigned char> img;
 int load_bmp (const char *const filename) { img.load_bmp(filename); return 0;}
 int save_bmp (const char *const filename) { img.save_bmp(filename); return 0;}
 void blur (const float sigma) { img.blur(sigma); }
 void sharpen (const float amplitude) { img.sharpen(amplitude); };
};

class cimg_unsigned_short : public cimg_base
{
 CImg <unsigned short> img;
 int load_bmp (const char *const filename) { img.load_bmp(filename); return 0;}
 int save_bmp (const char *const filename) { img.save_bmp(filename); return 0;}
 void blur (const float sigma) { img.blur(sigma); }
 void sharpen (const float amplitude) { img.sharpen(amplitude); };
};


void main(void)
{
 cimg_base *data;

 LARGE_INTEGER lpFrequency;
 LARGE_INTEGER lpPerformanceCountStart, lpPerformanceCountEnd;
 double Frequency,Start,End;

 // no matter witch line is used - progrm work as expected
 data = new cimg_unsigned_char;
 //data = new cimg_unsigned_short;

 data->load_bmp("test.bmp");
 //measure time with virtual
 QueryPerformanceFrequency(&lpFrequency);
 QueryPerformanceCounter(&lpPerformanceCountStart);

 data->blur(2.2f);
 data->sharpen(2.2f);

 QueryPerformanceCounter(&lpPerformanceCountEnd);
 Frequency = (double)lpFrequency.QuadPart;
 End = (double)lpPerformanceCountEnd.QuadPart;
 Start = (double)lpPerformanceCountStart.QuadPart;
 printf_s("Time (virtual):%lf ms\n",((End - Start) / Frequency)*1000);
 data->save_bmp("output_virt.bmp");

 CImg <unsigned char> img;
 img.load_bmp("test.bmp");

 QueryPerformanceCounter(&lpPerformanceCountStart);

 img.blur(2.2f);
 img.sharpen(2.2f);

 QueryPerformanceCounter(&lpPerformanceCountEnd);
 printf_s("Time (normal):%lf ms\n",((End - Start) / Frequency)*1000);
 img.save_bmp("output_normal.bmp");


 _getch();
}

since output of this program is:

Time (virtual):93.705392 ms
Time (normal):93.705392 ms

I don't think virtual functions are my performance problem (as I understand 'didierc' it will be the problem if I will make huge amount of calls?). Is this solution is somehow "acceptable" or I should not go this way for some reason I don't see now?

Upvotes: 1

didierc
didierc

Reputation: 14730

Many methods of the CImg class template depend on the T parameter, so even if non dependent operations were abstracted to a superclass, many parts of code using the library would end up depending on that type too anyway. A significant portion of the interface seems to use the Tfloat datatype, so there might be a way to make a suoerclass having only non dependent methods, which could be useable somewhat.

Perhaps the following could work:

class SuperCimg  {
 public:
    // expose the non dependent methods as virtual pure
    virtual Tfloat linear_atX( /* ... */ ) = 0;
    // etc.
};

template <typename T>
class DependentCimg : public virtual SuperCimg, public virtual Cimg<T> {
   // expose the needed constructors and methods
   public:
   Tfloat linear_atX( /* ... */) {
        return Cimg<T>::linear_atX( /* ... */ );
    }
};

But as you can see, the implementation is tedious, since it requires to redefine all the interface. Also, every method will end up being virtual, which will have an impact at run time (maybe this is the reason why implementors did not make a superclass).

Another possible way of handling the problem is to make every algorithms of your application as polymorphic on that type, and slice the most dependent parts out to specific classes which would be used as template arguments to your algorithms (a bit like allocator, comparator, and others configurable parts of the std library templates are made arguments of these templates).

Upvotes: 1

madcoder
madcoder

Reputation: 49

You certainly can do that if class template CImg<T> has a parent class. But you will find that the set of actions you can take without knowing the pixel type is limited to things like load and save. In order to operate on the image contents you will need to keep the concrete image objects around.

class CImgBase
{
    // Functions that do not reference the pixel type can go here.
    virtual void load_raw(...) = 0;  // agnostic of pixel type
};

// CImg implements CImgBase interface
template<typename T>
class CImg : public CImgBase
{
    void load_raw(...);
    T get_pixel(int x, int y);
};

Upvotes: 1

Related Questions