Android image sharpening, saturation, hue, brightness, and contrast

mna picture mna · Jun 24, 2011 · Viewed 10.7k times · Source

I'm trying to create an app that will allow me to adjust the hue, saturation, brightness, contrast, and sharpness of an image by adjusting the seekbars for each of the above fields. like at http://ronbigelow.com/articles/workflow_basic/hue-saturation_tool.jpg

I have no idea how to do this and I can't find any tutorials online. Does Android have anything that does this already? Do I have to manipulate the colors of individual pixels? If I have to mess with the pixels, how would I do that?

Answer

Tyler Peryea picture Tyler Peryea · Jun 26, 2011

Yes, android has some tools for manipulating colors, some easier than others. The only way to do what you're specifically asking for the general space of all images is to modify individual pixels. There are other quick and dirty tricks that are much faster, but much less precise (ColorFilter).

Hue changer:

private Bitmap adjustedHue(Bitmap o, int deg)
{
   Bitmap srca = o;
   Bitmap bitmap = srca.copy(Bitmap.Config.ARGB_8888, true);
   for(int x = 0;x < bitmap.getWidth();x++)
       for(int y = 0;y < bitmap.getHeight();y++){
               int newPixel = hueChange(bitmap.getPixel(x,y),deg);
               bitmap.setPixel(x, y, newPixel);
       }

   return bitmap;
}
private int hueChange(int startpixel,int deg){
   float[] hsv = new float[3];       //array to store HSV values
   Color.colorToHSV(startpixel,hsv); //get original HSV values of pixel
   hsv[0]=hsv[0]+deg;                //add the shift to the HUE of HSV array
   hsv[0]=hsv[0]%360;                //confines hue to values:[0,360]
   return Color.HSVToColor(Color.alpha(startpixel),hsv);
}

From here, the saturation/brightness are trivial. But, while all this will get what you want, it's kinda slow. The getPixel() function is especially intense. I'd recommend "caching" the pixels first, if you're going to modify these things in real-time. For instance, storing all of the HUE, SATURATION, VALUE and ALPHA values as 2d-arrays first, and calling THEM rather than recalling getPixel() and Color.colorToHSV() with every minor change will speed up the code considerably.

Also, the bitmap.getPixels() function has worked much better for me. You could store the array it produces first, then iterate over it.

Now, while brightness/contrast can be done using similar pixel-specific methods (multiply V by some value, and add some offset) ... sharpness isn't so simple. Sharpness is not an isolated color-based modification, it's a modification to the picture itself (called "convolution"). That is, the transform needs to know something about the neighboring pixels in order to work. I'm not aware of a built-in android function for this. But it can be done a number of ways.

If you want a "sharpen" function, I'd first try a "blur" function. It's a similar process, but it's more intuitive (and cooler). And you can actually sharpen an image using blurring. This guy does a very good job at explaining all of this for use in java (with source/applets):

http://www.jhlabs.com/ip/blurring.html