Skip to main content

How to Establish a Different Picture of the Android Camera by Image Processing (Gray and Comic)?

How to Establish a Different Picture of the Android Camera by Image Processing (Gray and Comic)?

How to Establish a Different Picture of the Android Camera by Image Processing (Gray and Comic)?

Introduction

Sometimes, we just feel fun to take a picture. Let’s take a different funny picture. We can develop by self. To design gray and comic style picture, it is not hard. You just need to own an Android phone and you can establish a funny camera app.

Normally, you will encounter auto focus when you take a picture. This problem can be solved in this study. Firstly, while we can be waiting the auto focus to finish when we take a picture. That is why need to overwrite auto focus method to help us take a clear picture. Secondly, while the image processing had compute when we need to transform raw data to bitmap format. We used to bitmap factory to help us do this transform. Thirdly, there are two image processing that was chosen by users. The gray scale and comic effect in this study. The gray scale is very simple that is just getting R, G and B of amount and then divide by three. That is your new pixels of gray scale, but we still need to know how to get R, G and B of channel respectively. We are getting a pixel value after use the Color method to help us get R, G and B of values. There is a difficult convolution processing about comic effect. The comic progress is two processing, including Sobel filter and ordered dither processing. We need to combine the two results of the image processing to establish a new image, that is called comic effect.

If you want to develop more image effect, you could use this code of architecture. To keep developing your new idea. Because there are preparing auto focus and take a picture of callback function. You just follow this architecture and then to add new image effect.

In this study, this app will open your camera before you choice image effect and then you have chosen an effect gray scale or comic. You can press 'take a picture' button and then you can watch a processed image. Such as those figures.

To develop this app just only two files, It is very simple, that is why I wrote this article. Because to help beginners in the camera app development. All code presents this article. I need to, you're a little patient to read. And then you will find out that so easy.

Equipment

Operation System: Android 4.1.2
Development Utility: Eclipse ADT

Usage


File Name: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.style.camera"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.style.camera.MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
       <! -- We should set those permissions. -->
	<uses-permission android:name="android.permission.CAMERA"></uses-permission>
	<uses-feature android:name="android.hardware.camera" />
	<uses-feature android:name="android.hardware.camera.autofocus" />
</manifest>


File Name: MainActivity.java
public class MainActivity extends Activity implements SurfaceHolder.Callback  {

