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 :
_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) ;
It was wrong, I had to compute the convolution like this:
_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;
For me, it is a bug into the C Compiler Mr Pelle.
The final source code is:
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) ;
}
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 ***
_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
*** AFTER ***
_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