
Overview
Welcome back for the second installment in this series. This installment serves as an introduction to the world of convolution filters. It is also the first version of our program that offers one level of undo. We'll build on that later, but for now I thought it mandatory that you be able to undo your experiments without having to reload the image every time.
So what is a convolution filter ? Essentially, it's a matrix, as follows:

The idea is that the pixel we are processing, and the eight that surround it, are each given a weight. The total value of the matrix is divided by a factor, and optionally an offset is added to the end value. The matrix above is called an identity matrix, because the image is not changed by passing through it. Usually the factor is the value derived from adding all the values in the matrix together, which ensures the end value will be in the range 0-255. Where this is not the case, for example, in an embossing filter where the values add up to 0, an offet of 127 is common. I should also mention that convolution filters come in a variety of sizes, 7x7 is not unheard of, and edge detection filters in particular are not symmetrical. Also, the bigger the filter, the more pixels we cannot process, as we cannot process pixels that do not have the number of surrounding pixels our matrix requires. In our case, the outer edges of the image to a depth of one pixel will go unprocessed.
A Framework
First of all we need to establish a framework from which to write these filters, otherwise we'll find ourselves writing the same code over and again. As our filter now relies on surrounding values to get a result, we are going to need a source and a destination bitmap. I tend to create a copy of the bitmap coming in and use the copy as the source, as it is the one getting discarded in the end. To facilitate this, I define a matrix class as follows:
public class ConvMatrix
{
public int TopLeft = 0, TopMid = 0, TopRight = 0;
public int MidLeft = 0, Pixel = 1, MidRight = 0;
public int BottomLeft = 0, BottomMid = 0, BottomRight = 0;
public int Factor = 1;
public int Offset = 0;
public void SetAll(int nVal)
{
TopLeft = TopMid = TopRight = MidLeft = Pixel = MidRight =
BottomLeft = BottomMid = BottomRight = nVal;
}
}
I'm sure you noticed that it is an identity matrix by default. I also define a method that sets all the elements of the matrix to the same value.
The pixel processing code is more complex than our last article, because we need to access nine pixels, and two bitmaps. I do this by defining constants for jumping one and two rows ( because we want to avoid calculations as much as possible in the main loop, we define both instead of adding one to itself, or multiplying it by 2 ). We can then use these values to write our code. As our initial offset into the different color is 0, 1, and 2, we end up with 3 and 6 added to each of those values to create indices for three pixels across, and use our constants to add the rows. In order to ensure we don't have any values jumping from the bottom of the image to the top, we need to create one int, which is used to calculate each pixel value, then clamped and stored. Here is the entire function:
public static bool Conv3x3(Bitmap b, ConvMatrix m)
{
if (0 == m.Factor)
return false; Bitmap
bSrc = (Bitmap)b.Clone();
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb);
BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height),
ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
int stride2 = stride * 2;
System.IntPtr Scan0 = bmData.Scan0;
System.IntPtr SrcScan0 = bmSrc.Scan0;
unsafe {
byte * p = (byte *)(void *)Scan0;
byte * pSrc = (byte *)(void *)SrcScan0;
int nOffset = stride - b.Width*3;
int nWidth = b.Width - 2;
int nHeight = b.Height - 2;
int nPixel;
for(int y=0;y < nHeight;++y)
{
for(int x=0; x < nWidth; ++x )
{
nPixel = ( ( ( (pSrc[2] * m.TopLeft) +
(pSrc[5] * m.TopMid) +
(pSrc[8] * m.TopRight) +
(pSrc[2 + stride] * m.MidLeft) +
(pSrc[5 + stride] * m.Pixel) +
(pSrc[8 + stride] * m.MidRight) +
(pSrc[2 + stride2] * m.BottomLeft) +
(pSrc[5 + stride2] * m.BottomMid) +
(pSrc[8 + stride2] * m.BottomRight))
/ m.Factor) + m.Offset);
if (nPixel < 0) nPixel = 0;
if (nPixel > 255) nPixel = 255;
p[5 + stride]= (byte)nPixel;
nPixel = ( ( ( (pSrc[1] * m.TopLeft) +
(pSrc[4] * m.TopMid) +
(pSrc[7] * m.TopRight) +
(pSrc[1 + stride] * m.MidLeft) +
(pSrc[4 + stride] * m.Pixel) +
(pSrc[7 + stride] * m.MidRight) +
(pSrc[1 + stride2] * m.BottomLeft) +
(pSrc[4 + stride2] * m.BottomMid) +
(pSrc[7 + stride2] * m.BottomRight))
/ m.Factor) + m.Offset);
if (nPixel < 0) nPixel = 0;
if (nPixel > 255) nPixel = 255;
p[4 + stride] = (byte)nPixel;
nPixel = ( ( ( (pSrc[0] * m.TopLeft) +
(pSrc[3] * m.TopMid) +
(pSrc[6] * m.TopRight) +
(pSrc[0 + stride] * m.MidLeft) +
(pSrc[3 + stride] * m.Pixel) +
(pSrc[6 + stride] * m.MidRight) +
(pSrc[0 + stride2] * m.BottomLeft) +
(pSrc[3 + stride2] * m.BottomMid) +
(pSrc[6 + stride2] * m.BottomRight))
/ m.Factor) + m.Offset);
if (nPixel < 0) nPixel = 0;
if (nPixel > 255) nPixel = 255;
p[3 + stride] = (byte)nPixel;
p += 3;
pSrc += 3;
}
p += nOffset;
pSrc += nOffset;
}
}
b.UnlockBits(bmData);
bSrc.UnlockBits(bmSrc);
return true;
}
Not the sort of thing you want to have to write over and over, is it ? Now we can use our ConvMatrix class to define filters, and just pass them into this function, which does all the gruesome stuff for us.
Smoothing
Given what I've told you about the mechanics of this filter, it is obvious how we create a smoothing effect. We ascribe values to all our pixels, so that the weight of each pixel is spread over the surrounding area. The code looks like this:
public static bool Smooth(Bitmap b, int nWeight )
{
ConvMatrix m = new ConvMatrix();
m.SetAll(1);
m.Pixel = nWeight;
m.Factor = nWeight + 8;
return BitmapFilter.Conv3x3(b, m);
}
As you can see, it's simple to write the filters in the context of our framework. Most of these filters have at least one parameter, unfortunately C# does not have default values, so I put them in a comment for you. The net result of apply this filter several times is as follows:

Gaussian Blur
Gaussian Blur filters locate significant color transitions in an image, then create intermediary colors to soften the edges. The filter looks like this:
| Gaussian Blur |
| 1 |
2 |
1 |
| 2 |
4 |
2 |
| 1 |
2 |
1 |
/16+0 |
The middle value is the one you can alter with the filter provided, you can see that the default value especially makes for a circular effect, with pixels given less weight the further they go from the edge. In fact, this sort of smoothing generates an image not unlike an out of focus lens.

Sharpen
On the other end of the scale, a sharpen filter looks like this:
| Sharpen |
| 0 |
-2 |
0 |
| -2 |
11 |
-2 |
| 0 |
-2 |
0 |
/3+0 |
If you compare this to the gaussian blur you'll note it's almost an exact opposite. It sharpens an image by enhancing the difference between pixels. The greater the difference between the pixels that are given a negative weight and the pixel being modified, the greater the change in the main pixel value. The degree of sharpening can be adjusted by changing the centre weight. To show the effect better I have started with a blurred picture for this example.

Mean Removal
The Mean Removal filter is also a sharpen filter, it looks like this:
| Mean Removal |
| -1 |
-1 |
-1 |
| -1 |
9 |
-1 |
| -1 |
-1 |
-1 |
/1+0 |
Unlike the previous filter, which only worked in the horizontal and vertical directions, this one spreads it's influence diagonally as well, with the following result on the same source image. Once again, the central value is the one to change in order to change the degree of the effect.

