Introduction
Sometimes, we just find it fun to take a picture. Let’s take a different funny picture. We can develop it by ourselves. 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, we wait for the auto focus to finish when we take a picture. That is why we need to overwrite auto focus method to help us take a clear picture.
Secondly, while the image processing computes, we need to transform raw data to bitmap format. We used bitmap factory to help us do this transform.
Thirdly, there are two image processing that are 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 dividing 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 using 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 are 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 it is preparing auto focus and taking a picture of callback function. You just follow this architecture and then add new image effect. In this study, this app will open your camera before you choose image effect and then you choose 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 tip to help beginners in the camera app development. All code is presented in this tip. I need you to be a little patient to read. And then, you will find that out so easily.
Background
Equipment Operation System: Android 4.1.2 Development Utility: Eclipse ADT
Using the Code
File Name: AndroidManifest.xml
="1.0"="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);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
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);
SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
iImageProcessingId = 0;
rdg_Main.setOnCheckedChangeListener( new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if ( checkedId == rdb_Gray.getId() )
{
iImageProcessingId = 0;
}
else if ( checkedId == rdb_Comic.getId() )
{
iImageProcessingId = 1;
}
}
});
mPictureCB = new PictureCallback(){
@Override
public void onPictureTaken(byte[] data, Camera camera){
Bitmap mBitmap = BitmapFactory.decodeByteArray(data, 0 , data.length);
bitmapClone = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(),
mBitmap.getConfig());
bitmapClone.copy(mBitmap.getConfig(), true);
if ( true )
{
int iY = 0;
int iX = 0;
int iPixel = 0;
int iRed = 0;
int iGreen = 0;
int iBlue = 0;
int iRGBAvg = 0;
if ( iImageProcessingId == 0 )
{
for ( iY = 0; iY < bitmapClone.getHeight(); iY++ )
{
for ( iX = 0; iX < bitmapClone.getWidth(); iX++ )
{
iPixel = mBitmap.getPixel(iX, iY);
iRed = Color.red(iPixel);
iGreen = Color.green(iPixel);
iBlue = Color.blue(iPixel);
iRGBAvg = ( iRed + iGreen + iBlue ) / 3;
bitmapClone.setPixel(iX, iY, Color.rgb(iRGBAvg, iRGBAvg, iRGBAvg));
}
}
}
else if ( iImageProcessingId == 1 )
{
int iSobel1 [][]= { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 }};
int iSobel2 [][]= { { -1, 0, -1 }, { -2, 0, 2 }, { 1, 0, 1 }};
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;
int iX2 = 0;
int iY2 = 0;
for ( iY = 1; iY < bitmapClone.getHeight() - 1; iY++ )
{
for ( iX = 1; iX < bitmapClone.getWidth() - 1; iX++ )
{
iY2= 0;
iValue1 = 0;
iValue2 = 0;
for ( iY1 = iY - iR; iY1 <= iY + iR; iY1++ )
{
iX2 = 0;
for ( iX1 = iX - iR; iX1 <= iX + iR; iX1++ )
{
iPixel = mBitmap.getPixel(iX1, iY1);
iRed = Color.red(iPixel);
iGreen = Color.green(iPixel);
iBlue = Color.blue(iPixel);
fYofYUV = ( 0.299f * iRed ) + ( 0.587f * iGreen ) +
( 0.114f * iBlue );
iYofYUV = (int) fYofYUV;
iValue1 += iYofYUV * iSobel1[iX2][iY2];
iValue2 += iYofYUV * iSobel2[iX2][iY2];
iX2++;
}
iY2++;
iX2 = 0;
}
iValue = Math.max(iValue1, iValue2);
if ( iValue > 24 )
{
bitmapClone.setPixel(iX, iY, Color.rgb(0, 0, 0));
}
else
{
bitmapClone.setPixel(iX, iY, Color.rgb(255, 255, 255));
}
}
}
for ( iY = 0; iY < bitmapClone.getHeight() - 3; iY+=3 )
{
for ( iX = 0; iX < bitmapClone.getWidth() - 3; iX+=3 )
{
iY2 = 0;
for ( iY1 = iY; iY1 <= iY + 2 ; iY1++ )
{
iX2 = 0;
for ( iX1 = iX; iX1 <= iX + 2; iX1++ )
{
iPixel = mBitmap.getPixel(iX1, iY1);
iRed = Color.red(iPixel);
iGreen = Color.green(iPixel);
iBlue = Color.blue(iPixel);
fYofYUV = ( 0.299f * iRed ) + ( 0.587f * iGreen ) +
( 0.114f * iBlue );
iYofYUV = (int) fYofYUV;
if ( iYofYUV >= iOrderDither[iX2][iY2] )
{
bitmapClone.setPixel(iX, iY, Color.rgb(255, 255, 255));
}
else
{
bitmapClone.setPixel(iX, iY, Color.rgb(0, 0, 0));
}
iX2++;
}
iY2++;
iX2 = 0;
}
}
}
}
}
ImgView.setImageBitmap(bitmapClone);
String strInfo = "";
strInfo = String.valueOf(mBitmap.getHeight());
txtView.setText(strInfo);
camera.startPreview();
camera.autoFocus(null);
}
};
mAutoFocusCB = new AutoFocusCallback(){
@Override
public void onAutoFocus(boolean success, Camera camera){
if ( success == true )
{
camera.takePicture(null, null, mPictureCB);
}
}
};
btn_Capture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try{
if(mCamera != null){
new Thread(new Runnable() {
public void run() {
mCamera.autoFocus(mAutoFocusCB);
}
}).start();
}
}catch(Exception e) {
e.printStackTrace();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPictureSize(640, 480);
parameters.setPreviewSize(width, height);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if ( mCamera == null )
{
mCamera = Camera.open();
}
try {
mCamera.setPreviewDisplay(holder);
}catch(Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
}
}
Exception
- For debug, you should enable USB debug with your Android phone.
Acknowledgement
Thank you (Android, Eclipse) very much for this great development utility.