    SurfaceView mSurfaceView ;
    Button btn_Capture;        
    Camera mCamera;    
    PictureCallback mPictureCB;
    AutoFocusCallback mAutoFocusCB;
    ImageView ImgView;
    TextView txtView;
    Bitmap bitmapClone;
    RadioGroup rdg_Main;
    RadioButton rdb_Gray;
    RadioButton rdb_Comic;
    int iImageProcessingId; 

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Set the format of window, as per the PixelFormat types. 
        // This overrides the default format that is selected by 
        // the Window based on its window decorations.
        // System chooses a format that supports translucency (many alpha bits). 
        getWindow().setFormat(PixelFormat.TRANSLUCENT);
        // Enable extended window features. 
        // Flag for the "no title" feature, turning off the title at the top of the screen.
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        // Set the flags of the window, as per the WindowManager.LayoutParams flags.
        // Window flag: Hide all screen decorations (e.g. status bar). 
        // while this window is displayed. This allows the window to use 
        // the entire display space for itself -- the status bar will be 
        // hidden when an app window with this flag set is on the top layer. 
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);           
        // Set the activity content from a layout resource. 
        // The resource will be inflated, adding all top-level views to the activity.
        setContentView(R.layout.activity_main);
        // Change the desired orientation of this activity. 
        // If the activity is currently in the foreground or 
        // otherwise impacting the screen orientation, 
        // the screen will immediately be changed 
        // (possibly causing the activity to be restarted). 
        // Otherwise, this will be used the next time the activity is visible.
        // Constant corresponding to portrait in the android.R.attr.screenOrientation attribute.
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        // -- (Start)
        ImgView = (ImageView)this.findViewById(R.id.ImgView);
        txtView = (TextView)this.findViewById(R.id.txtView);
        btn_Capture = (Button)this.findViewById(R.id.btn_Capture);
        mSurfaceView  = (SurfaceView)this.findViewById(R.id.surView_Camera); 
        rdg_Main = (RadioGroup) findViewById (R.id.rdg_Main);
        rdb_Gray = (RadioButton) findViewById (R.id.rdb_Gray);
        rdb_Comic = (RadioButton) findViewById (R.id.rdb_Comic);
        // -- (End)
        // Set and get SurfaceHolder
        // Abstract interface to someone holding a display surface. 
        // Allows you to control the surface size and format, 
        // edit the pixels in the surface, and monitor changes to the surface. 
        // This interface is typically available through the SurfaceView class. 
        // When using this interface from a thread other than the one running 
        // its SurfaceView, you will want to carefully read the methods 
        // lockCanvas and Callback.surfaceCreated().
        SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder(); 
        mSurfaceHolder.addCallback(this);
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        // To record the choice of image processing by the user 
        iImageProcessingId = 0;

        // To listen choice of the user and record it.
        // There are two choices, including Gray and Comic.
        rdg_Main.setOnCheckedChangeListener( new RadioGroup.OnCheckedChangeListener() {


        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            // TODO Auto-generated method stub
            // Gray
            if ( checkedId == rdb_Gray.getId() )
            {
                iImageProcessingId = 0;
            }
            // Comic
            else if ( checkedId == rdb_Comic.getId() )
            {
                iImageProcessingId = 1;
            }
        }
        });

        // To establish Camera.takePicture callback function.
        mPictureCB = new PictureCallback(){
        // Image processing.
        // Overwrite onPictureTake function.
        @Override
        public void onPictureTaken(byte[] data, Camera camera){
               // We use the BitmapFactory to decode become raw data to bitmap format.
               Bitmap mBitmap = BitmapFactory.decodeByteArray(data, 0 , data.length);
               bitmapClone = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), mBitmap.getConfig());
               bitmapClone.copy(mBitmap.getConfig(), true);
               // For debug of switch.
               if ( true )
               {
                   int iY = 0;
                   int iX = 0;
                   int iPixel = 0;
                   int iRed = 0;
                   int iGreen = 0;
                   int iBlue = 0;
                   int iRGBAvg = 0;
                   // Gray of image processing.
                   if ( iImageProcessingId == 0 )
                   {
                          // The height of the image
                          for ( iY = 0; iY < bitmapClone.getHeight(); iY++ )
                          {
                              // The width of the image
                              for ( iX = 0; iX < bitmapClone.getWidth(); iX++ )
                              {
                                  // To get pixel.
                                  iPixel = mBitmap.getPixel(iX, iY);
                                  // To get value of the red channel.
                                  iRed = Color.red(iPixel);
                                  // To get value of the green channel.
                                  iGreen = Color.green(iPixel);
                                  // To get value of the blue channel.
                                  iBlue = Color.blue(iPixel);
                                  // Compute value of gray.
                                  iRGBAvg = ( iRed + iGreen + iBlue ) / 3;
                                  // Set pixel of gray. 
                                  bitmapClone.setPixel(iX, iY, Color.rgb(iRGBAvg, iRGBAvg, iRGBAvg));
                              }
                          }
                   }
                   // Comic
                   else if ( iImageProcessingId == 1 )
                   {
                       // The horizontal of Sobel matrix
                       int iSobel1 [][]= { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 }};
                       // The vertical of Sobel matrix
                       int iSobel2 [][]= { { -1, 0, -1 }, { -2, 0, 2 }, { 1, 0, 1 }};
                       // The ordered dither of the matrix
                       int iOrderDither [][] = { { 28, 255, 57 }, { 142, 113, 227 }, { 170, 198, 85 } };
                       float fYofYUV = 0.0f;
                       int iYofYUV = 0;
                       int iX1 = 0;
                       int iY1 = 0;
                       int iR = 1;
                       int iValue1 = 0;
                       int iValue2 = 0;
                       int iValue = 0;
                       // For a horizontal index of Sobel matrix
                       int iX2 = 0;
                       // For a vertical index of Sobel matrix
                       int iY2 = 0;
                       // Sobel filter of image processing
                       // The height of the image
                       for ( iY = 1; iY < bitmapClone.getHeight() - 1; iY++ )
                       {
                           // The width of the image
                           for ( iX = 1; iX < bitmapClone.getWidth() - 1; iX++ )
                           {
                               iY2= 0;
                               iValue1 = 0;
                               iValue2 = 0;
                               // The height of Sobel matrix
                               for ( iY1 = iY - iR; iY1 <= iY + iR; iY1++ )
                               {
                                   iX2 = 0;
                                   // The width of Sobel matrix
                                   for ( iX1 = iX - iR; iX1 <= iX + iR; iX1++ )
                                   {
                                       // Get value of pixel
                                       iPixel = mBitmap.getPixel(iX1, iY1);
                                       // To get value of the red channel.
                                       iRed = Color.red(iPixel);
                                       // To get value of the green channel.
                                       iGreen = Color.green(iPixel);
                                       // To get value of the blue channel.
                                       iBlue = Color.blue(iPixel);
                                       // Compute value of gray.
                                       fYofYUV = ( 0.299 * iRed ) + ( 0.587f * iGreen ) + ( 0.114f * iBlue );
                                       // To compute Sobel matrix, we transform float to integer.
                                       iYofYUV = (int) fYofYUV;
                                       // Convolution computing horizontal of Sobel matrix.  
                                       iValue1 += iYofYUV * iSobel1[iX2][iY2];
                                       // Convolution computing vertical of Sobel matrix.
                                       iValue2 += iYofYUV * iSobel2[iX2][iY2];
                                       iX2++;
                                   }
                                   iY2++;
                                   iX2 = 0;
                               }
                               // Choice maximum value.
                               iValue = Math.max(iValue1, iValue2);
                               // The twenty-four is a magic number.
                               if ( iValue > 24 )
                               {
                                   // Set the pixel is black.
                                   bitmapClone.setPixel(iX, iY, Color.rgb(0, 0, 0));
                               }
                               else
                               {
                                   // Set the pixel is white.
                                   bitmapClone.setPixel(iX, iY, Color.rgb(255, 255, 255));
                               }
                           }
                       }
                       // The height of the image. But we are stepping to three once.
                       for ( iY = 0; iY < bitmapClone.getHeight() - 3; iY+=3 )
                       {
                           // The width of the image. But we are stepping to three once.
                           for ( iX = 0; iX < bitmapClone.getWidth() - 3; iX+=3 )
                           {
                               iY2 = 0;
                               // The height of the matrix.
                               for ( iY1 = iY; iY1 <= iY + 2 ; iY1++ )
                               {
                                   iX2 = 0;
                                   // The width of the matrix.
                                   for ( iX1 = iX; iX1 <= iX + 2; iX1++ )
                                   {
                                       // Get value of pixel
                                       iPixel = mBitmap.getPixel(iX1, iY1);
                                       // To get value of the red channel.
                                       iRed = Color.red(iPixel);
                                       // To get value of the green channel.
                                       iGreen = Color.green(iPixel);
                                       // To get value of the blue channel.
                                       iBlue = Color.blue(iPixel);
                                       // Compute value of gray.
                                       fYofYUV = ( 0.299 * iRed ) + ( 0.587f * iGreen ) + ( 0.114f * iBlue );
                                       // To compute Sobel matrix, we transform float to integer.
                                       iYofYUV = (int) fYofYUV;
                                       // If the gray depth more than the matrix, it should be white.
                                       if ( iYofYUV >= iOrderDither[iX2][iY2] )
                                       {
                                           bitmapClone.setPixel(iX, iY, Color.rgb(255, 255, 255));
                                       }
                                       // Otherwise, it should be black.
                                       else
                                       {
                                           bitmapClone.setPixel(iX, iY, Color.rgb(0, 0, 0));
                                       }
                                       iX2++;
                                   }
                                   iY2++;
                                   iX2 = 0;
                               }
                           }
                       }
                   }
               }
               // Set processed image to display.
               ImgView.setImageBitmap(bitmapClone);
               // Show the height of the image.
               String strInfo = "";
               strInfo = String.valueOf(mBitmap.getHeight());
               txtView.setText(strInfo);
               // Restart camera to preview.
               camera.startPreview();
               // To disable auto focus of callback function. 
               camera.autoFocus(null);
           }
        };


        // To establish Camera.AutoFocusCallback
        mAutoFocusCB = new AutoFocusCallback(){
            @Override
            public void onAutoFocus(boolean success, Camera camera){
                // When auto focus is done and then we will take a picture.
                if ( success == true )
                {
                    // Into take a picture of callback function.
                    camera.takePicture(null, null, mPictureCB);                    
                }
            }
        };

        // While a user press the take a picture button, when it starts auto focus.
        btn_Capture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try{
                    // To make sure the camera is open.
                    if(mCamera != null){
                        // Create a thread.
                        new Thread(new Runnable() {
                            public void run() {
                                // To execute the auto focus.
                                mCamera.autoFocus(mAutoFocusCB);
                            }
                          }).start();
                    }
                }catch(Exception e) {
                    e.printStackTrace();
                }
            }
        });         

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub
        // Get parameters of the camera.
        Camera.Parameters parameters = mCamera.getParameters();
        // Set size of the picture.
        parameters.setPictureSize(640, 480);
        // Set size of preview.
        parameters.setPreviewSize(width, height);
        // Set auto focus.
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        // Set parameters of the camera.
        mCamera.setParameters(parameters);
        // Start preview.
        mCamera.startPreview();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        // If the camera is initially successful and then to open camera.
        if ( mCamera == null )
        {
            mCamera = Camera.open();
        }
        try {
            // Set SurfaceHolder.
            mCamera.setPreviewDisplay(holder);
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        // Stop preview.
        mCamera.stopPreview();        
        // Release Camera.
        mCamera.release();
    }

}

