C language > Expert questions

Convolution function

(1/3) > >>

Grincheux:
Hello,

I am writing a convolution function but I am not sure to follow the good way.
Could you help me?


--- Code: ---typedef struct tagFILTRES_PERSO
{
    char            szName[64] ;
    int             ColsNumber ;
    int             Divisor ;
    int             Bias ;
    int             Matrix[3][3] ;
} FILTRES_PERSO, *LPFILTRES_PERSO ;

FILTRES_PERSO   Filtre  =   {"FX000000241",3,   1,  0,{  -7,   7,   0,  -7,  -7,   7,   2,  -2,   0}} ;

//  Image must be int 32 bits (Alpha, Red, Green, Blue)
//  Width and Height mut be > 16 pixels
//  The Divisor must not be equal to 0. If it is equal to 0, the function set it to 1.

int Convolve_3x3(int __iWidth,int __iHeight,LPBYTE __lpImageBits,LPFILTRES_PERSO __lpFiltre)
{
    LPBYTE  _lpxy1, _lpxy2, _lpxy3 ;
    LPBYTE  _lpTmp ;

    int     _Red, _Green, _Blue, _Rgb ;
    int     _x1, _x2, _x3, _y1, _y2, _y3 ;
    int     _x, _y, _xx, _yy ;
    int     _i, _j ;

    if(!__lpFiltre)                 return (FALSE) ;
    if(!__lpImageBits)              return (FALSE) ;

    if(__iWidth < 16)               return (FALSE) ;
    if(__iHeight < 16)              return (FALSE) ;

    if(__lpFiltre->Divisor == 0)
        __lpFiltre->Divisor = 1 ;

    _lpTmp = __lpImageBits ;

    _xx = 4 ;                                                // Column #1
    _yy = (__iWidth * 4) + 4 ;                      // Line #1

    _lpTmp += _xx ;

    for(_x = 1 ; _x < __iWidth - 2 ; _x++)
    {
        _x1 = _xx - 4 ;                                // X - 1    Offset 0    Previous column
        _x2 = _xx ;                                    // X        Offset 4    Current column
        _x3 = _xx + 4 ;                             // X + 1    Offset 8    Next column

        _xx += 4 ;

        for(_y = 1 ; _y < __iHeight - 2; _y++)
        {
            _y1 = (__iWidth * 4) * (_y - 1) ;         // Y - 1    Previous line
            _y2 = (__iWidth * 4) * _y ;                // Y        Current line
            _y3 = (__iWidth * 4) * (_y + 1) ;       // Y + 1    Next line

            _lpxy1 = _lpTmp + _x1 + _y1 ;
            _lpxy2 = _lpTmp + _x2 + _y2 ;
            _lpxy3 = _lpTmp + _x3 + _y3 ;

            _Red    = (((*_lpxy1) & 0x00FF0000) >> 16) + (((*_lpxy2) & 0x00FF0000) >> 16) + (((*_lpxy3) & 0x00FF0000) >> 16) ;
            _Green  = (((*_lpxy1) & 0x0000FF00) >>  8) + (((*_lpxy2) & 0x0000FF00) >>  8) + (((*_lpxy3) & 0x0000FF00) >>  8) ;
            _Blue   = (((*_lpxy1) & 0x000000FF)      ) + (((*_lpxy2) & 0x000000FF)      ) + (((*_lpxy3) & 0x000000FF)      ) ;

            for(_i = 0 ; _i < 3 ; _i++)
            {
                for(_j = 0 ; _j < 3 ; _j++)
                {
                    _Red    *=  __lpFiltre->Matrix[_i][_j] ;      //  Red * Coef
                    _Green  *=  __lpFiltre->Matrix[_i][_j] ;    //  Green * Coef
                    _Blue   *=  __lpFiltre->Matrix[_i][_j] ;     //  Blue * Coef
                }
            }

            _Red /= __lpFiltre->Divisor ;
            _Green /= __lpFiltre->Divisor ;
            _Blue /= __lpFiltre->Divisor ;

            if(_Red < 0)        _Red = 0 ;
            if(_Green < 0)     _Green = 0 ;
            if(_Blue < 0)       _Blue = 0 ;

            if(_Red > 255)      _Red = 255 ;
            if(_Green > 255)   _Green = 255 ;
            if(_Blue > 255)     _Blue = 255 ;

            _Rgb = (_Red << 16) | (_Green << 8) | _Blue ;
            *(_lpTmp + _x2 + _y2) = _Rgb ;
        }
    }

    return (TRUE) ;
}

-----------------
    Calling :       Convolve_3x3(_BitmapWidth,_BitmapHeight,_lpImageBits,&Filtre) ;