Embossing
Probably the most spectacular filter you can do with a convolution filter is embossing. Embossing is really just an edge detection filter. I'll cover another simple edge detection filter after this and you'll notice it's quite similar. Edge detection generally works by offsetting a positive and a negative value across an axis, so that the greater the difference between the two pixels, the higher the value returned. With an emboss filter, because our filter values add to 0 instead of 1, we use an offset of 127 to brighten the image, otherwise much of it would clamp to black.
The filter I have implemented looks like this:
| Emboss Laplascian |
| -1 |
0 |
-1 |
| 0 |
4 |
0 |
| -1 |
0 |
-1 |
/1+127 |
and it looks like this:

As you might have noticed, this emboss works in both diagonal directions. I've also included a custom dialog where you can enter your own filters, you might like to try some of these for embossing:
| Horz/Vertical |
| 0 |
-1 |
0 |
| -1 |
4 |
-1 |
| 0 |
-1 |
0 |
/1+127 | |
| All Directions |
| -1 |
-1 |
-1 |
| -1 |
8 |
-1 |
| -1 |
-1 |
-1 |
/1+127 | |
| Lossy |
| 1 |
-2 |
1 |
| -2 |
4 |
-2 |
| -2 |
1 |
-2 |
/1+127 | |
| Horizontal Only |
| 0 |
0 |
0 |
| -1 |
2 |
-1 |
| 0 |
0 |
0 |
/1+127 | |
| Vertical Only |
| 0 |
-1 |
0 |
| 0 |
0 |
0 |
| 0 |
1 |
0 |
/1+127 | |
The horizontal and vertical only filters differ for no other reason than to show two variations. You can actually rotate these filters as well, by rotating the values around the central point. You'll notice the filter I have used is the horz/vertical filter rotated by one degree, for example.
Let's not get carried away
Although this is kinda cool, you will notice if you run Photoshop that it offers a lot more functionality than the emboss I've shown you here. Photoshop creates an emboss using a more specifically written filter, and only part of that functionality can be simulated using convolution filters. I have spent some time writing a more flexible emboss filter, once we've covered bilinear filtering and the like, I may write an article on a more complete emboss filter down the track.
Edge Detection
Finally, just a simple edge detection filter, as a foretaste of the next article, which will explore a number of ways to detect edges. The filter looks like this:
| Edge Detect |
| 1 |
1 |
1 |
| 0 |
0 |
0 |
| -1 |
-1 |
-1 |
/1+127 |
Like all edge detection filters, this filter is not concerned with the value of the pixel being examined, but rather in the difference between the pixels surrounding it. As it stands it will detect a horizontal edge, and, like the embossing filters, can be rotated. As I said before, the embossing filters are essentially doing edge detection, this one just heightens the effect.

What's in store
The next article will be covering a variety of edge detection methods. I'd also encourage you to search the web for convolution filters. The comp.graphics.algorithms newsgroup tends to lean towards 3D graphics, but if you search an archive like google news for 'convolution' you'll find plenty more ideas to try in the custom dialog.
| You must Sign In to use this message board. |
|
|
 |
|
 |
