May 22, 2012

Unsharp Mask (USM) on Android Image Processing

Read it first: Image processing on Android, the basic logic of Convolution Matrix.

The Unsharp Mask filter sharpens edges of the elements without increasing noise or blemish. Refer to GIMP doc to know How does an unsharp mask work.

As my understanding, for each pixel = original + (original - blur)

In this code, I use the blured image from "Apply Blur effect on Android, using Convolution Matrix" to obtain the USM image. In order to make it obviously, I apply the effect three times.

Unsharp Mask (USM) on Android Image Processing


package com.AndroidImageProcessing;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;

public class AndroidImageProcessingActivity extends Activity {
 
 final static int KERNAL_WIDTH = 3;
 final static int KERNAL_HEIGHT = 3;

 int[][] kernal_blur = {
   {1, 1, 1},
   {1, 1, 1},
   {1, 1, 1}
 };
 
 final static int DIV_BY_9 = 9;
 
 ImageView imageSource, imageAfter;
 Bitmap bitmap_Source;
 ProgressBar progressBar;
 
 private Handler handler;
 Bitmap afterProcess;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        imageSource = (ImageView)findViewById(R.id.imageSource);
        imageAfter = (ImageView)findViewById(R.id.imageAfter);
        progressBar = (ProgressBar)findViewById(R.id.progressBar);
        
        bitmap_Source = BitmapFactory.decodeResource(getResources(), R.drawable.testpicture);

        handler = new Handler();
        StratBackgroundProcess();
    }
    
    private void StratBackgroundProcess(){
     
     Runnable runnable = new Runnable(){

   @Override
   public void run() {
    afterProcess = processingBitmap(bitmap_Source, kernal_blur);
    afterProcess = processingBitmap(afterProcess, kernal_blur);
    afterProcess = processingBitmap(afterProcess, kernal_blur);
    handler.post(new Runnable(){

     @Override
     public void run() {
      progressBar.setVisibility(View.GONE);
      imageAfter.setImageBitmap(afterProcess);
     }
     
    });
   }
     };
     new Thread(runnable).start();
    }
    
    private Bitmap processingBitmap(Bitmap src, int[][] knl){
     Bitmap dest = Bitmap.createBitmap(
       src.getWidth(), src.getHeight(), src.getConfig());
     
     int bmWidth = src.getWidth();
     int bmHeight = src.getHeight();
     int bmWidth_MINUS_2 = bmWidth - 2;
     int bmHeight_MINUS_2 = bmHeight - 2;
     int bmWidth_OFFSET_1 = 1;
     int bmHeight_OFFSET_1 = 1;
     
     for(int i = bmWidth_OFFSET_1; i <= bmWidth_MINUS_2; i++){
      for(int j = bmHeight_OFFSET_1; j <= bmHeight_MINUS_2; j++){
       
       //get the surround 7*7 pixel of current src[i][j] into a matrix subSrc[][]
       int[][] subSrc = new int[KERNAL_WIDTH][KERNAL_HEIGHT];
       for(int k = 0; k < KERNAL_WIDTH; k++){
        for(int l = 0; l < KERNAL_HEIGHT; l++){
         subSrc[k][l] = src.getPixel(i-bmWidth_OFFSET_1+k, j-bmHeight_OFFSET_1+l);
        }
       }
       
       //subSum = subSrc[][] * knl[][]
       long subSumA = 0;
       long subSumR = 0;
       long subSumG = 0;
       long subSumB = 0;

       for(int k = 0; k < KERNAL_WIDTH; k++){
        for(int l = 0; l < KERNAL_HEIGHT; l++){
         subSumA += (long)(Color.alpha(subSrc[k][l])) * (long)(knl[k][l]);
         subSumR += (long)(Color.red(subSrc[k][l])) * (long)(knl[k][l]);
         subSumG += (long)(Color.green(subSrc[k][l])) * (long)(knl[k][l]);
         subSumB += (long)(Color.blue(subSrc[k][l])) * (long)(knl[k][l]);
        }
       }
       
       subSumA = subSumA/DIV_BY_9;
       subSumR = subSumR/DIV_BY_9;
       subSumG = subSumG/DIV_BY_9;
       subSumB = subSumB/DIV_BY_9;
       
       int orgColor = src.getPixel(i, j);
       int orgA = Color.alpha(orgColor);
       int orgR = Color.red(orgColor);
       int orgG = Color.green(orgColor);
       int orgB = Color.blue(orgColor);
       
       subSumA = orgA + (orgA - subSumA);
       subSumR = orgR + (orgR - subSumR);
       subSumG = orgG + (orgG - subSumG);
       subSumB = orgB + (orgB - subSumB);

       if(subSumA <0){
        subSumA = 0;
       }else if(subSumA > 255){
        subSumA = 255; 
       }
       
       if(subSumR <0){
        subSumR = 0;
       }else if(subSumR > 255){
        subSumR = 255; 
       }
       
       if(subSumG <0){
        subSumG = 0;
       }else if(subSumG > 255){
        subSumG = 255;
       }
       
       if(subSumB <0){
        subSumB = 0;
       }else if(subSumB > 255){
        subSumB = 255;
       }

       dest.setPixel(i, j, Color.argb(
         (int)subSumA, 
         (int)subSumR, 
         (int)subSumG, 
         (int)subSumB));
      } 
     }
     
     return dest;
    }

}


Using the main.xml in last article "Display image in full size".

Next:
- Image Processing with open JPG file dialog


No comments:

Post a Comment

Infolinks In Text Ads