-----------------

--- End code ---

John Z:
;) no clue.  Is this purpose edge detection?  Seems comparable to edge detection in IrfanView which I use extensively.

John z

Grincheux:
Now I find the same results that XnView!
The problem was coming from the compiler.

I thought that I could compute the convolution like this :

--- Code: ---               _Red   =   (((*_lpx1y1 >> 16) & 255) * _c1) +
                        (((*_lpx2y1 >> 16) & 255) * _c2) +
                        (((*_lpx3y1 >> 16) & 255) * _c3) +
                        (((*_lpx1y2 >> 16) & 255) * _c4) +
                        (((*_lpx2y2 >> 16) & 255) * _c5) +
                        (((*_lpx3y2 >> 16) & 255) * _c6) +
                        (((*_lpx1y3 >> 16) & 255) * _c7) +
                        (((*_lpx2y3 >> 16) & 255) * _c8) +
                        (((*_lpx3y3 >> 16) & 255) * _c9) ;

--- End code ---

It was wrong, I had to compute the convolution like this:

--- Code: ---               _r1 = ((*_lpx1y1 >> 16) & 255) * _c1 ;
               _r2 = ((*_lpx2y1 >> 16) & 255) * _c2 ;
               _r3 = ((*_lpx3y1 >> 16) & 255) * _c3 ;
               _r4 = ((*_lpx1y2 >> 16) & 255) * _c4 ;
               _r5 = ((*_lpx2y2 >> 16) & 255) * _c5 ;
               _r6 = ((*_lpx3y2 >> 16) & 255) * _c6 ;
               _r7 = ((*_lpx1y3 >> 16) & 255) * _c7 ;
               _r8 = ((*_lpx2y3 >> 16) & 255) * _c8 ;
               _r9 = ((*_lpx3y3 >> 16) & 255) * _c9 ;

               _Red = _r1 + _r2 + _r3 + _r4 + _r5 + _r6 + _r7 + _r8 + _r9 ;

               if(_Red < 0)   _Red = 0 ;
               if(_Red > 255)   _Red = 255;

--- End code ---

For me, it is a bug into the C Compiler Mr Pelle.

The final source code is:

--- Code: ---int Convolve_3x3(int __iWidth,int __iHeight,LPBYTE __lpImageBits,LPFILTRES_PERSO __lpFiltre,int __iApplyDivisor,int __iChannelRed,int __iChannelGreen,int __iChannelBlue)
{
   LPDWORD   _lpx1y1, _lpx1y2, _lpx1y3, _lpx2y1, _lpx2y2, _lpx2y3, _lpx3y1, _lpx3y2, _lpx3y3 ;
   LPDWORD   _lpTmp ;

   int      _Red, _Green, _Blue ;
   int      _c1, _c2, _c3, _c4, _c5, _c6, _c7, _c8, _c9 ;
   int      _r1, _r2, _r3, _r4, _r5, _r6, _r7, _r8, _r9 ;
   int      _g1, _g2, _g3, _g4, _g5, _g6, _g7, _g8, _g9 ;
   int      _b1, _b2, _b3, _b4, _b5, _b6, _b7, _b8, _b9 ;
   DWORD   _iChannel ;
   int      _x1, _x2, _x3, _y1, _y2, _y3, _Rgb ;
   int      _x, _y, _xx ;

   if(!__lpFiltre)               return (FALSE) ;
   if(!__lpImageBits)            return (FALSE) ;

   if(__iWidth < 16)            return (FALSE) ;
   if(__iHeight < 16)            return (FALSE) ;

   if((__iApplyDivisor < 0) || (__iApplyDivisor > 1))   return (FALSE) ;

   if((__iChannelRed < 0)   || (__iChannelRed > 1))   return (FALSE) ;
   if((__iChannelGreen < 0) || (__iChannelGreen > 1))   return (FALSE) ;
   if((__iChannelBlue < 0)  || (__iChannelBlue > 1))   return (FALSE) ;

   _iChannel = 0 ;

   if(__iChannelRed)   _iChannel |= 1 ;
   if(__iChannelGreen)   _iChannel |= 2 ;
   if(__iChannelBlue)   _iChannel |= 4 ;

   _c1 = __lpFiltre->Matrix[0][0] ;      // Y1 X1
   _c2 = __lpFiltre->Matrix[0][1] ;      // Y1 X2
   _c3 = __lpFiltre->Matrix[0][2] ;      // Y1 X3
   _c4 = __lpFiltre->Matrix[1][0] ;      // Y2 X1
   _c5 = __lpFiltre->Matrix[1][1] ;      // Y2 X2
   _c6 = __lpFiltre->Matrix[1][2] ;      // Y2 X3
   _c7 = __lpFiltre->Matrix[2][0] ;      // Y3 X1
   _c8 = __lpFiltre->Matrix[2][1] ;      // Y3 X2
   _c9 = __lpFiltre->Matrix[2][2] ;      // Y3 X3

   __lpFiltre->Divisor = 0 ;

   if(__iApplyDivisor)
   {
      __lpFiltre->Divisor += _c1 ;
      __lpFiltre->Divisor += _c2 ;
      __lpFiltre->Divisor += _c3 ;
      __lpFiltre->Divisor += _c4 ;
      __lpFiltre->Divisor += _c5 ;
      __lpFiltre->Divisor += _c6 ;
      __lpFiltre->Divisor += _c7 ;
      __lpFiltre->Divisor += _c8 ;
      __lpFiltre->Divisor += _c9 ;

      __lpFiltre->Divisor /= 9 ;
   }

   if(__lpFiltre->Divisor == 0)
      __lpFiltre->Divisor = 1 ;

   _Red = _Green = _Blue = _Rgb = 0 ;

   _lpTmp = (LPDWORD) __lpImageBits ;

   _lpTmp++ ;

   _xx = 1 ;                                 // Column #1

   for(_x = 1 ; _x < __iWidth - 2 ; _x++)
   {
      _x1 = _xx - 1 ;                           // X - 1   Offset 0   Previous column
      _x2 = _xx ;                              // X      Offset 4   Current column
      _x3 = _xx + 1 ;                           // X + 1   Offset 8   Next column

      _xx++ ;

      for(_y = 1 ; _y < __iHeight - 2 ; _y++)
      {
         _y1 = __iWidth * (_y - 1) ;               // Y - 1   Previous line
         _y2 = __iWidth * _y ;                  // Y      Current line
         _y3 = __iWidth * (_y + 1) ;               // Y + 1   Next line

         _lpx1y1 = _lpTmp + _x1 + _y1 ;            // C1   X1,Y1
         _lpx1y2 = _lpTmp + _x1 + _y2 ;            // C4   X1,Y2
         _lpx1y3 = _lpTmp + _x1 + _y3 ;            // C7   X1,Y3

         _lpx2y1 = _lpTmp + _x2 + _y1 ;            // C2   X2,Y1
         _lpx2y2 = _lpTmp + _x2 + _y2 ;            // C5   X2,Y2
         _lpx2y3 = _lpTmp + _x2 + _y3 ;            // C8   X2,Y3

         _lpx3y1 = _lpTmp + _x3 + _y1 ;            // C3   X3,Y3
         _lpx3y2 = _lpTmp + _x3 + _y2 ;            // C6   X3,Y2
         _lpx3y3 = _lpTmp + _x3 + _y3 ;            // C9   X3,Y3

         if(__lpFiltre->Divisor == 1)
         {
            if(__iChannelRed)
            {
               _r1 = ((*_lpx1y1 >> 16) & 255) * _c1 ;
               _r2 = ((*_lpx2y1 >> 16) & 255) * _c2 ;
               _r3 = ((*_lpx3y1 >> 16) & 255) * _c3 ;
               _r4 = ((*_lpx1y2 >> 16) & 255) * _c4 ;
               _r5 = ((*_lpx2y2 >> 16) & 255) * _c5 ;
               _r6 = ((*_lpx3y2 >> 16) & 255) * _c6 ;
               _r7 = ((*_lpx1y3 >> 16) & 255) * _c7 ;
               _r8 = ((*_lpx2y3 >> 16) & 255) * _c8 ;
               _r9 = ((*_lpx3y3 >> 16) & 255) * _c9 ;

               _Red = _r1 + _r2 + _r3 + _r4 + _r5 + _r6 + _r7 + _r8 + _r9 ;

               if(_Red < 0)   _Red = 0 ;
               if(_Red > 255)   _Red = 255;
            }

            if(__iChannelGreen)
            {
               _g1 = ((*_lpx1y1 >>  & 255) * _c1 ;
               _g2 = ((*_lpx2y1 >>  & 255) * _c2 ;
               _g3 = ((*_lpx3y1 >>  & 255) * _c3 ;
               _g4 = ((*_lpx1y2 >>  & 255) * _c4 ;
               _g5 = ((*_lpx2y2 >>  & 255) * _c5 ;
               _g6 = ((*_lpx3y2 >>  & 255) * _c6 ;
               _g7 = ((*_lpx1y3 >>  & 255) * _c7 ;
               _g8 = ((*_lpx2y3 >>  & 255) * _c8 ;
               _g9 = ((*_lpx3y3 >>  & 255) * _c9 ;

               _Green = _g1 + _g2 + _g3 + _g4 + _g5 + _g6 + _g7 + _g8 + _g9 ;

               if(_Green < 0)      _Green = 0 ;
               if(_Green > 255)   _Green = 255;
            }

            if(__iChannelBlue)
            {
               _b1 = (*_lpx1y1 & 255) * _c1 ;
               _b2 = (*_lpx2y1 & 255) * _c2 ;
               _b3 = (*_lpx3y1 & 255) * _c3 ;
               _b4 = (*_lpx1y2 & 255) * _c4 ;
               _b5 = (*_lpx2y2 & 255) * _c5 ;
               _b6 = (*_lpx3y2 & 255) * _c6 ;
               _b7 = (*_lpx1y3 & 255) * _c7 ;
               _b8 = (*_lpx2y3 & 255) * _c8 ;
               _b9 = (*_lpx3y3 & 255) * _c9 ;

               _Blue = _b1 + _b2 + _b3 + _b4 + _b5 + _b6 + _b7 + _b8 + _b9 ;

               if(_Blue < 0)   _Blue = 0 ;
               if(_Blue > 255)   _Blue = 255;
            }
         }
         else
         {
            if(__iChannelRed)
            {
               _r1 = (((*_lpx1y1 >> 16) & 255) * _c1) / __lpFiltre->Divisor ;
               _r2 = (((*_lpx2y1 >> 16) & 255) * _c2) / __lpFiltre->Divisor ;
               _r3 = (((*_lpx3y1 >> 16) & 255) * _c3) / __lpFiltre->Divisor ;
               _r4 = (((*_lpx1y2 >> 16) & 255) * _c4) / __lpFiltre->Divisor ;
               _r5 = (((*_lpx2y2 >> 16) & 255) * _c5) / __lpFiltre->Divisor ;
               _r6 = (((*_lpx3y2 >> 16) & 255) * _c6) / __lpFiltre->Divisor ;
               _r7 = (((*_lpx1y3 >> 16) & 255) * _c7) / __lpFiltre->Divisor ;
               _r8 = (((*_lpx2y3 >> 16) & 255) * _c8) / __lpFiltre->Divisor ;
               _r9 = (((*_lpx3y3 >> 16) & 255) * _c9) / __lpFiltre->Divisor ;

               _Red = _r1 + _r2 + _r3 + _r4 + _r5 + _r6 + _r7 + _r8 + _r9 ;

               if(_Red < 0)   _Red = 0 ;
               if(_Red > 255)   _Red = 255;
            }

            if(__iChannelGreen)
            {
               _g1 = (((*_lpx1y1 >>  & 255) * _c1) / __lpFiltre->Divisor ;
               _g2 = (((*_lpx2y1 >>  & 255) * _c2) / __lpFiltre->Divisor ;
               _g3 = (((*_lpx3y1 >>  & 255) * _c3) / __lpFiltre->Divisor ;
               _g4 = (((*_lpx1y2 >>  & 255) * _c4) / __lpFiltre->Divisor ;
               _g5 = (((*_lpx2y2 >>  & 255) * _c5) / __lpFiltre->Divisor ;
               _g6 = (((*_lpx3y2 >>  & 255) * _c6) / __lpFiltre->Divisor ;
               _g7 = (((*_lpx1y3 >>  & 255) * _c7) / __lpFiltre->Divisor ;
               _g8 = (((*_lpx2y3 >>  & 255) * _c8) / __lpFiltre->Divisor ;
               _g9 = (((*_lpx3y3 >>  & 255) * _c9) / __lpFiltre->Divisor ;

               _Green = _g1 + _g2 + _g3 + _g4 + _g5 + _g6 + _g7 + _g8 + _g9 ;

               if(_Green < 0)      _Green = 0 ;
               if(_Green > 255)   _Green = 255;
            }

            if(__iChannelBlue)
            {
               _b1 = ((*_lpx1y1 & 255) * _c1) / __lpFiltre->Divisor ;
               _b2 = ((*_lpx2y1 & 255) * _c2) / __lpFiltre->Divisor ;
               _b3 = ((*_lpx3y1 & 255) * _c3) / __lpFiltre->Divisor ;
               _b4 = ((*_lpx1y2 & 255) * _c4) / __lpFiltre->Divisor ;
               _b5 = ((*_lpx2y2 & 255) * _c5) / __lpFiltre->Divisor ;
               _b6 = ((*_lpx3y2 & 255) * _c6) / __lpFiltre->Divisor ;
               _b7 = ((*_lpx1y3 & 255) * _c7) / __lpFiltre->Divisor ;
               _b8 = ((*_lpx2y3 & 255) * _c8) / __lpFiltre->Divisor ;
               _b9 = ((*_lpx3y3 & 255) * _c9) / __lpFiltre->Divisor ;

               _Blue = _b1 + _b2 + _b3 + _b4 + _b5 + _b6 + _b7 + _b8 + _b9 ;

               if(_Blue < 0)   _Blue = 0 ;
               if(_Blue > 255)   _Blue = 255;
            }
         }

         switch(_iChannel)
         {
            case   0 :   _Rgb = 0 ;                                 break ;
            case   1 :   _Rgb = (_Red   << 16) | (_Red   << | _Red ;      break ;
            case   2 :   _Rgb = (_Green << 16) | (_Green << | _Green ;   break ;
            case   3 :   _Rgb = (_Red   << 16) | (_Green << ;            break ;
            case   4 :   _Rgb = (_Blue  << 16) | (_Blue  << | _Blue ;      break ;
            case   5 :   _Rgb = (_Red   << 16) | _Blue ;                  break ;
            case   6 :   _Rgb = (_Green <<  | _Blue ;                  break ;
            case   7 :   _Rgb = (_Red   << 16) | (_Green << | _Blue ;      break ;
         }

         *(_lpTmp + _x1 + _y1) = _Rgb ;
      }
   }

   return (TRUE) ;
}

--- End code ---

Rather making the sum, it it possible to compute the MAX, the MIN, the AVERAGE.

When computing a SOBEL filter, you call the function with your filter then the filter must be changed as follow before calling again the function.

*** BEFORE ***

--- Code: ---   _c1 = __lpFiltre->Matrix[0][0] ;      // Y1 X1
   _c2 = __lpFiltre->Matrix[0][1] ;      // Y1 X2
   _c3 = __lpFiltre->Matrix[0][2] ;      // Y1 X3
   _c4 = __lpFiltre->Matrix[1][0] ;      // Y2 X1
   _c5 = __lpFiltre->Matrix[1][1] ;      // Y2 X2
   _c6 = __lpFiltre->Matrix[1][2] ;      // Y2 X3
   _c7 = __lpFiltre->Matrix[2][0] ;      // Y3 X1
   _c8 = __lpFiltre->Matrix[2][1] ;      // Y3 X2
   _c9 = __lpFiltre->Matrix[2][2] ;      // Y3 X3

--- End code ---
*** AFTER ***

--- Code: ---   _c1 = __lpFiltre->Matrix[0][0] ;      // Y1 X1
   _c4 = __lpFiltre->Matrix[0][1] ;      // Y1 X2
   _c7 = __lpFiltre->Matrix[0][2] ;      // Y1 X3
   _c2 = __lpFiltre->Matrix[1][0] ;      // Y2 X1
   _c5 = __lpFiltre->Matrix[1][1] ;      // Y2 X2
   _c8 = __lpFiltre->Matrix[1][2] ;      // Y2 X3
   _c3 = __lpFiltre->Matrix[2][0] ;      // Y3 X1
   _c6 = __lpFiltre->Matrix[2][1] ;      // Y3 X2
   _c9 = __lpFiltre->Matrix[2][2] ;      // Y3 X3

THEN DO

   __lpFiltre->Matrix[0][0] = _c1 ;      // Y1 X1
   __lpFiltre->Matrix[0][1] = _c2;      // Y1 X2
   __lpFiltre->Matrix[0][2] = _c3;      // Y1 X3
   __lpFiltre->Matrix[1][0] = _c4;      // Y2 X1
   __lpFiltre->Matrix[1][1] = _c5 ;      // Y2 X2
   __lpFiltre->Matrix[1][2] = _c6 ;      // Y2 X3
   __lpFiltre->Matrix[2][0] = _c7 ;      // Y3 X1
   __lpFiltre->Matrix[2][1] = _c8 ;      // Y3 X2
   __lpFiltre->Matrix[2][2] = _c9 ;      // Y3 X3

--- End code ---

Grincheux:
I forgot to show the result.


John Z:
Wow, well you persevered and achieved desired results...

Could it be that part of the problem is this warning in the help file?

--- Quote --- Note! Do not select names for identifiers that begin with two underscores, or with an underscore followed by an uppercase letter. The C standard allows identifier names that begin with these character combinations to be reserved for compiler use.

--- End quote ---

 _Red   <=  underscore followed by an uppercase letter …..
int      _Red, _Green, _Blue ; //

So it may be working accidentally right now.....

 John Z

Navigation

[0] Message Index

[#] Next page

Go to full version