Very good Article.
Hi i am creating function for Sharpen & Smoothing. I make some changes on your filter matrix. I googled and found some filter matrix for sharpen.All are performing fine. So i want to ask you which is good and true. I tried below matrix. [0 -2 0] with dividing factor 8. [-2 11 -2] [0 -2 0]
[0 -1 0] with dividing factor 4. [-1 5 -1] [0 -1 0]
1. Can i apply here Floating point values? 2. I want to use it with scroll bar like below link example have? So what value i have to change from matrix for that?
Click here for example Please help... prashant
adad
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Consistently images of 1000x1000 work great. Consistently images of 3400x4000 break at:
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); With a generic GDI+ error.
Has anyone else seen such behavior or know a cause or better yet, a fix?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
There is a bug in Conv3x3(Bitmap b, ConvMatrix m) function
It assumes it should not go beyond the edge of the image by doing this:
int nWidth = b.Width - 2; int nHeight = b.Height - 2;
int nPixel;
for(int y=0;y < nHeight;++y) { for(int x=0; x < nWidth; ++x ) { ...
where 2 stands for the remaining 2 pixels of the matrix. This is good but at the end of each row we see
p += nOffset; pSrc += nOffset;
to correct for the offset but we don't see
p += 6; pSrc += 6;
to correct for the 2 matrix pixels mentioned before (2 pixels by 3 bytes = 6)
so the right function is:
public static bool Conv3x3(Bitmap b, ConvMatrix m) { if (0 == m.Factor) return false;
Bitmap bSrc = (Bitmap)b.Clone();
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride; int stride2 = stride * 2; System.IntPtr Scan0 = bmData.Scan0; System.IntPtr SrcScan0 = bmSrc.Scan0;
unsafe { byte * p = (byte *)(void *)Scan0; byte * pSrc = (byte *)(void *)SrcScan0;
int nOffset = stride - b.Width*3; int nWidth = b.Width - 2; int nHeight = b.Height - 2;
int nPixel;
for(int y=0;y < nHeight;++y) { for(int x=0; x < nWidth; ++x ) { nPixel = ( ( ( (pSrc[2] * m.TopLeft) + (pSrc[5] * m.TopMid) + (pSrc[8] * m.TopRight) + (pSrc[2 + stride] * m.MidLeft) + (pSrc[5 + stride] * m.Pixel) + (pSrc[8 + stride] * m.MidRight) + (pSrc[2 + stride2] * m.BottomLeft) + (pSrc[5 + stride2] * m.BottomMid) + (pSrc[8 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);
if (nPixel < 0) nPixel = 0; if (nPixel > 255) nPixel = 255;
p[5 + stride]= (byte)nPixel;
nPixel = ( ( ( (pSrc[1] * m.TopLeft) + (pSrc[4] * m.TopMid) + (pSrc[7] * m.TopRight) + (pSrc[1 + stride] * m.MidLeft) + (pSrc[4 + stride] * m.Pixel) + (pSrc[7 + stride] * m.MidRight) + (pSrc[1 + stride2] * m.BottomLeft) + (pSrc[4 + stride2] * m.BottomMid) + (pSrc[7 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);
if (nPixel < 0) nPixel = 0; if (nPixel > 255) nPixel = 255; p[4 + stride] = (byte)nPixel;
nPixel = ( ( ( (pSrc[0] * m.TopLeft) + (pSrc[3] * m.TopMid) + (pSrc[6] * m.TopRight) + (pSrc[0 + stride] * m.MidLeft) + (pSrc[3 + stride] * m.Pixel) + (pSrc[6 + stride] * m.MidRight) + (pSrc[0 + stride2] * m.BottomLeft) + (pSrc[3 + stride2] * m.BottomMid) + (pSrc[6 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);
if (nPixel < 0) nPixel = 0; if (nPixel > 255) nPixel = 255;
p[3 + stride] = (byte)nPixel; p += 3; pSrc += 3; } p += 6; pSrc += 6;
p += nOffset; pSrc += nOffset; } }
b.UnlockBits(bmData); bSrc.UnlockBits(bmSrc);
return true; }
The problem of the current function is that it will apply the matrix of the most right image pixels column and most left column, while those to columns are not next to each other. Another side effect of this bug is that if the image is big the number of columns will accumulate and at the end we may have several rows at the bottom of not processed pixels.
modified on Sunday, September 13, 2009 7:36 PM
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi,
How can i change images with transparent background like PNG files!???
How can i detect if a certain pixel got alpha channel???
hope u can really help me...
By the way.. great coding... was very helpfull for my understand and coding in VB.net.
best regards,
Bruno Coelho
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Hi,
I need a small help in my work. I managed to code the convolution matrix of 5x5 Smile and implement it. It runs perfectly except for one problem. The end result of the image turns to be a shade of red. Please could anyone tell me what this problem is caused by and how I can solve it.
Thank You in advance.
TC
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
Hi,
I need a small help in my work. I managed to code the convolution matrix of 5x5 and implement it. It runs perfectly except for one problem. The end result of the image turns to be a shade of red. Please could anyone tell me what this problem is caused by and how I can solve it.
Thank You in advance.
TC
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
Hi Chris,
I read through ur Convo 3x3 filter coding and I was able to understand most of it! But I got stuck and i cannot figure out one part of the code which is like the most important part of the code. The part is
(pSrc[2] * m.TopLeft) + (pSrc[5] * m.TopMid) + (pSrc[8] * m.TopRight) + (pSrc[2 + stride] * m.MidLeft) + (pSrc[5 + stride] * m.Pixel) + (pSrc[8 + stride] * m.MidRight) + (pSrc[2 + stride2] * m.BottomLeft) + (pSrc[5 + stride2] * m.BottomMid) + (pSrc[8 + stride2] * m.BottomRight)
In the above part i cannot figure out how this process occurs! I tried to trace it one by one but i get mixed up and clueless half way round.
I appreciate if you could explain to me this process in a brief way.
I also tried to implement this process for the convo 5x5 matrix but i get an error like this "Access Violation Exception was unhandled". The coding for that is as follows:
(pSrc[4] * m.FTopLeft1) + (pSrc[9] * m.FTopLeft2) + (pSrc[14] * m.FTopMid) + (pSrc[19] * m.STopRight2) + (pSrc[24] * m.FTopRight1) + (pSrc[4 + stride] * m.STopLeft1) + (pSrc[9 + stride] * m.STopLeft2) + (pSrc[14 + stride] * m.STopMid) + (pSrc[19 + stride] * m.STopRight2) + (pSrc[24 + stride] * m.STopRight1) + (pSrc[4 + stride2] * m.MidLeft1) + (pSrc[9 + stride2] * m.MidLeft2) + (pSrc[14 + stride2] * m.Pixel) + (pSrc[19 + stride2] * m.MidRight2) + (pSrc[24+ stride2] * m.MidRight1) + (pSrc[4 + stride] * m.SBottomLeft1) + (pSrc[9 + stride] * m.SBottomLeft2) + (pSrc[14 + stride] * m.SBottomMid) + (pSrc[19 + stride] * m.SBottomRight2) + (pSrc[24 + stride] * m.SBottomRight1) + (pSrc[4] * m.FBottomLeft1) + (pSrc[9] * m.FBottomLeft2) + (pSrc[14] * m.FBottomMid) + (pSrc[19] * m.FBottomRight2) + (pSrc[24] * m.FBottomRight1)
The variables of the matrix i interpreted in the following way:
FTopRight1 FTopRight2 FTopMid FTopLeft2 FTopLeft1 STopRight1 STopRight2 STopMid STopLeft2 STopLeft1 MRight1 MRight2 Pixel MLeft2 MLeft1 SBottomRight1 SBottomRight2 SBottomMid SBottomLeft2 SBottomLeft1 FBottomRight1 FBottomRight2 FBottomMid FBottomLeft2 FBottomLeft1
Anyways hope this is not very messy! Thank u in advance!
tc !
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks again for a great article.
I changed the format in Conv3x3 to Format32bppArgb and i guess I will have to make some other changes in Conv3x3.
Can you please enlighten me?
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I am trying to use this from asp.net. I made the filers.cs a class project and referenced it.
I can upload images and run the coversions all day long, but no changes are applied... what am I missing.
I see a this.Invalidate(); is called in the windows forms application, I believe this to be the difference. Any ideas?
This is basically the code...
System.Drawing.Bitmap myConvertedBitmap = new System.Drawing.Bitmap(strPath.ToLower().Replace(".gif", "_TN.gif").Replace(".jpg", "_TN.jpg").Replace(".jpeg", "_TN.jpeg")); System.Drawing.Bitmap myConvertedBitmapA = CSharpFilters.BitmapFilter.Invert(myConvertedBitmap);
System.Drawing.Bitmap myConvertedBitmapB = CSharpFilters.BitmapFilter.Color(myConvertedBitmapA, 17, 100, -100); System.Drawing.Image myConvertedThumbnail = myConvertedBitmapB.GetThumbnailImage(lnNewWidth, lnNewHeight, myCallback, IntPtr.Zero); myConvertedThumbnail.Save(strPath.ToLower().Replace(".gif", "_0TN.gif").Replace(".jpg", "_0TN.jpg").Replace(".jpeg", "_0TN.jpeg"));
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
It's not obvious to me how to make the image blurrier. I've tried tweaking the various numbers in the functions, but no success. My goal is to take a screen shot and make it blurry enough so that text is visible but not quite readable.
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
Hi,
I wanted to use this class, but I was unable to do a simple automatic conversion from C# to vb.net, so I've made this class. It uses the same type of ConvMatrix, and returns the image with the Matrix applied.
Public Class clsMatrix
Public Function Conv3x3Bitmap(ByRef b As Bitmap, ByVal m As ConvMatrix) As Image If m.Factor = 0 Then Return b End If Dim bmpOriginal As Bitmap Dim bmpTreated As Bitmap Dim x As Integer Dim y As Integer Dim rPixel As Integer Dim gPixel As Integer Dim bPixel As Integer Dim p1 As Color Dim p2 As Color Dim p3 As Color Dim p4 As Color Dim p5 As Color Dim p6 As Color Dim p7 As Color Dim p8 As Color Dim p9 As Color
bmpOriginal = b bmpTreated = b
For y = 2 To bmpOriginal.Height - 2 For x = 2 To bmpOriginal.Width - 2 p1 = bmpOriginal.GetPixel(x - 1, y - 1) p2 = bmpOriginal.GetPixel(x, y - 1) p3 = bmpOriginal.GetPixel(x + 1, y - 1) p4 = bmpOriginal.GetPixel(x - 1, y) p5 = bmpOriginal.GetPixel(x, y) p6 = bmpOriginal.GetPixel(x + 1, y) p7 = bmpOriginal.GetPixel(x - 1, y + 1) p8 = bmpOriginal.GetPixel(x, y + 1) p9 = bmpOriginal.GetPixel(x + 1, y + 1)
rPixel = ((((p1.R * m.TopLeft) + _ (p2.R * m.TopMid) + _ (p3.R * m.TopRight) + _ (p4.R * m.MidLeft) + _ (p5.R * m.Pixel) + _ (p6.R * m.MidRight) + _ (p7.R * m.BottomLeft) + _ (p8.R * m.BottomMid) + _ (p9.R * m.BottomRight)) _ / m.Factor) + m.Offset)
gPixel = ((((p1.G * m.TopLeft) + _ (p2.G * m.TopMid) + _ (p3.G * m.TopRight) + _ (p4.G * m.MidLeft) + _ (p5.G * m.Pixel) + _ (p6.G * m.MidRight) + _ (p7.G * m.BottomLeft) + _ (p8.G * m.BottomMid) + _ (p9.G * m.BottomRight)) _ / m.Factor) + m.Offset)
bPixel = ((((p1.B * m.TopLeft) + _ (p2.B * m.TopMid) + _ (p3.B * m.TopRight) + _ (p4.B * m.MidLeft) + _ (p5.B * m.Pixel) + _ (p6.B * m.MidRight) + _ (p7.B * m.BottomLeft) + _ (p8.B * m.BottomMid) + _ (p9.B * m.BottomRight)) _ / m.Factor) + m.Offset)
If rPixel < 0 Then rPixel = 0 If gPixel < 0 Then gPixel = 0 If bPixel < 0 Then bPixel = 0
If rPixel > 255 Then rPixel = 255 If gPixel > 255 Then gPixel = 255 If bPixel > 255 Then bPixel = 255
bmpTreated.SetPixel(x, y, Color.FromArgb(p5.A, rPixel, gPixel, bPixel))
Next Next Return bmpTreated
bmpOriginal = Nothing bmpTreated = Nothing
End Function
End Class
Best regards,
Raul Costa
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
DOES ANYONE KNOW HOW TO DO THIS?
I process, resize and save jpeg images. Any one knows how to turn off chroma subsampling in JPEG codesc while saving the file?
I am looking for an answer for last 3\4 months!!!
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
This is I am trying to find. In Irfanview we can save a bitmap as jpeg and disable Color Subsampling during the save.
Does anyone know how to do this programmatically?
Your help will be highly appreciated.
Thanks in advance
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
I just noticed that same file resized by Flickr is clearer and sharper than the same image I got after resizing. Virtually Flickr produces better quality scaling\downsizing of uploaded images.
Just wondering if any one knows how to generate\resize\downsize good quality images like Flickr? I am not looking for exact quality (might not possible?), but quality should be close.
WHAT I AM MISSING? SOME KIND OF FILTER OR MUSK OR SPECIAL EFFECT? IF YES, THEN HOW DO FLICKR OR I DO IT?
Here is my sample code: private void SaveMedSizeImg(string strSavePath, string strSaveFileName, Bitmap bmSource, long lQuality) { int iSaveWidth, iSaveHeight; iSaveWidth = 500; iSaveHeight = 375; //assume for now
using (Bitmap Img = new Bitmap(bmSource, iSaveWidth, iSaveHeight)) { System.Drawing.Imaging.EncoderParameters encoderParams = new System.Drawing.Imaging.EncoderParameters(2);
System.Drawing.Imaging.EncoderParameter encoderParam = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, lQuality);
//next 2 doesn't make difference long encodingColorDepth = 24; System.Drawing.Imaging.EncoderParameter encoderParam2 = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, encodingColorDepth);
//System.Drawing.Imaging.EncoderValue encodingCompression = System.Drawing.Imaging.EncoderValue.CompressionLZW; //System.Drawing.Imaging.EncoderParameter encoderParam3 = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)encodingCompression);
encoderParams.Param[0] = encoderParam; encoderParams.Param[1] = encoderParam2; //encoderParams.Param[2] = encoderParam3;
System.Drawing.Imaging.ImageCodecInfo[] arrayICI = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); System.Drawing.Imaging.ImageCodecInfo jpegICI = null;
int x;
for (x = 0; x < arrayICI.Length; x++) //[BMP | JPEG | GIF | TIFF | PNG] { if (arrayICI[x].FormatDescription == "JPEG") // #2 in the array { jpegICI = arrayICI[x]; break; } }
if (jpegICI != null) { Img.Save(strSavePath + strSaveFileName, jpegICI, encoderParams); } } }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I figured it out. I am generating same quality photos like flikr but will slightly smaller file size. Wow!!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks again for sharing the code. I did finally convert the code to VB with alpha channel taken into consideration (thanks to some posts in the thread). Below is a VB function.
The problem I'm facing is grayish artifacts surrounding the text, when filter is applied to the transparent bitmap. Generating image with solid background does not produce artifacts – it is perfect even when compared to the same text image created in Photoshop. Zoomed clips can be seen HERE. The last image displays a problem.
So far I was not successful rectifying the problem and wonder how to modify algorithm to preserve the shade for transparent pixels, when the channel values are gathered and calculated from "neighbors". Thanks for any help!
Public Function Conv3x3VB(ByVal b As Bitmap, ByVal m As ConvMatrixVB) As Boolean
Dim nPixel, x, y, n, f, nWidth, nHeight, nOffset, BufferLen As Integer Dim i As Integer = 0 Dim bSrc As Bitmap = b.Clone Dim bmData As Imaging.BitmapData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), _ ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb) Dim bmSrc As Imaging.BitmapData = bSrc.LockBits(New Rectangle(0, 0, bSrc.Width, bSrc.Height), _ ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
Dim stride As Integer = bmData.Stride Dim stride2 As Integer = stride * 2 Dim Scan0 As IntPtr = bmData.Scan0 Dim SrcScan0 As IntPtr = bmSrc.Scan0 BufferLen = b.Height * stride Dim p(BufferLen - 1) As Byte Marshal.Copy(Scan0, p, 0, BufferLen) Dim pSrc(BufferLen - 1) As Byte Marshal.Copy(SrcScan0, pSrc, 0, BufferLen) nWidth = b.Width - 2 nHeight = b.Height - 2 nOffset = stride + 8 - (b.Width * 4) For y = 0 To nHeight - 1 For x = 0 To nWidth - 1 For n = 0 To 3 f = i + n nPixel = ((((pSrc(f) * m.TopLeft) + _ (pSrc(f + 4) * m.TopMid) + _ (pSrc(f + 8) * m.TopRight) + _ (pSrc(f + stride) * m.MidLeft) + _ (pSrc(f + 4 + stride) * m.Pixel) + _ (pSrc(f + 8 + stride) * m.MidRight) + _ (pSrc(f + stride2) * m.BottomLeft) + _ (pSrc(f + 4 + stride2) * m.BottomMid) + _ (pSrc(f + 8 + stride2) * m.BottomRight)) / m.Factor) + m.Offset) If (nPixel < 0) Then nPixel = 0 If (nPixel > 255) Then nPixel = 255 p(f + 4 + stride) = CByte(nPixel) Next i += 4 Next i += nOffset Next
Marshal.Copy(p, 0, Scan0, BufferLen) Marshal.Copy(pSrc, 0, SrcScan0, BufferLen) p = Nothing pSrc = Nothing b.UnlockBits(bmData) bSrc.UnlockBits(bmSrc) Return True
End Function
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
hello i have to match two images and to check wether they are same or not i have converted my image to grayscale and binarization is also done now plz guide me and refer some material to understand what to do next waiting for reply thanks
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
Images of the same objects, but not the same photo ? That's tough, I guess how tough depends on how different the photos are ?
I've never done this.
Christian Graus Please read this if you don't understand the answer I've given you "also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Well, the asker doesn't actually specify....
If it's just comparing two images, you could go by file size, or pixel iteration of each, then compare - Whichever catches your fancy :p
If it's the same object on two different pictures...
Good luck with that
-= Reelix =-
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi
For instance let's take an example of your Gaussian Blur filter. You have given a weight as 4 to the center pixel. And surrounding 8 pixels are also given 2's and 1's accordingly. So my question is that is it necessary to have the pixel value to be 4 or is it fine to give any other weight. And if we give another weight say 13 then how about the surrounding pixel's . Would they change as well or not. And how to find out which weight would give the best result. This question is valid for every convolution filter you implemented.
Thank You James
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
hi friends ... currently i am trying to write the code to find edges for my image using sobel algorithm but iam not understanding the constants
link: http://www.codeproject.com/KB/GDI-plus/csharpfilters.aspx
in that why int stride2 = stride * 2;
byte * p = (byte *)(void *)Scan0; byte * pSrc = (byte *)(void *)SrcScan0; int nOffset = stride - b.Width*3; int nWidth = b.Width - 2; int nHeight = b.Height - 2; and why three times npixel calculations
mano
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|