May 17, 2012

Process image in background thread


Last article "Sharpen image, using Convolution Matrix" perform image processing in main thread (or called UI Thread), system will not respond any other user action before the task finished - It not a good practice! If your activity take long time not responding, it will be killed by the system.



It will be modified to be performed in background Runnable. Before the image process finished, a ProgressBar will be shown to indicate that it's running.



AndroidImageProcessingActivity.java
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[][] kernalBlur ={
   {0, -1, 0},
   {-1, 5, -1},
   {0, -1, 0}
 };
 
 ImageView imageSource, imageAfter;
 Bitmap bitmap_Source;
 ProgressBar progressBar;
 
 private Handler handler;
 Bitmap afterSharpen;
 
    /** 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() {
    afterSharpen = processingBitmap(bitmap_Source, kernalBlur);
    
    handler.post(new Runnable(){

     @Override
     public void run() {
      progressBar.setVisibility(View.GONE);
      imageAfter.setImageBitmap(afterSharpen);
     }
     
    });
   }
     };
     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;
     
     for(int i = 1; i <= bmWidth_MINUS_2; i++){
      for(int j = 1; j <= bmHeight_MINUS_2; j++){
       
       //get the surround 3*3 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-1+k, j-1+l);
        }
       }
       
       //subSum = subSrc[][] * knl[][]
       int subSumA = 0;
       int subSumR = 0;
       int subSumG = 0;
       int subSumB = 0;

       for(int k = 0; k < KERNAL_WIDTH; k++){
        for(int l = 0; l < KERNAL_HEIGHT; l++){
         subSumA += Color.alpha(subSrc[k][l]) * knl[k][l];
         subSumR += Color.red(subSrc[k][l]) * knl[k][l];
         subSumG += Color.green(subSrc[k][l]) * knl[k][l];
         subSumB += Color.blue(subSrc[k][l]) * knl[k][l];
        }
       }
       
       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(
         subSumA, 
         subSumR, 
         subSumG, 
         subSumB));
      } 
     }
     
     return dest;
    }

}

Modify main.xml to add a ProgressBar overlap imageAfter in a FrameLayout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
    <ScrollView 
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <LinearLayout 
            android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:orientation="vertical" >
         <TextView
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:text="Original" />
      <ImageView
          android:id="@+id/imageSource" 
          android:layout_width="wrap_content"
          android:layout_height="wrap_content" 
          android:src="@drawable/testpicture"/>
      <TextView
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:text="Result" />
      <FrameLayout 
          android:layout_width="wrap_content"
          android:layout_height="wrap_content">
          <ImageView
              android:id="@+id/imageAfter" 
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"/>
          <ProgressBar
              android:id="@+id/progressBar"
              style="?android:attr/progressBarStyleLarge"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"/>
      </FrameLayout>
      
     </LinearLayout>
    </ScrollView>

</LinearLayout>


No comments:

Post a Comment

Infolinks In Text Ads