Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Why does this supposed to smooth function in C fail?
#11
Thanks!!! BTW, what are the equivalents of UBOUND and LBOUND in c?
y smiley is 24 bit.
[Image: anya2.jpg]

Genso's Junkyard:
http://rel.betterwebber.com/
Reply
#12
Quote:Thanks!!! BTW, what are the equivalents of UBOUND and LBOUND in c?
In C the lower bound is always zero. sizeof will give you the number of bytes allocated for the array (doesn't work for dynamic arrays, then it just gives you the size of the pointer itself). From there you can divide by the element size to get the number of elements. Subtract one and you've got your UBOUND.

There's no easier way that I know of, its because C doesn't keep track of or check array bounds. The compiler will allow this even though it will probably crash:
Code:
int array[10];
array[5000] = 1234;
Reply
#13
Yeah, I was about to say, just divide them before you add.

It's kind of interesting, I've been doing actual photo filter work in my digital signal processing class. They don't smooth at all, but they convolute (like multiplying polynomial) each row array to create different filters. So with the same routine you could blur an image or undo a blur, or turn it all kinds of funky colors.
Reply
#14
I noticed Jofers, I made an image module myself in C++. To be technically, Rel's blur function is incorrect, as it uses pre-pixel-pre-calculated data to blur the image.

Here's my blur function:
[syntax="C"]unsigned char* cImage::blur (unsigned char* imgData, int imgWidth, int imgHeight, short blurSize)
{
/*------------------------------------------------------------------\
| blur |
| |
| Blurs an image according to float blurFactor. The higher this nr, |
| the more the image will be blurred. It must be > 0. This routine |
| is affected by the current edit mode. |
| |
| IMAGE_EDITMODE_UPDATE: |
| Old image will be deleted and a pointer to the new image will be |
| returned. |
| IMAGE_EDITMODE_NEW: |
| Old image will remain intact while a pointer to the new image is |
| returned. |
\------------------------------------------------------------------*/
// make a pointer to new image
unsigned char* retPointer;
// calculate amount of bytes in image
unsigned long imgSize = imgWidth * imgHeight * vFormatSize[vDefFormat];
// calculate amount of pixels in blur unit
int blurunit = (blurSize * 2 + 1) * (blurSize * 2 + 1);

// allocate new image
retPointer = (unsigned char*)malloc( imgSize );
assert( retPointer != NULL );

// storage buffer to hold all pixels around destination pixel
unsigned char storageBuffer[4] = { 0, 0, 0, 0 };
// the sums of each color in the 9 pixel block
int sums[4] = { 0, 0, 0, 0 };

/* OK, now here's the algorithm of the blur method I used (width e.g. BlurSize = 1)
first we get all nine surrounding pixels of the pixel we want to blur

123
456
789

In which 5 is the pixel we want to blur (the middle/center one). We get all colour values of these 9 pixels
and store them into the storageBuffer array. (36 = 9 * 4 bytes, when using RGBA format, else we have some spare bytes).
Then we compare each of the nine pixels with the center one, and calculate the differences between these pixels and sum
them into the sums array. After we summed all pixels, we divide the sums by 9 so that we get the average difference of
this nine pixel block. This average is exactly what we need because the center pixel should be corrected with
this difference to blur it.

*/
/* EDIT: I had to edit the code because the old algo was a bit unefficient. Now no more differences, just averages */

// a loop to go by all pixels of the image
for (int loopX=0;loopX<imgWidth;loopX++)
{
for (int loopY=0;loopY<imgHeight;loopY++)
{
// clear buffer
memset( sums, 0, 4 * sizeof(int) );

// get all surrounding pixels and store them in buffer
for (short difX=-blurSize;difX<=blurSize;difX++)
{
for (short difY=-blurSize;difY<=blurSize;difY++)
{
// of course only when on the image
if ( (loopX+difX>=0) && (loopY+difY>=0) && (loopX+difX<imgWidth) && (loopY+difY<imgHeight) )
{
memcpy( storageBuffer, imgData + (loopY + difY) * imgWidth * vFormatSize[vDefFormat] + (loopX + difX) * vFormatSize[vDefFormat], vFormatSize[vDefFormat] );
sums[0] += storageBuffer[0];
sums[1] += storageBuffer[1];
sums[2] += storageBuffer[2];
sums[3] += storageBuffer[3];
}
}
}

// average
storageBuffer[0] = (unsigned char)int((float)sums[0] / (float)blurunit);
storageBuffer[1] = (unsigned char)int((float)sums[1] / (float)blurunit);
storageBuffer[2] = (unsigned char)int((float)sums[2] / (float)blurunit);
storageBuffer[3] = (unsigned char)int((float)sums[3] / (float)blurunit);

// copy the write pixel information
memcpy( retPointer + loopY * imgWidth * vFormatSize[vDefFormat] + loopX * vFormatSize[vDefFormat], storageBuffer, vFormatSize[vDefFormat] );

}
}

// if update image then delete old image
if ( vEditMode == IMAGE_EDITMODE_UPDATE )
{
free( imgData );
imgData = NULL;
}

// return pointer to new blurred image
return retPointer;
}[/syntax]


Rel, if you're interested in more of my image functions, I'd happily share them with you (just PM me Wink)
Reply
#15
I've realized that the best blur is got using convolution with a 3x3 matrix. You can use integer math and it flies (much faster than using floats).

Matrix:
Code:
|1 1 1|
|1 1 1| * 1/9
|1 1 1|

Basicly, for each pixel at (x,y) in the resulting image you add the colours at (x-1, y-1), (x, y-1), (x, y+1), (x-1, y), (x, y), (x+1, y), (x-1, y+1), (x, y+1) and (x+1, y+1) in an integer variable, then divide by 9 and you can store the result in an unsigned char.

Of course you have to deal with the pixels in the edges and corners differently, as the whole matrix can't be applied there.

Dividing before adding causes precission loss if you are using integer math.
SCUMM (the band) on Myspace!
ComputerEmuzone Games Studio
underBASIC, homegrown musicians
[img]http://www.ojodepez-fanzine.net/almacen/yoghourtslover.png[/i
Reply
#16
It's the same algorithm I applied in my blur code Tongue Only in my blur code, the user is able to specify the size of the matrix.

I use floats in the code to make sure there are no round-off errors, because when you divide unsigned chars by unsigned chars, you get an unsigned char, which may sometimes be 0 even though both other chars are positive. I use the floor() function to prevent this.

The algorithm of my code isn't based on dividing before adding. I first sum up all red, green, blue and alpha components of the matrix, then divide it by the number of pixels in the matrix to get the average blurred components.
Reply
#17
Actually that blur code is just for testing. :*)
The blur code I use(now converted to C) is the blurcode I use in relsmooth.asm
:*)