image.png

image.png

You can download source code and binary code, the hyperlink is https://drive.google.com/file/d/0BzHb_OyLyVZlOFlFbVpOd0tRbVk/view?usp=sharing
MD5: 0bcefd51cf373542fae4456a9b1659eb

Exception

  1. For debug, you should enable USB debug with your android phone.

Refernce

None.

Acknowledge

Thank you (Android, Eclipse) very much for this great development utility.

Popular posts from this blog

Python 日期與時間的處理

Visual Basic 6.0 (VB6) 程式語言案例學習 (10. 條碼列印程式)

寫作:波蘭文學習之旅:1-1. 波蘭文字母與發音(注音版)

Python 日期與時間的處理

Image

Visual Basic 6.0 (VB6) 程式語言案例學習 (10. 條碼列印程式)

Image

寫作:波蘭文學習之旅:1-1. 波蘭文字母與發音(注音版)

Image

數位影像處理:最佳化處理策略之快速消除扭曲演算法

Image

Visual Basic 6.0 (VB6) 程式語言案例學習 (04. 人事考勤管理系統)

Image

用10種程式語言做影像二值化(Image binarization)

Visual Basic 6.0 (VB6) 程式語言案例學習 (07. 收據列印程式)

Image

Visual Basic .Net (VB.Net) 程式語言案例學習 (03. 場地預約系統)

Image

Visual Basic 6.0 (VB6) 程式語言案例學習 (11. 生產線拍照程式)

Image

Visual Basic .Net (VB.Net) 程式語言案例學習 (06. 題庫測驗系統)

Image