A good way to implement mutual conversion of user-defined classes?



  • Shade Of Mine schrieb:

    ... conversation ...

    Pretty sure you meant conversions? 🙂 Besides, I totally agree.



  • hustbaer schrieb:

    I'd like to know what those types are. Without that knowledge one can only speculate as to what would be the best way to do things.

    You are right. I need to convert colors from one color space to another. This needs to be done very fast.

    Color is something like that:

    template<idColorFormat CF, idColorComponentType CT> struct tColor;
    

    idColorFormat is something like cfRGB , cfBGR , cfGrayscale , cfIndexed .
    idColorComponentType is something like ctUChar , ctUShort , ctUInt , ctFloat , ctDouble .

    I have already done all possible conversions of colors from one pair of parameters <CF,CT> to any other pair. The idea is that tColor contain 3 or 1 components inside:

    template<idColorComponentType CT> tColorComponent;
    
    template<idColorComponentType CT> tColor<cfRGB,CT>
    {
      tColorComponent<CT> r,g,b;
      ...
    };
    

    So, the conversion operators of tColor deal with different idColorFormat , while tColorComponent deal with different idColorComponentType .

    So (if omit cfIndexed ), I need (3*3-3)+(5*5-5) = 6+20 conversion operators. And I have done this.

    The problem is that I need to go further, and make color space conversion. I decided to use ONLY cfRGB color format for such conversions. Color space is something like that:

    enum idColorSpace{csCIEXYZ,    //CIE 1931 XYZ color space. X,Y,Z values are stored in R,G,B respectively
                      csSRGBLinear, //sRGB Linear color space
                      csSRGB,      //sRGB color space
                      csCIELAB};  //CIE 1976 LAB color space. L,A,B values are stored in G,R,B respectively
    
    template<idColorSpace T> struct tColorSpace{}; //To store idColorSpace as compile-time constant to use function overloading instead of template specialization.
    

    I think conversion functions should look like that:

    template<idColorComponentType CT1, idColorComponentType CT2, idColorSpace CS1, idColorSpace CS2>
      inline void ConvertColor(tColor<cfRGB,CT1> const &c1, tColor<cfRGB,CT2> &c2, tColorSpace<CS1>, tColorSpace<CS2>, bool clip);
    

    Notice that I perform color space conversion at the same time as color component type conversion. This is very important to be able to do some optimizations (such as using of tables).



  • SAn schrieb:

    But how to make this? I need to write something like that:

    template<class T = tMyType4 or tMyType5> inline void Convert(tMyType1 const &vInput, T &vOutput)
    { ... }
    

    you could use a traits-template (like std::iterator_traits).



  • example:

    class CA {};
    class CB {};
    class CC {};
    class CD {};
    class CE {};
    
    namespace hidden
    {
    	struct float_cat {};
    	struct other_cat {};
    
    	// assign categories (concepts) to the userdefined classes
    	template < class T > struct traits {};
    	template <> struct traits<CA> { typedef other_cat cat; };
    	template <> struct traits<CB> { typedef other_cat cat; }; 
    	template <> struct traits<CC> { typedef other_cat cat; }; 
    	template <> struct traits<CD> { typedef float_cat cat; }; 
    	template <> struct traits<CE> { typedef float_cat cat; };
    
    	template < class A, class B, class CAT > void convert( A const &a, B &b, CAT c );
    
    	// specialized template-instances for category float_cat ...
    	template < class B > void convert( CA const &a, B &b, float_cat c ) { TEST; }
    	template < class B > void convert( CB const &a, B &b, float_cat c ) { TEST; }
    	template < class B > void convert( CC const &a, B &b, float_cat c ) { TEST; }
    
    	// ...and other_cat
    	void convert( CA const &a, CB &b, other_cat c ) { TEST; }
    	void convert( CA const &a, CC &b, other_cat c ) { TEST; }
    
    	/*...*/
    }
    
    template < class T > void convert( T const& a, T &b ) { b = a; }
    
    // call the right function by passing a dummy-instance of type traits::cat
    template < class A, class B > void convert( A const& a, B &b )
    { hidden::convert( a, b, typename hidden::traits<B>::cat() ); }
    

    man verzeihe mein englisch...
    ... und dass ich tatsächlich 5 klassen deklariert hab...



  • I don't have much time to think about this right now, but you could have a look at GIL:
    http://www.boost.org/doc/libs/1_36_0/libs/gil/doc/index.html

    Maybe you could use it directly, or maybe you find some clever idea in there that you could borrow 🙂



  • hustbaer schrieb:

    I don't have much time to think about this right now, but you could have a look at GIL:
    http://www.boost.org/doc/libs/1_36_0/libs/gil/doc/index.html

    Maybe you could use it directly, or maybe you find some clever idea in there that you could borrow 🙂

    Very interesting! In fact, I'm not familiar with Boost, Iterators and other such things. So, I need something simplier. But I will look at color conversion there...



  • Do you have one instance of your class per pixel? I think this will be much overhead.



  • asdfgfvsd schrieb:

    Do you have one instance of your class per pixel? I think this will be much overhead.

    C++ classes do not have any overhead in particular compared to C-structs or plain old data types. They are more or less syntactic sugar, if you do not use (dynamic) polymorphism. The compiler takes care of optimizations. I think this is called the "zero cost" principle of C++.



  • I think normally int or float arrays are used to represent the pixels of an image. I have never seen an array of classes to store pixles.
    Will this have the same speed?

    std::vector<int> pixels;
    ...
    for(...)
         pixels[pos+0] = r;
         pixels[pos+1] = g;
         pixels[pos+2] = b;
    
    std::vector<PixelClass> pixels;
    ...
    for(...)
         pixels[pos].r = r;
         pixels[pos].g = g;
         pixels[pos].b = b;
    


  • Will this have the same speed?

    Nothing is ever the same.
    But both solutions should be close.

    It all depends on what the compiler will optimize better, and of course on what alignment the compiler will be using for the RGB-struct. And probably a dozen other little things.



  • wandrer schrieb:

    example:

    [...]

    man verzeihe mein englisch...
    ... und dass ich tatsächlich 5 klassen deklariert hab...

    Thank you! This is exactly what I need.

    In fact, I already have traits of 3 types in my libriary:

    enum idColorComponentFamily { ccfUnsignedInteger, ccfSignedInteger, ccfFloatingPoint };
    

    I just could't figure out how to use that until I have seen your example.

    Now I will do that way: ccfUnsignedInteger  — depend of type, ccfSignedInteger  — forbidden, because signed integers are special cases, ccfFloatingPoint  — use the same algorithm for both float and double .



  • asdfgfvsd schrieb:

    I think normally int or float arrays are used to represent the pixels of an image. I have never seen an array of classes to store pixles.
    Will this have the same speed?

    std::vector<int> pixels;
    ...
    for(...)
         pixels[pos+0] = r;
         pixels[pos+1] = g;
         pixels[pos+2] = b;
    
    std::vector<PixelClass> pixels;
    ...
    for(...)
         pixels[pos].r = r;
         pixels[pos].g = g;
         pixels[pos].b = b;
    

    Yes, this will have the same speed for most cases.


Anmelden zum Antworten