Image Processing – Convolution Matrix
It’s kinda hard to explain about Convolution, so I just pick up several articles which would be helpful for you for references.
GIMP Documentation on Convolution Matrix <— really detailed on explanation.
Convolution Study by Ahn Song Ho
VcsKicks.Com – Convolution Application on Box Blur effect
CodeProject – Image Processing for Dummies (Part II – Convolution Filters)
RoboRealms – Short article on Convolution
You can find more on Internet for details. However, you can see that Convolution is applied very widely in image processing.
Some image effects are better to implement using Convolution Matrix method like: Gaussian Blur, Sharpening, Embossing…
Ok, I write this post just to introduce about Convolution and prepare for the next several articles on image processing, cool effects!
At the very first, you need a base for computing Convolution Matrix on Android, don’t you?
This is my implementation:
package pete.android.study;
import android.graphics.Bitmap;
import android.graphics.Color;
public class ConvolutionMatrix
{
public static final int SIZE = 3;
public double[][] Matrix;
public double Factor = 1;
public double Offset = 1;
public ConvolutionMatrix(int size) {
Matrix = new double[size][size];
}
public void setAll(double value) {
for (int x = 0; x < SIZE; ++x) {
for (int y = 0; y < SIZE; ++y) {
Matrix[x][y] = value;
}
}
}
public void applyConfig(double[][] config) {
for(int x = 0; x < SIZE; ++x) {
for(int y = 0; y < SIZE; ++y) {
Matrix[x][y] = config[x][y];
}
}
}
public static Bitmap computeConvolution3x3(Bitmap src, ConvolutionMatrix matrix) {
int width = src.getWidth();
int height = src.getHeight();
Bitmap result = Bitmap.createBitmap(width, height, src.getConfig());
int A, R, G, B;
int sumR, sumG, sumB;
int[][] pixels = new int[SIZE][SIZE];
for(int y = 0; y < height - 2; ++y) {
for(int x = 0; x < width - 2; ++x) {
// get pixel matrix
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
pixels[i][j] = src.getPixel(x + i, y + j);
}
}
// get alpha of center pixel
A = Color.alpha(pixels[1][1]);
// init color sum
sumR = sumG = sumB = 0;
// get sum of RGB on matrix
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
sumR += (Color.red(pixels[i][j]) * matrix.Matrix[i][j]);
sumG += (Color.green(pixels[i][j]) * matrix.Matrix[i][j]);
sumB += (Color.blue(pixels[i][j]) * matrix.Matrix[i][j]);
}
}
// get final Red
R = (int)(sumR / matrix.Factor + matrix.Offset);
if(R < 0) { R = 0; }
else if(R > 255) { R = 255; }
// get final Green
G = (int)(sumG / matrix.Factor + matrix.Offset);
if(G < 0) { G = 0; }
else if(G > 255) { G = 255; }
// get final Blue
B = (int)(sumB / matrix.Factor + matrix.Offset);
if(B < 0) { B = 0; }
else if(B > 255) { B = 255; }
// apply new pixel
result.setPixel(x + 1, y + 1, Color.argb(A, R, G, B));
}
}
// final image
return result;
}
}
We will move to some nice effects on next articles!
Hope you like it!
Cheers,
Pete Houston
How to get bitmap stone effect like http://0.tqn.com/d/graphicssoft/1/0/m/H/1/photosketch-emboss.gif
I use the following kernel matrix for emboss effect ,but not get correct output
2,0,0
0,-1,0
0,0,-1 how can i get the matrix for emboss masking filter .
Here is an optimized version of your code, based on android.graphics.Matrix; caching pixels really speeds up the computation. Also, by cloning original pixels, we don’t loose last two rows and columns.
private static final int MATRIX_SIZE = 3;
private static int cap(int color) {
if (color 255)
return 255;
else
return color;
}
public static Bitmap convolute(Bitmap bmp, Matrix mat, float factor, int offset) {
// get matrix values
float [] mxv = new float[MATRIX_SIZE * MATRIX_SIZE];
mat.getValues(mxv);
// cache source pixels
int width = bmp.getWidth();
int height = bmp.getHeight();
int [] scrPxs = new int[width * height];
bmp.getPixels(scrPxs, 0, width, 0, 0, width, height);
// clone source pixels in an array
// here we’ll store results
int [] rtPxs = scrPxs.clone();
int r, g, b;
int rSum, gSum, bSum;
int idx; // current pixel index
int pix; // current pixel
float mv; // current matrix value
for(int x = 0, w = width – MATRIX_SIZE + 1; x < w; ++x) {
for(int y = 0, h = height – MATRIX_SIZE + 1; y < h; ++y) {
idx = (x + 1) + (y + 1) * width;
rSum = gSum = bSum = 0;
for(int mx = 0; mx < MATRIX_SIZE; ++mx) {
for(int my = 0; my < MATRIX_SIZE; ++my) {
pix = scrPxs[(x + mx) + (y + my) * width];
mv = mxv[mx + my * MATRIX_SIZE];
rSum += (Color.red(pix) * mv);
gSum += (Color.green(pix) * mv);
bSum += (Color.blue(pix) * mv);
}
}
r = cap((int)(rSum / factor + offset));
g = cap((int)(gSum / factor + offset));
b = cap((int)(bSum / factor + offset));
// store computed pixel
rtPxs[idx] = Color.argb(Color.alpha(scrPxs[idx]), r, g, b);
}
}
// return bitmap with transformed pixels
return Bitmap.createBitmap(rtPxs, width, height, bmp.getConfig());
}
cheers !
as the matrix is added to the Matrix object?
The cap function is incorrect. It should be:
private static int cap(int color) {
if (color > 255)
return 255;
else if (color < 0)
return 0;
else
return color;
}
Beside this – fantastic algorithm – I was looking for it for a long time!
Thanks
How to implement it in Blackberry.
I want emboss image effects and sketch effect in blackberry.
how to implement it in Blackberry.I want to do emboss effect and sketch effect.
/*Gaussian Blur
1 2 1
2 4 2
1 2 1 /16+0 */
public Bitmap gaussianBlur(Bitmap src) {
double[][] EmbossConfig = new double[][] {
{ 1 , 2, 1 },
{ 2 , 4, 2 },
{1 , 2, 1 }
};
ConvolutionMatrix convMatrix = new ConvolutionMatrix(3);
convMatrix.applyConfig(EmbossConfig);
convMatrix.Factor = 16;
convMatrix.Offset = 0;
return ConvolutionMatrix.computeConvolution3x3(src, convMatrix);
}
You can apply the upper code. it is ok.
I have used your computeConvolution3x3 in my project, have you encounterd delays?
Oooops…my serious mistake, I’ve just fixed a found error on my ConvolutionMatrix.computeConvolution3x3().
You might want to update the source code and run it again
I am using your function as below, but it seems that i am doing something wrong. I am using this value to get a gaussian blur effect, like in http://www.codeproject.com/KB/GDI-plus/csharpfilters.aspx
ConvolutionMatrix matrix = new ConvolutionMatrix(3);
double config[][] = {{1.0,2.0,1.0},{2.0D,4.0D,2.0D},{1.0,2.0,1.0}};
matrix.applyConfig(config);
Bitmap tempBitmap = computeConvolution3x3(mBitmap, matrix);
And I am always getting a white image