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
Related
i am going to make app like Retrica
The problem is that i am apply some filter or effect on image it will cause java.lang.OutOfMemoryError and take a more time to apply on image.
public class ImageEnhancemeane extends AppCompatActivity {
private static final int[] FROM_COLOR = new int[]{49, 179, 110};
private static final int THRESHOLD = 3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_enhancemeane);
ImageView imgStatus = (ImageView) findViewById(R.id.backImage);
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.testimg);
imgStatus.setImageBitmap(createSepiaToningEffect(bm, 2, 0.2, 0.5, 0.59));
}
public static Bitmap createSepiaToningEffect(Bitmap src, int depth, double red, double green, double blue) {
// image size
int width = src.getWidth();
int height = src.getHeight();
// create output bitmap
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
// constant grayscale
final double GS_RED = 0.3;
final double GS_GREEN = 0.59;
final double GS_BLUE = 0.11;
// 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);
// get color on each channel
A = Color.alpha(pixel);
R = Color.red(pixel);
G = Color.green(pixel);
B = Color.blue(pixel);
// apply grayscale sample
B = G = R = (int) (GS_RED * R + GS_GREEN * G + GS_BLUE * B);
// apply intensity level for sepid-toning on each channel
R += (depth * red);
if (R > 255) {
R = 255;
}
G += (depth * green);
if (G > 255) {
G = 255;
}
B += (depth * blue);
if (B > 255) {
B = 255;
}
// set new pixel color to output image
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}
}
src.recycle();
src = null;
// return final image
return bmOut;
}
}
Here is createSepiaToningEffect() method is my filter to apply some effect on image but it will cause OutOfMemoryError.
I will solve the OutOfMemoryError using largeheap = true in manifests but i want better solution.
And it will take time when i call the filter and apply some effect on image.
Please give some solid solution.
Here is what google has to say about it:
However, the ability to request a large heap is intended only for a
small set of apps that can justify the need to consume more RAM (such
as a large photo editing app). Never request a large heap simply
because you've run out of memory and you need a quick fix
Avoid wasting memory with bitmaps
When you load a bitmap, keep it in RAM only at the resolution you need
for the current device's screen, scaling it down if the original
bitmap is a higher resolution. Keep in mind that an increase in bitmap
resolution results in a corresponding (increase2) in memory needed,
because both the X and Y dimensions increase.
For better handling of images and memory give these developer recommendations a go:
Loading Large Bitmaps Efficiently
Also, would advise you to consider using some of Android Image Libraries for image manipulations and loading. E.g. Picasso, Fresco, Glide. Each has its own pros and cons. Choose what is right for you and suits your need best, below posts may guide you in the right direction.
Picasso v/s Imageloader v/s Fresco vs Glide
Comparison of Image Library for Android (Picasso, Fresco, etc.)
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.
In my app i want to edit images like brightness, contrast, etc. I got some tutorial and i am trying this to change contrast
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 final image
return bmOut;
calling it as :
ImageView image = (ImageView)(findViewById(R.id.image));
//image.setImageBitmap(createContrast(bitmap));
But i dont see any offect happening for the image. Can you please help where i am going wrong.
I saw the effectFactory from APi 14 . IS there something similar / any tutorial that can be used for older versions for image processing
There are three basic problems with this approach. The first two are coding issues. First, you are always calling Color.red, and there is no Color.green and Color.blue to be found in your code. The second issue is that this calculation is too repetitive. You assume the colors are in the range [0, 255], so it is much faster to create a array of 256 positions with the contrast calculated for each i in [0, 255].
The third issue is more problematic. Why did you consider this algorithm to improve contrast ? The results are meaningless for RGB, you might get something better in a different color system. Here are the results you should expect, with your parameter value at 0, 10, 20, and 30:
And here is a sample Python code to perform the operation:
import sys
from PIL import Image
img = Image.open(sys.argv[1])
width, height = img.size
cvalue = float(sys.argv[2]) # Your parameter "value".
contrast = ((100 + cvalue) / 100) ** 2
def apply_contrast(c):
c = (((c / 255.) - 0.5) * contrast + 0.5) * 255.0
return min(255, max(0, int(c)))
# Build the lookup table.
ltu = []
for i in range(256):
ltu.append(apply_contrast(i))
# The following "point" method applies a function to each
# value in the image. It considers the image as a flat sequence
# of values.
img = img.point(lambda x: ltu[x])
img.save(sys.argv[3])
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)
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;
}