Wednesday, October 3, 2012

What's HSV (hue, saturation, value)?

HSV is one of the most common cylindrical-coordinate representations of points in an RGB color model. It rearrange the geometry of RGB in an attempt to be more intuitive and perceptually relevant than the cartesian (cube) representation. It is used today in color pickers, in image editing software, and less commonly in image analysis and computer vision. ~ To know more: refer Wikipedia - HSL and HSV.

Last exercise demonstrate "how to convert between HSV and RGB Color". it's modified to represent the hue, saturation, value components of HSV separately in red, green and blue images, such that you can understand it easier.

HSV (hue, saturation, value)

package com.example.androidcolor;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.widget.ImageView;

public class MainActivity extends Activity {

 ImageView imgSource, imgTarget;
 ImageView imgHue, imgSat, imgVal;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imgSource = (ImageView)findViewById(R.id.imgsource);
        imgTarget = (ImageView)findViewById(R.id.imgtarget);
        imgHue = (ImageView)findViewById(R.id.imghue);
        imgSat = (ImageView)findViewById(R.id.imgsat);
        imgVal = (ImageView)findViewById(R.id.imgval);
        
        //Load bitmap from internet
        String onLineImgSource = "http://goo.gl/yxNeG";
        URL urlImgSource;
        
  try {
   urlImgSource = new URL(onLineImgSource);
   new MyNetworkTask(imgSource, imgTarget, imgHue, imgSat, imgVal)
    .execute(urlImgSource);
  } catch (MalformedURLException e) {
   e.printStackTrace();
  }
    }

    private class MyNetworkTask extends AsyncTask<URL, Void, Bitmap>{
     
     ImageView ivSource, ivTarget;
     ImageView ivHue, ivSat, ivVal;
     
     public MyNetworkTask(ImageView iSource, ImageView iTarget,
       ImageView iHue, ImageView iSat, ImageView iVal){
      ivSource = iSource;
      ivTarget = iTarget;
      ivHue = iHue;
      ivSat = iSat;
      ivVal = iVal;
     }

  @Override
  protected Bitmap doInBackground(URL... urls) {
   Bitmap networkBitmap = null;
      
      URL networkUrl = urls[0]; //Load the first element
      try {
       networkBitmap = BitmapFactory.decodeStream(
         networkUrl.openConnection().getInputStream());
      } catch (IOException e) {
       e.printStackTrace();
      }

      return networkBitmap;
  }

  @Override
  protected void onPostExecute(Bitmap result) {
   ivSource.setImageBitmap(result);
   
   GroupBitmap groupBMResult = convertColorHSVColor(result);
   
   ivTarget.setImageBitmap(groupBMResult.bitmapDest);
   ivHue.setImageBitmap(groupBMResult.bitmapHue);
   ivSat.setImageBitmap(groupBMResult.bitmapSat);
   ivVal.setImageBitmap(groupBMResult.bitmapVal);
  }

    }
    
    class GroupBitmap {
  Bitmap bitmapHue;
  Bitmap bitmapSat;
  Bitmap bitmapVal;
  Bitmap bitmapDest;
 };
    
    //Convert Bitmap from Color to HSV, then HSV to Color
    private GroupBitmap convertColorHSVColor(Bitmap src){
     
     GroupBitmap convertedGroupBitmap = new GroupBitmap();

     int w = src.getWidth();
     int h = src.getHeight();
     
     int[] mapSrcColor = new int[w * h];
     int[] mapDestColor= new int[w * h];
     
     int[] mapHue = new int[w * h];
     int[] mapSat = new int[w * h];
     int[] mapVal = new int[w * h];
     
     float[] pixelHSV = new float[3];
     /*
      * pixelHSV[0] : Hue (0 .. 360) 
      * pixelHSV[1] : Saturation (0...1) 
      * pixelHSV[2] : Value (0...1)
      */

     src.getPixels(mapSrcColor, 0, w, 0, 0, w, h);
     /*
      * getPixels (int[] pixels, int offset, int stride, int x, int y, int width, int height)
      * - Returns in pixels[] a copy of the data in the bitmap. Each value is a packed int representing a Color. 
      * 
      * pixels: The array to receive the bitmap's colors
      * offset: The first index to write into pixels[]
      * stride: The number of entries in pixels[] to skip between rows (must be >= bitmap's width). Can be negative.
      * x:  The x coordinate of the first pixel to read from the bitmap
      * y:  The y coordinate of the first pixel to read from the bitmap
      * width: The number of pixels to read from each row
      * height: The number of rows to read
      * 
      */
     
     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);
                
                /*
                 * Represent Hue, Saturation and Value in separated color
                 * of R, G, B.
                 */
                mapHue[index] = Color.rgb((int)(pixelHSV[0] * 255/360), 0, 0);
                mapSat[index] = Color.rgb(0, (int)(pixelHSV[1] * 255), 0);
                mapVal[index] = Color.rgb(0, 0, (int)(pixelHSV[2] * 255));

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

                index++;
            }
        }
        
        Config destConfig = src.getConfig();
        /*
         * If the bitmap's internal config is in one of the public formats, return that config, 
         * otherwise return null.
         */
        
        if (destConfig == null){
         destConfig = Config.RGB_565;
        }

        convertedGroupBitmap.bitmapHue = Bitmap.createBitmap(mapHue, w, h, Config.RGB_565);
        convertedGroupBitmap.bitmapSat = Bitmap.createBitmap(mapSat, w, h, Config.RGB_565);
        convertedGroupBitmap.bitmapVal = Bitmap.createBitmap(mapVal, w, h, Config.RGB_565);
        convertedGroupBitmap.bitmapDest = Bitmap.createBitmap(mapDestColor, w, h, destConfig);
        
     return convertedGroupBitmap;
    }

}


<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" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />
    <ScrollView 
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <ImageView
                android:id="@+id/imgsource"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <ImageView
                android:id="@+id/imgtarget"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <HorizontalScrollView 
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <LinearLayout 
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal">
                    <ImageView
                        android:id="@+id/imghue"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"/>
                    <ImageView
                        android:id="@+id/imgsat"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"/>
                    <ImageView
                        android:id="@+id/imgval"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"/>
                </LinearLayout>
   </HorizontalScrollView>
        </LinearLayout>
    </ScrollView>

</LinearLayout>


Remark: Permission of "android.permission.INTERNET" is needed in this exercise to load Bitmap from internet.

download filesDownload the files.

Next:
- Adjust hue, saturation, and brightness by changing of HSV


No comments: