3

おそらくnoobの質問です。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);  
...

しかし、CImg メソッドの 99% は、'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

「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 に答える
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( /* ... */ );
    }
};

しかし、ご覧のとおり、すべてのインターフェースを再定義する必要があるため、実装は面倒です。また、すべてのメソッドは最終的に仮想化され、実行時に影響を与えます (これが、実装者がスーパークラスを作成しなかった理由かもしれません)。

この問題を処理するもう 1 つの方法は、アプリケーションのすべてのアルゴリズムをその型のポリモーフィックとして作成し、最も依存する部分をアルゴリズムのテンプレート引数として使用される特定のクラスにスライスすることです (アロケータ、コンパレータ、およびstd ライブラリ テンプレートのその他の構成可能な部分は、これらのテンプレートの引数になります)。

于 2013-04-10T20:42:31.213 に答える