# Blur and sharpen a bitmap

Show 80 post(s) from this thread on one page
Page 1 of 2 12 Last
• 03-07-2005
Mikro
Blur and sharpen a bitmap
Is there a tutorial or an algorithm that describes how you implement a blur or sharpen function for bitmaps in standard C++.
I am not talking about Microsoft or UNIX stuff but independent stuff.

I know how to rotate, darken, invert and resize a bitmap image.

• 03-07-2005
Sang-drax
Blur shouldn't be that hard. Just create a new image where every pixel is the mean of all surrounding pixels in the original image.

Here's a page that explains how to implement a blur or sharpen filter:
http://www.gamedev.net/reference/art...rticle1994.asp
• 03-07-2005
Sang-drax
You could implement the sharpen filter something like this:
Code:

```void sharpenImage(Image& input, Image& output) {   for x = 1 ... width   for y = 1 ... height   {     output[x,y] = 5*input[x,y] - input[x+1,y] - input[x-1,y]                           - input[x,y+1] - input[x,y-1];   } }```
But it'd probably be better to write a more general kind of filter function, which supports more kinds of filters (given in matrix form).
• 03-08-2005
Mikro
Code:

```void sharpen() {     int sharpen[3][3] = {{0, -1, 0}, {-1, 5, -1}, {0, -1, 0}};     bitmap2.initFromBMP("test.bmp");    // Reads the bitmap file     for(int i=0; i < bitmap2.getHeight(); i++)         for(int j=0; j < bitmap2.getWidth(); j++)               for (int k = 0; k < 3; k++)                   for (int l = 0; l < 3; l++)                   {                       Pixel p = bitmap2.getCopyOfPixel(i,j); // Gets the pixel from the specific position.                       p.r = p.r * sharpen[k][l];  // Color red                       p.g = p.g * sharpen[k][l];  // Color green                       p.b = p.b * sharpen[k][l];  // Color blue                       bitmap2.setPixel(i,j,p);      // Inserts the pixel at the right place.                   } }```
It just returns a black image. I know I am doing something wrong.
• 03-08-2005
Sang-drax
>>I know I am doing something wrong.

Yes.

1. You should add the different components from the filter together.

2. You must create a new image instead of processing the original. Otherwise it won't work.

3. The values returned from the filter won't be in the 0..255 interval. You need to normalize the values.

4. Try doing it with a black&white image first.
• 03-09-2005
Mikro
Code:

```void MyImageProcessingApp::sharpen() {     bitmap1.initFromBMP("test.bmp");  // Reads the Bitmap file     t = new Bitmap(bitmap1.getHeight(), bitmap1.getWidth()); // Dynamically createas an empty Bitmap     int sumr;     int sumg;     int sumb;     int sharpen[3][3] = {{0,-1,0}, {-1,5,-1}, {0,-1,0}}; // The sharpen filter     Pixel color;     unsigned char r;     unsigned char g;     unsigned char b;     for (int i = 1; i < bitmap1.getHeight() - 1; i++)     {           for (int j = 1; j < bitmap1.getWidth() - 1; j++)           {         for (int k = 0; k < 3; k++)         {               for (int l = 0; l < 3; l++)               {                   color = bitmap1.getCopyOfPixel(i, j); // gets an individual pixel                   r = color.r;                   g = color.g;                   b = color.b;                   sumr += r * sharpen[k][l];                   sumg += g * sharpen[k][l];                   sumb += b * sharpen[k][l];             }         }         color.r = sumr;         color.g = sumg;         color.b = sumb;                                 t->setPixel(i, j, color);  // Inserts the pixel           }     } }```
Now I get result but the whole image is a mess big time and I still don't understand why. I am sure it is very simple to fix it, but.....
• 03-09-2005
VirtualAce
Code:

``` struct RGBA {   BYTE red;   BYTE green;   BYTE blue;   BYTE alpha; }; float BInterp(float v1,float v2,float v3,float v4,float f1,float f2) {   asm {     sub  esp,8     fld [v2]     fsub [v1]     fmul [f1]     fadd [v1]     fstp [esp-4]     fld [v4]     fsub [v3]     fmul [f1]     fadd [v3]     fstp [esp-8]     fld [esp-8]     fsub [esp-4]     fmul [f2]     fadd [esp-4]     add esp,8     } } void FilterImage(RGBA **pOutImage,RGBA *pInImage,DWORD dwWidth,DWORD dwHeight,float fFilterCoef) {     *pOutImage=new RGBA[dwHeight*dwWidth];     RGBA *ptrOutImage=*pOutImage;       for (DWORD i=0;i<dwHeight-1;i++)   {       for (DWORD j=0;j<dwWidth-1;j++)       {         DWORD offset1=i*dwWidth+j;         DWORD offset2=offset1+1;         DWORD offset3=offset1+dwWidth;         DWORD offset4=offset3+1;               RGBA finalcolor;         RGBA1=pInImage[offset1];         RGBA2=pInImage[offset2];         RGBA3=pInImage[offset3];         RGBA4=pInImage[offset4];         finalcolor.red=BI(RGBA1.red,                               RGBA2.red,                               RGBA3.red,                               RGBA4.red,                               fFilterCoef,                               fFilterCoef);         finalcolor.green=BI(RGBA1.green,                               RGBA2.green,                               RGBA3.green,                               RGBA4.green,                               fFilterCoef,                               fFilterCoef);         finalcolor.blue=BI(RGBA1.blue,                               RGBA2.blue,                               RGBA3.blue,                               RGBA4.blue,                               fFilterCoef,                               fFilterCoef);         finalcolor.alpha=BI(RGBA1.alpha,                             RGBA2.alpha,                             RGBA3.alpha,                             RGBA4.alpha,                             fFilterCoef,                             fFilterCoef);         ptrOutImage[offset1] =finalcolor;       }   } }```
Not the fastest code in the world, but it will do a bilinear filter on any 32-bit true color image, including the alpha channel. fFilterCoef should always satisfy 0<x<1.
• 03-10-2005
Mikro
Bubba thanks but what I am trying to do is a solution that is close to standard C++ as much as it can be. I am aware of getCopyOfPixel() and setPixel() are not standard. It feels like I have hit the wall with this one.
• 03-10-2005
MrWizard
Quote:

Originally Posted by Mikro
Code:

```void MyImageProcessingApp::sharpen() {     bitmap1.initFromBMP("test.bmp");  // Reads the Bitmap file     t = new Bitmap(bitmap1.getHeight(), bitmap1.getWidth()); // Dynamically createas an empty Bitmap     int sumr;     int sumg;     int sumb;     int sharpen[3][3] = {{0,-1,0}, {-1,5,-1}, {0,-1,0}}; // The sharpen filter     Pixel color;     unsigned char r;     unsigned char g;     unsigned char b;     for (int i = 1; i < bitmap1.getHeight() - 1; i++)     {           for (int j = 1; j < bitmap1.getWidth() - 1; j++)           {         for (int k = 0; k < 3; k++)         {               for (int l = 0; l < 3; l++)               {                   color = bitmap1.getCopyOfPixel(i, j); // gets an individual pixel                   r = color.r;                   g = color.g;                   b = color.b;                   sumr += r * sharpen[k][l];                   sumg += g * sharpen[k][l];                   sumb += b * sharpen[k][l];             }         }         color.r = sumr;         color.g = sumg;         color.b = sumb;                                 t->setPixel(i, j, color);  // Inserts the pixel           }     } }```
Now I get result but the whole image is a mess big time and I still don't understand why. I am sure it is very simple to fix it, but.....

First of all, you keep calling getCopyOfPixel(i, j) or whatever. That's the same pixel you are sampling every time! You need to sample the correct pixel as if the matrix was overlying on top of your pixels. You also need to keep an additional sum variable to store the values from the matrix. So if you matrix was

[0 1 0]
[1 0 1]
[0 1 0]

the value for the new sum of the matrix would be 4. Just a simple line of code is all that takes:

Code:

`ksum += Kernel[krow][kcol];`
or whatever your variable names are.

Then, after your matrix loop, you set your pixel to (sum / ksum) for each r,g,b component respectively. Hopefully that makes sense to you.
• 03-11-2005
Mikro
Code:

