Wednesday, September 18, 2013

Adjust HSV(Hue, Saturation and Value) of bitmap

android.graphics.Color class provide colorToHSV() and HSVToColor() methods to convert between ARGB color and HSV components. Such that we can adjust HSV of bitmap.

Adjust HSV(Hue, Saturation and Value) of bitmap

package com.example.androiddrawbitmap;

import java.io.FileNotFoundException;

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

public class MainActivity extends Activity {

 Button btnLoadImage;
 TextView textSource;
 ImageView imageResult;
 SeekBar hueBar, satBar, valBar;
 TextView hueText, satText, valText;
 Button btnResetHSV;

 final int RQS_IMAGE1 = 1;

 Uri source;
 Bitmap bitmapMaster;
 Canvas canvasMaster;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  btnLoadImage = (Button) findViewById(R.id.loadimage);
  textSource = (TextView) findViewById(R.id.sourceuri);
  imageResult = (ImageView) findViewById(R.id.result);
  
  btnLoadImage.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {
    Intent intent = new Intent(
      Intent.ACTION_PICK,
      android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(intent, RQS_IMAGE1);
   }
  });
  
  hueText = (TextView) findViewById(R.id.texthue);
  satText = (TextView) findViewById(R.id.textsat);
  valText = (TextView) findViewById(R.id.textval);
  hueBar = (SeekBar) findViewById(R.id.huebar);
  satBar = (SeekBar) findViewById(R.id.satbar);
  valBar = (SeekBar) findViewById(R.id.valbar);
  hueBar.setOnSeekBarChangeListener(seekBarChangeListener);
  satBar.setOnSeekBarChangeListener(seekBarChangeListener);
  valBar.setOnSeekBarChangeListener(seekBarChangeListener);
  btnResetHSV = (Button)findViewById(R.id.resethsv);
  btnResetHSV.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    // reset SeekBars
    hueBar.setProgress(256);
    satBar.setProgress(256);
    valBar.setProgress(256);

    loadBitmapHSV();
   }});
 }

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);

  if (resultCode == RESULT_OK) {
   switch (requestCode) {
   case RQS_IMAGE1:
    source = data.getData();

    try {
     bitmapMaster = BitmapFactory
       .decodeStream(getContentResolver().openInputStream(
         source));

     // reset SeekBars
     hueBar.setProgress(256);
     satBar.setProgress(256);
     valBar.setProgress(256);

     loadBitmapHSV();

    } catch (FileNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    break;
   }
  }
 }

 OnSeekBarChangeListener seekBarChangeListener = new OnSeekBarChangeListener() {

  @Override
  public void onProgressChanged(SeekBar seekBar, int progress,
    boolean fromUser) {
   // TODO Auto-generated method stub

  }

  @Override
  public void onStartTrackingTouch(SeekBar seekBar) {
   // TODO Auto-generated method stub

  }

  @Override
  public void onStopTrackingTouch(SeekBar seekBar) {
   loadBitmapHSV();
  }

 };

 private void loadBitmapHSV() {
  if (bitmapMaster != null) {

   int progressHue = hueBar.getProgress() - 256;
   int progressSat = satBar.getProgress() - 256;
   int progressVal = valBar.getProgress() - 256;

   /*
    * Hue (0 .. 360) Saturation (0...1) Value (0...1)
    */

   float hue = (float) progressHue * 360 / 256;
   float sat = (float) progressSat / 256;
   float val = (float) progressVal / 256;

   hueText.setText("Hue: " + String.valueOf(hue));
   satText.setText("Saturation: " + String.valueOf(sat));
   valText.setText("Value: " + String.valueOf(val));

   imageResult.setImageBitmap(updateHSV(bitmapMaster, hue, sat, val));

  }
 }

 private Bitmap updateHSV(Bitmap src, float settingHue, float settingSat,
   float settingVal) {

  int w = src.getWidth();
  int h = src.getHeight();
  int[] mapSrcColor = new int[w * h];
  int[] mapDestColor = new int[w * h];

  float[] pixelHSV = new float[3];

  src.getPixels(mapSrcColor, 0, w, 0, 0, w, h);

  int index = 0;
  for (int y = 0; y < h; ++y) {
   for (int x = 0; x < w; ++x) {

    // Convert from Color to HSV
    Color.colorToHSV(mapSrcColor[index], pixelHSV);

    // Adjust HSV
    pixelHSV[0] = pixelHSV[0] + settingHue;
    if (pixelHSV[0] < 0.0f) {
     pixelHSV[0] = 0.0f;
    } else if (pixelHSV[0] > 360.0f) {
     pixelHSV[0] = 360.0f;
    }

    pixelHSV[1] = pixelHSV[1] + settingSat;
    if (pixelHSV[1] < 0.0f) {
     pixelHSV[1] = 0.0f;
    } else if (pixelHSV[1] > 1.0f) {
     pixelHSV[1] = 1.0f;
    }

    pixelHSV[2] = pixelHSV[2] + settingVal;
    if (pixelHSV[2] < 0.0f) {
     pixelHSV[2] = 0.0f;
    } else if (pixelHSV[2] > 1.0f) {
     pixelHSV[2] = 1.0f;
    }

    // Convert back from HSV to Color
    mapDestColor[index] = Color.HSVToColor(pixelHSV);

    index++;
   }
  }

  return Bitmap.createBitmap(mapDestColor, w, h, Config.ARGB_8888);

 }

}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/loadimage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Load Image 1" />

    <TextView
        android:id="@+id/sourceuri"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    
    <ImageView
        android:id="@+id/result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:background="@android:color/background_dark"
        android:scaleType="centerInside" />
    
    <TextView 
        android:id="@+id/texthue"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hue" />
    <SeekBar
        android:id="@+id/huebar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="511"
        android:progress="256"/>
    <TextView 
        android:id="@+id/textsat"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Saturation" />
    <SeekBar
        android:id="@+id/satbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="511"
        android:progress="256"/>
    <TextView 
        android:id="@+id/textval"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Value" />
    <SeekBar
        android:id="@+id/valbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="511"
        android:progress="256"/>
    <Button 
        android:id="@+id/resethsv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Reset HSV" />
</LinearLayout>


download filesDownload the files.

download filesDownload and try APK.



more: Something about processing images in Android

4 comments:

sandeep said...

Thank you and nice tutorial.May I know what is that emulator you are using..?

Andr.oid Eric said...

hello sandeep,

it run on true device. not emulator.

sandeep said...

But I see a mouse cursor there..How come..?

Andr.oid Eric said...

hello sandeep,

Some Android devices (basically MOST new devices as i know) include my HTC One X and Samsung S3 support OTG USB. You can insert a OTG USB cable to Android USB port, insert your mouse to the USB OTB cable, then you can use your mouse as a pointing device in Android.