3

可能是菜鸟问题。我希望使用 CImg 库对图像进行一些处理。它们中的一些可能是(8 位)和其中一些(16 位)的类型。不幸的是,在用户不选择要处理的文件之前,我不知道数据的类型。当然我可以这样做:

...  
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);  
...

但是 99% 的 CImg 方法对于“unsigned char”、“int”或“float”类型(例如“load_raw”或“blur”)看起来完全相同。有什么方法可以制作 - 我不知道 - 指针?- 所以当用户选择文件时,我可以制作魔法:

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(...); 
4

3 回答 3

1

如果类模板CImg<T>有父类,你当然可以这样做。但是您会发现,您可以在不知道像素类型的情况下执行的一组操作仅限于加载和保存之类的操作。为了对图像内容进行操作,您需要保留具体的图像对象。

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);
};
于 2013-04-10T19:55:39.987 回答
1

类模板的许多方法都CImg依赖于T参数,因此即使将非依赖操作抽象为超类,使用该库的许多代码部分最终也会依赖于该类型。接口的很大一部分似乎使用了Tfloat数据类型,因此可能有一种方法可以使 suoerclass 仅具有非依赖方法,这在某种程度上可能是可用的。

也许以下方法可以工作:

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( /* ... */ );
    }
};

但正如您所见,实现很繁琐,因为它需要重新定义所有接口。此外,每个方法最终都会是虚拟的,这会在运行时产生影响(也许这就是实现者没有创建超类的原因)。

处理该问题的另一种可能方法是使您的应用程序的每个算法都在该类型上具有多态性,并将最依赖的部分分割成特定的类,这些类将用作您的算法的模板参数(有点像分配器、比较器和std 库模板的其他可配置部分作为这些模板的参数)。

于 2013-04-10T20:42:31.213 回答
1

感谢“madcoder”和“didierc”。我发现你的两个答案都非常有用。我最终得到这样的结果:

#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();
}

因为这个程序的输出是:

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

我不认为虚函数是我的性能问题(据我所知,'didierc' 如果我会进行大量调用,这将是问题吗?)。这个解决方案是否以某种方式“可以接受”,或者由于某种我现在看不到的原因我不应该这样做?

于 2013-04-11T12:12:26.663 回答