```void MyImageProcessingApp::sharpen() {     bmp->initFromBMP("test.bmp");     Pixel **matrix = new Pixel*[bmp->getHeight()];     for (int i = 0; i < bmp->getHeight(); i++)         matrix[i] = new Pixel[bmp->getWidth()];     t = new Bitmap(bmp->getHeight(), bmp->getWidth()); // Dynamically createas an empty Bitmap     int sumr = 0;     int sumg = 0;     int sumb = 0;     int sharpsum = 0;     int sharpen[3][3] = {{0,-1,0}, {-1,5,-1}, {0,-1,0}}; // The sharpen filter     unsigned char r;     unsigned char g;     unsigned char b;     for (int i = 0; i < 3; i++)         for (int j = 0; j < 3; j++)                 sharpsum += sharpen[i][j];     for (int i = 1; i < bmp->getHeight() - 1; i++)         for (int j = 1; j < bmp->getWidth() - 1; j++)                 matrix[i][j] = bmp->getCopyOfPixel(i, j); // gets an individual pixel and insert it at position i, j in the matrix.     for (int i = 1; i < bmp->getHeight() - 1; i++)         for (int j = 1; j < bmp->getWidth() - 1; j++)         {                 for (int k = 0; k < 3; k++)                 {                         for (int l = 0; l < 3; l++)                         {                                 sumr += matrix[i][j].r * sharpen[k][l];                                 sumg += matrix[i][j].g * sharpen[k][l];                                 sumb += matrix[i][j].b * sharpen[k][l];                         }                 }                 matrix[i][j].r = sumr / sharpsum;                 matrix[i][j].g = sumg / sharpsum;                 matrix[i][j].b = sumb / sharpsum;                                         t->setPixel(i, j, matrix[i][j]);  // Inserts the pixel         } }```
Still I am unable to get this function to work.
• 03-11-2005
MrWizard
You still are not doing what I was originally saying. Also, why do you have a matrix now that you fill? This is unnecessary.

Also, what are you going to do about the corners of your image? You can't ignore them.

Take this filter for example:

columns numbered 0,1,2
rows numbered 0,1,2

[0 1 0]
[1 1 1]
[0 1 0]

ksum = 5 for this filter. Let's run through pixel filtering pixel at (0,0).

you would make pixel (0,0) correspond to the center of your matrix (i.e. col #1 row #1).

assume row and col are filter loop indices and x and y are image loop indices. You should try going from -1 to 1 on your filter indices rather than 0 to 3, makes life easier. Perform bounds checking before you access pixels that are off the image.

Psuedo-code
Code:

```for y = 0 to height   for x = 0 to width     for row = -1 to 1       for col = -1 to 1         if((y + row) >= 0 && (y + row) < height)           if((x + col) >= 0 && (x + col) < width)             sum += filter[row + 1][col + 1] * pixel(x + i, y + j)             ksum += filter[row + 1][col + 1];           end if          end if       end for     end for     setpixel(x, y, sum / ksum); // check for div 0   end for end for```
You should be doing something like that. Don't just take this code and use it, understand why it works and then write it yourself.
• 03-11-2005
Perspective
also make sure you reset the variables that are collecting the sums!
• 03-11-2005
VirtualAce
Thiose filters are just averaging nearby pixels. The bilinear filter will produce better results.
• 03-12-2005
Mikro
Huh, I didn't manage to get this thing to work so I asked two of my friends if they were able to pull it off and neiter of them succeded. I am beginning to wonder if there is something wrong with the complier or the library.

I would be very greatfull if somebody could check the files that I am working with and I have uploaded the project here,
http://www.angelfire.com/theforce2/sgisun/bmp.zip

OS: Windows 2000 sp4
CPU: AMD Athlon64
Compiler: MS Visual Studio.net 2003
• 03-12-2005
MrWizard
Quote:

Originally Posted by Bubba
Thiose filters are just averaging nearby pixels. The bilinear filter will produce better results.

What? If you are referring to my filter I used in my example then you should know it was just for educational purposes. He already knew the filter he was going to use so I just picked arbitrary numbers. He originally asked how to sharpen and blur an image. I believe he means by way of a convolution kernel. Which is way more flexible than "bilinear filtering".

OP:
I'll look at your source at some point and get back to you.

Found your problem. You have the line:

Code:

`p = bmp->getCopyOfPixel(x, y);`
To retrieve a pixel from the source image but you are using the wrong variable. You need to use:

Code:

`p = bitmap.getCopyOfPixel(x, y);`
Also make sure to reset rsum, gsum, bsum, ksum all to 0 after you set the pixel in the destination image so they are ready for the next pass. This should at least get you in the right direction.
Show 80 post(s) from this thread on one page
Page 1 of 2 12 Last