BTW, I just made some 3d routines and some GFX routines. No asm, just plain C code. :*) Man C is fast!!!
y smiley is 24 bit.
[Image: anya2.jpg]

Genso's Junkyard:
http://rel.betterwebber.com/
Reply
#18
Quote:
relsoft Wrote:Thanks!!! BTW, what are the equivalents of UBOUND and LBOUND in c?
In C the lower bound is always zero. sizeof will give you the number of bytes allocated for the array (doesn't work for dynamic arrays, then it just gives you the size of the pointer itself). From there you can divide by the element size to get the number of elements. Subtract one and you've got your UBOUND.

There's no easier way that I know of, its because C doesn't keep track of or check array bounds. The compiler will allow this even though it will probably crash:
Code:
int array[10];
array[5000] = 1234;

so:

Code:
long e = sizeof(array);
int nume = s/sizeof(int or long or blah) - 1;
would work?

How about dynamic arrays declared with malloc?
y smiley is 24 bit.
[Image: anya2.jpg]

Genso's Junkyard:
http://rel.betterwebber.com/
Reply
#19
Quote:Actually that blur code is just for testing. :*)
The blur code I use(now converted to C) is the blurcode I use in relsmooth.asm
:*)
Is it the same algorithm as I posted above in my C++ code? (because that one doesn't get average stacking faults).

Rel: If my C++ compiler worked, I could just look up the answer to your question Sad

Quote:
Code:
int array[10];
array[5000] = 1234;
In QB, this is also possible Wink
Reply
#20
mine is a pretty staightforward sampling technique. :*) No, fancy stuff, but it works nonthless. :*)
y smiley is 24 bit.
[Image: anya2.jpg]

Genso's Junkyard:
http://rel.betterwebber.com/
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)