I have Black and White picture - RGB 565, 200x50.
as I can calculate the intensity 0..255 of each pixel?
That's what I meant, thanks. ma be this can someone help. I get Intensity 0..255 of each pixel and get the average.
Bitmap cropped = Bitmap.createBitmap(myImage, 503, 270,myImage.getWidth() - 955, myImage.getHeight() - 550);
Bitmap cropped2 = Bitmap.createBitmap(cropped, 0, 0,cropped.getWidth() , cropped.getHeight() / 2 );
final double GS_RED = 0.35;
final double GS_GREEN = 0.55;
final double GS_BLUE = 0.1;
int R, G, B;
int result = 0;
int g = 0;
int ff;
for(int x = 0; x < cropped2.getWidth(); x++)
{
int ff_y = 0;
for(int y = 0; y < cropped2.getHeight(); y++)
{
Pixel = cropped.getPixel(x, y);
R = Color.red(Pixel);
G = Color.green(Pixel);
B = Color.blue(Pixel);
ff = (int)(GS_RED * R + GS_GREEN * G + GS_BLUE * B) ;
ff_y += ff;
}
result += ff_y;
g = result / (cropped2.getWidth()*cropped2.getHeight());
}
Toast.makeText(this, "00" + g, Toast.LENGTH_LONG).show();
You could try to convert it using a color model with a luminance and two chrominance components. The luminance component accounts for the brightness while the two chrominance components represent the colors. You might want to check out http://en.wikipedia.org/wiki/YUV.
Otherwise: If I'm correct, the white over gray to black colors have equal values in a RGB format which has the same number of bits for each channel (e.g. from (0, 0, 0) to (255, 255, 255)). Assuming this is true you could just take one of the channels to represent the intensity as you could determine the other values from that. No guarantee if this works.
Edit:
I wrote a snippet demonstrating the idea described above. I used RGB888 but it should also work with RGB 565 after dropping the assertion and modifying the maximum intensity of a pixel as described in the comments. Mind that there are only 2^5 different intensity levels per pixel. Hence you might want to use a scaled version of the average intensity.
I tested it using images from http://www.smashingmagazine.com/2008/06/09/beautiful-black-and-white-photography/. I hope it will work out porting this to android for you.
// 2^5 for RGB 565
private static final int MAX_INTENSITY = (int) Math.pow(2, 8) - 1;
public static int calculateIntensityAverage(final BufferedImage image) {
long intensitySum = 0;
final int[] colors = image.getRGB(0, 0, image.getWidth(),
image.getHeight(), null, 0, image.getWidth());
for (int i = 0; i < colors.length; i++) {
intensitySum += intensityLevel(colors[i]);
}
final int intensityAverage = (int) (intensitySum / colors.length);
return intensityAverage;
}
public static int intensityLevel(final int color) {
// also see Color#getRed(), #getBlue() and #getGreen()
final int red = (color >> 16) & 0xFF;
final int blue = (color >> 0) & 0xFF;
final int green = (color >> 8) & 0xFF;
assert red == blue && green == blue; // doesn't hold for green in RGB 565
return MAX_INTENSITY - blue;
}
Related
In my application I have a seek bar, by sliding it a user can increase or decrease brightness of image. I have done this work but the problem is that its very slow to show, it takes around 3-4 second to show effect on image after sliding seek bar. Below is my code which I have implemented, can anybody tell me that what should I do to make this effect smooth over an image.
public static Bitmap doBrightness(Bitmap src, int value) {
// image size
int width = src.getWidth();
int height = src.getHeight();
// create output bitmap
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
// color information
int A, R, G, B;
int pixel;
// scan through all pixels
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
// get pixel color
pixel = src.getPixel(x, y);
A = Color.alpha(pixel);
R = Color.red(pixel);
G = Color.green(pixel);
B = Color.blue(pixel);
// increase/decrease each channel
R += value;
if (R > 255) {
R = 255;
} else if (R < 0) {
R = 0;
}
G += value;
if (G > 255) {
G = 255;
} else if (G < 0) {
G = 0;
}
B += value;
if (B > 255) {
B = 255;
} else if (B < 0) {
B = 0;
}
// apply new pixel color to output bitmap
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}
}
// return final image
return bmOut;
}
You're walking every pixel in the image in a single thread of Java code as well as using Color methods to break down the color into its constituent parts. This would be a good candidate for something to be done in RenderScript. RS will either offload the operation to a DSP or GPU (if supported on your device) or parallelize it on the CPU. See this talk for basic usage and background on RenderScript.
I have hex rgb color and black-white mask. It's two integer arrays:
mColors = new int[] {
0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
0xFFFFFF00, 0xFFFF0000
};
mColorsMask = new int[] {
0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF,
0xFFFFFFFF, 0xFF000000
};
I need to convert my color to black value depending on contrast. Contrast is integer value in a range from 0 to 255:
With white all is fine, I make byte addition:
int newHexColor = (contrast << 16) | (contrast << 8) | contrast | mColors[i];
newColorsArray[i] = mode;
How to convert it to black?
You might look into using the HSB color space. It seems much more suited to what you're trying to do. In particular, you see those angles that end up black in your "what i want" image? Those correspond to "hues" at 60, 180, and 300 degrees (1.0/6, 3.0/6, and 5.0/6 in Java). The white corresponds to 0, 120, and 240 degrees (0, 1.0/3, and 2.0/3 in Java) -- and not coincidentally, the colors at those angles are primary colors (that is, two of the three RGB components are zero).
What you'd do is find the difference between your color's hue and the nearest primary color. (Should be less than 1/6.) Scale it up (multiplying by 6 should do it), to give you a value between 0 and 1.0. That will give you an "impurity" value, which is basically the deviation from the nearest primary color. Of course, that number subtracted from 1.0 gives you the "purity", or the closeness to a primary color.
You can create a greyscale color based on the impurity or purity by using the respective value as the R, G, and B, with an alpha of 1.0f.
public Color getMaskColor(Color c) {
float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
float hue = hsv[0];
// 0, 1/3, and 2/3 are the primary colors. Find the closest one to c,
// by rounding c to the nearest third.
float nearestPrimaryHue = Math.round(hue * 3.0f) / 3.0f;
// difference between hue and nearestPrimaryHue <= 1/6
// Multiply by 6 to get a value between 0 and 1.0
float impurity = Math.abs(hue - nearestPrimaryHue) * 6.0f;
float purity = 1.0f - impurity;
// return a greyscale color based on the "purity"
// (for #FF0000, would return white)
// using impurity would return black instead
return new Color(purity, purity, purity, 1.0f);
}
You could either use a color component of the returned color as the "contrast" value, or change the function so that it returns the "purity" or "impurity" as needed.
Note, the math gets wonky with greyscale colors. (The way Java calculates HSB, pure greys are just reds (hue=0) with no tint (saturation=0). The only component that changes is the brightness.) But since your color wheel doesn't have greyscale colors...
You can make the image black n white using contrast.
See the code..
public static Bitmap createContrast(Bitmap src, double value) {
// image size
int width = src.getWidth();
int height = src.getHeight();
// create output bitmap
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
// color information
int A, R, G, B;
int pixel;
// get contrast value
double contrast = Math.pow((100 + value) / 100, 2);
// scan through all pixels
for(int x = 0; x < width; ++x) {
for(int y = 0; y < height; ++y) {
// get pixel color
pixel = src.getPixel(x, y);
A = Color.alpha(pixel);
// apply filter contrast for every channel R, G, B
R = Color.red(pixel);
R = (int)(((((R / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
if(R < 0) { R = 0; }
else if(R > 255) { R = 255; }
G = Color.red(pixel);
G = (int)(((((G / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
if(G < 0) { G = 0; }
else if(G > 255) { G = 255; }
B = Color.red(pixel);
B = (int)(((((B / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
if(B < 0) { B = 0; }
else if(B > 255) { B = 255; }
// set new pixel color to output bitmap
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}
}
return bmOut;
}
Set the double value to 50 on method call. For Example createContrast(Bitmap src, 50)
Im currently working on a program which applies edge detection to an area of the preview frame. I have used previewcallback and got my cropped bitmap, have converted to grayscale using the following method.
int height1=120;
int width2=120;
final Bitmap resizedBitmap = Bitmap.createBitmap(bmp, 260, 15,
width2, height1);
try {
int bWidth = resizedBitmap.getWidth();
int bHeight = resizedBitmap.getHeight();
int[] pixels = new int[bWidth * bHeight];
resizedBitmap.getPixels(pixels, 0, bWidth, 0, 0, bWidth, bHeight);
for (int y = 0; y < bHeight; y++){
for (int x = 0; x < bWidth; x++){
int index = y * bWidth + x;
int R = (pixels[index] >> 16) & 0xff; //bitwise shifting
int G = (pixels[index] >> 8) & 0xff;
int B = pixels[index] & 0xff;
int gray = (int) (.299 * R + .587 * G + .114 * B);
}
}
I am very new to this, and would like to know whether gray is a 2D array of 120x120 pixels, or whether the value of gray is just being overwritten for each loop.
Apologies if this is very basic
Well, maybe I'm missing something, but as far as I can see gray is overwritten. You'd need something like
int[][] gray = new int[width][height];
// start loop
In the Loop:
gray[x][y] = ...;
I apply sepia effect on image but when I click on button to apply its done but after 90 sec .
public static Bitmap effect(Bitmap src, int depth, double red, double green, double blue)
{
int width = src.getWidth();
int height = src.getHeight();
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
final double GS_RED = 0.3;
final double GS_GREEN = 0.59;
final double GS_BLUE = 0.11;
int A, R, G, B;
int pixel;
for(int x = 0; x < width; ++x) {
for(int y = 0; y < height; ++y) {
pixel = src.getPixel(x, y);
A = Color.alpha(pixel);
R = Color.red(pixel);
G = Color.green(pixel);
B = Color.blue(pixel);
B = G = R = (int)(GS_RED * R + GS_GREEN * G + GS_BLUE * B);
R += (depth * red);
if(R > 255) { R = 255; }
G += (depth * green);
if(G > 255) { G = 255; }
B += (depth * blue);
if(B > 255) { B = 255; }
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}}
return bmOut;
}
Oh, it appears that you are using the sample code on my blog: http://xjaphx.wordpress.com/2011/06/21/image-processing-photography-sepia-toning-effect/
The article means to demonstrate the how to implement the algorithm, so it certainly doesn't mention anything else.
As for performance problem, I suggest:
If you develop under Application Level (Java code..), use getPixels() setPixels() and manipulate the two-dimensional array. Well, in this sepia-toning, it might be up to only 5-10 seconds on emulator, on real device it might be 3 seconds.
It's preferable to do all image processing stuffs on NDK (like creating image processing library..), it will process much faster.
Anyway, have fun!
You could just place a semi-transparent orange/yellow rectangle ontop, it will achieve the same effect as your code above and you wont have to worry about processing time, you are using a mobile phone after all.
Its not solving your problem but its also no analysing and manipulating every pixels colour, your only issue would be saving the resulting image however this is done in a similar way
I want to get RGB values of a Bitmap on Android but I can't do this so far. My aim is to obtain RGB values for each pixel of a Bitmap. Is there any specific function for Android or anything else?
Also I wonder that do I need colorMatrix() function?
It is very important for my project.
Bitmap#getPixel(x, y) returns an int with the colour values and alpha value embedded into it.
int colour = bitmap.getPixel(x, y);
int red = Color.red(colour);
int green = Color.green(colour);
int blue = Color.blue(colour);
int alpha = Color.alpha(colour);
This may be slightly late, but to clear up the confusion with the use of &0xff:
In Java ints are 32 bits, so the (A)RGB values for each pixel are packed in 4 bytes.
In other words, a pixel with the values R(123), G(93), B(49) = FF7B 5D31 in the ARGB_8888 model. Where Alpha = FF, R = 7B, G = 5D, B = 31. But this is stored as an int as -8692431.
So, to extract the Green value from -8692431, we need to shift the 5D by 8 bits to the right, as you know. This gives 00FF 7B5D. So, if we were just to take that value we would be left with 16743261 as our Green value. Therefore, we bitwise-and that value with the mask of 0xFF (which is equivalent to 0000 00FF) and will result in 00FF 7B5D being 'masked' to 0000 005D. So we have extracted our Green value of 5D (or 93 decimal).
We can use the same mask of 0xFF for each extraction because the values have all been shifted to expose the desired two bytes as the least significant. Hence the previously suggested code of:
int p = pixel[index];
int R = (p >> 16) & 0xff;
int G = (p >> 8) & 0xff;
int B = p & 0xff;
If it makes it clearer, you can perform the equivalent operation of:
int R = (p & 0xff0000) >> 16;
int G = (p & 0x00ff00) >> 8;
int B = (p & 0x0000ff) >> 0;
For brevity, the extra 0s can be dropped, and it can be written as
int R = (p & 0xff0000) >> 16;
int G = (p & 0xff00) >> 8;
int B = p & 0xff;
Note however, that alternative colour models may be used, such as RGB_555 which stores each pixel as just 2 bytes, with varying precision for the RGB channels. So you should check the model that your bitmap is using before you perform the extraction, because the colours may be stored differently.
This is how I am trying to get that value. Use bitmap.getPixel() to get the corresponding bitmap in
integer array. By using bitwise rotation operation, we will get RGB values.
int[] pix = new int[picw * pich];
bitmap.getPixels(pix, 0, picw, 0, 0, picw, pich);
int R, G, B,Y;
for (int y = 0; y < pich; y++){
for (int x = 0; x < picw; x++)
{
int index = y * picw + x;
int R = (pix[index] >> 16) & 0xff; //bitwise shifting
int G = (pix[index] >> 8) & 0xff;
int B = pix[index] & 0xff;
//R,G.B - Red, Green, Blue
//to restore the values after RGB modification, use
//next statement
pix[index] = 0xff000000 | (R << 16) | (G << 8) | B;
}}
Arbitrary Bitmap Color Handling
You can read about the various Color methods here that will extract the components of color from a pixel int.
You might want to apply a filter to the bitmap, and return a byte array. Otherwise, you can cut this example down to the for-loop and roll through the pixels generating your array of bytes.
private byte[] rgbValuesFromBitmap(Bitmap bitmap)
{
ColorMatrix colorMatrix = new ColorMatrix();
ColorFilter colorFilter = new ColorMatrixColorFilter(
colorMatrix);
Bitmap argbBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(argbBitmap);
Paint paint = new Paint();
paint.setColorFilter(colorFilter);
canvas.drawBitmap(bitmap, 0, 0, paint);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int componentsPerPixel = 3;
int totalPixels = width * height;
int totalBytes = totalPixels * componentsPerPixel;
byte[] rgbValues = new byte[totalBytes];
#ColorInt int[] argbPixels = new int[totalPixels];
argbBitmap.getPixels(argbPixels, 0, width, 0, 0, width, height);
for (int i = 0; i < totalPixels; i++) {
#ColorInt int argbPixel = argbPixels[i];
int red = Color.red(argbPixel);
int green = Color.green(argbPixel);
int blue = Color.blue(argbPixel);
rgbValues[i * componentsPerPixel + 0] = (byte) red;
rgbValues[i * componentsPerPixel + 1] = (byte) green;
rgbValues[i * componentsPerPixel + 2] = (byte) blue;
}
return rgbValues;
}
One for statement less :D
imagen.getPixels(pix, 0, picw, 0, 0, picw, pich);
for (i = 0; i < pix.length; i++) {
r = (pix[i]) >> 16 & 0xff;
g = (pix[i]) >> 8 & 0xff;
b = (pix[i]) & 0xff;
}
In addition to #Cobbles' answer, you can also use Bitmap#getColor(x, y) and a Color object.
for (int y = 0; y < bitmap.getHeight(); y++) {
for (int x = 0; x < bitmap.getWidth(); x++) {
Color color = bitmap.getColor(x, y);
float red = color.red();
float green = color.green();
float blue = color.blue();
float alpha = color.alpha();
Log.d(TAG, String.format(
"(R, G, B, A) = (%f, %f, %f, %f)", red, green, blue, alpha
));
}
}
With above code, you can get float (0..1) RGBA values. When you just want to get integer (0..255) values, #Cobble's way is rather straight forward (recommended). Though there is still a way to get integer values with this Color object by using Color#toArgb.
for (int y = 0; y < bitmap.getHeight(); y++) {
for (int x = 0; x < bitmap.getWidth(); x++) {
int color = bitmap.getColor(x, y).toArgb();
int red = Color.red(color);
int green = Color.green(color);
int blue = Color.blue(color);
int alpha = Color.alpha(color);
Log.d(TAG, String.format(
"(R, G, B, A) = (%3d, %3d, %3d, %3d)", red, green, blue, alpha
));
}
}