Sunday, July 15, 2012

Cara Mengakses Kamera pada Android

contoh penggunaan kamera

Kamera adalah sensor yang paling terlihat dan paling sering digunakan dalam sebuah device android. Kamera adalah titik jual untuk sebagian besar, pembeli, dan kemampuan kamera semakin baik untuk tiap generasinya.
Aplikasi pengolahan citra biasanya bekerja pada sebuah citra setelah citra tersebut diambil, namun aplikasi lainnya, seperti augmented reality, menggunakan kamera secara langsung(real-time) dengan lapisan-lapisan aplikasi. Terdapat dua cara untuk mengakses kamera dari sebuah aplikasi. Pertama dengan mendeklarasikan intent secara implicit.
Intent implicit meluncurkan interface kamera default:
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
startActivity(intent);

cara berikutnya lebih mengangkat kelas Kamera, yang mana menyediakan lebih banyak fleksibilitas dalam setting. Cara ini membuat sebuah interface kamera yang sudah diubah, yang mana menjadi focus dalam contoh berikut. untuk mengakses perangkat keras Kamera membutuhkan permission eksplisit dalam file XML AndroidManifest:
<uses-permission android:name="android.permission.CAMERA" />
yang mana lebih lengkapnya bisa dilihat dalam contoh berikut.
Mengembangkan Kamera
Kendali terhadap kamera diabstraksikan kedalam berbagai komponen dalam sistem android:
-    Class Camera digunakan untuk mengakses hardware kamera
-    Class Camera.Parameters menunjukkan parameter kamera seperti ukuran gambar, kualitas gambar, mode flash, dan cara untuk memberikan lokasi Global Positioning System(GPS).
-    Method Camera Preview menentukan tampilan output kamera dan menyalakan streaming preview kamera pada layar.
-    Class SurfaceView digunakan sebagai permukaan gambar pada tingkat terendah dari hirarki view(tampilan) sebagai tempat pemegang(placeholder) untuk menampilka preview kamera.
Sebelum menjelaskan bagaimana komponen tersebut digabungkan, struktur layout akan ditunjukkan. Layout utama ditunjukkan pada kode 7.1 dan memasukkan sebuah SurfaceView untuk memegang output kamera.
Kode 7.1 res/layout/main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<SurfaceView android:id="@+id/surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</SurfaceView>
</LinearLayout>

Sebuah interface kendali bisa ditambahkan di atas view ini dengan menggunakan sebuah layout yang terpisah, seperti yang ditunjukkan pada kode 7.2 berikut. layout ini memuat tombol pada tengah bawah dari layar untuk mengambil gambar.

Kode 7.2 res/layout/cameraoverlay.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="bottom"
android:layout_gravity="bottom">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="take picture"
/>
</LinearLayout>
</LinearLayout>
Activity utama melibatkan banyak fungsionalitas. Pertama, layout bekerja sebagai berikut:
1.    Setting window diubah untuk menyala dan full scree. Dalam contoh ini, setting akan menyembunyikan title dan bar notifikasi.
2.    SurfaceView yang ditunjukkan dalam layout sebelumnya (R.id.surface) kemudian diisi oleh camera preview. Tiap SurfaceView berisi sebuah SurfaceHolder untuk akses dan kendali pada surface. Activity ditambahkan sebagai callback untuk SurfaceHolder dan jenisnya dipasang SURFACE_TYPE_PUSH_BUFFERS, yang mana berarti SurfaceHolder memciptakan sebuah surface PUSH dan object tidak menyimpan buffer. Hal ini akan membuat streaming lebih efisien.
3.    Sebuah LayoutInflater dibuat untuk meng-inflate layout lainnya (cameraoverlay.xml) pada layout asal (main.xml).
Berikutnya, activity mengatur sebuah pemicu untuk mengambil sebuah gambar:
1.    Sebuah OnClickListener ditambahkan pada tombol dari layout cameraoverlay.xml, sehingga ketika diklik, akan mengambil gambar (mCamera.takePicture()).
2.    Method takePicture() membutuhkan tiga method untuk didefinisikan:
a.    ShutterCallback() untuk mendefinisikan efek apapun yang dibutuhkan setelah gambar diambil, seperti sebuah suara untuk memberi tahu pengguna bahwa gambar telah diambil.
b.    Sebuah PictureCallback() untuk data gambar mentah jika hardware mempunyai memori yang cukup untuk menunjang fitur ini jika tidak, data akan dikembalikan berupa null.
c.    Sebuah PictureCallback() kedua untuk data gambar yang terkompres.  Ini memanggil method local done() untuk menyimpan gambar.
Kemudian, activity menyimpan gambar apapun yang diambil:
1.    Array byte Gambar yang dikompres disimpan pada sebuah variable local tempdata. BitmapFactory digunakan untuk meenerjemahkan ByteArray menjadi sebuah object Bitmap.
2.    Media content provider digunakan untuk menyimpan bitmap dan mengembalikan sebuah URL. Jika activity utama ini dipanggil oleh activity lainnya, URL ini akan menjadi infomasi yang dikembalikan pada activity pemanggil untuk menyerahkan gambar.
3.    Setelah process ini, finish() dipanggil untuk mengakhiri activity.
Terakhir, activity mengatur sebuah response untuk sebuah perubahan dalam surface view:
1.    Sebuah interface SurfaceHolder.CallBack diterapkan. Interface ini membutuhkan tiga method untuk dioverride:
a.    surfaceCreated() adalah method yang dipanggil saat surface pertama kali dibuat. Inisialisasikan object di sini.
b.    surfaceChanged() adalah method yang dipanggil setelah pembuatan surface dan ketika surface berubah misalkan format atau ukuran.
c.    surfaceDestroyed() adalah method yang dipanggil antara penghilangan surface dari view pengguna dan penghancuran surface. Ini digunakan ketika surface. Ini digunakan untuk pembersihan memori.
2.    Parameter untuk kamera diubah ketika surface diubah misalkan berdasarkan PreviewSize yang berbasis pada ukuran surface.
Fungsionalitas tersebut ditunjukkan dalam activity secara menyeluruh yang ditunjukkan pada kode 7.3.
Kode 7.3 src/com/hhn/CameraApplication.java
package com.hhn;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.provider.MediaStore.Images;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.Toast;
public class CameraApplication extends Activity
implements SurfaceHolder.Callback {
private static final String TAG = "cookbook.hardware";
private LayoutInflater mInflater = null;
Camera mCamera;
byte[] tempdata;
boolean mPreviewRunning = false;
private SurfaceHolder mSurfaceHolder;
private SurfaceView mSurfaceView;
Button takepicture;
@Override
public 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.main);
mSurfaceView = (SurfaceView)findViewById(R.id.surface);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mInflater = LayoutInflater.from(this);
View overView = mInflater.inflate(R.layout.cameraoverlay, null);
this.addContentView(overView,
new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
takepicture = (Button) findViewById(R.id.button);
takepicture.setOnClickListener(new OnClickListener(){
public void onClick(View view){
mCamera.takePicture(mShutterCallback,
mPictureCallback, mjpeg);
}
});
}
ShutterCallback mShutterCallback = new ShutterCallback(){
@Override
public void onShutter() {}
};
PictureCallback mPictureCallback = new PictureCallback() {

public void onPictureTaken(byte[] data, Camera c) {}
};
PictureCallback mjpeg = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera c) {
if(data !=null) {
tempdata=data;
done();
}
}
};
void done() {
Bitmap bm = BitmapFactory.decodeByteArray(tempdata,
0, tempdata.length);
String url = Images.Media.insertImage(getContentResolver(),
bm, null, null);
bm.recycle();
Bundle bundle = new Bundle();
if(url!=null) {
bundle.putString("url", url);
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK, mIntent);
} else {
Toast.makeText(this, "Picture can not be saved",
Toast.LENGTH_SHORT).show();
}
finish();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int w, int h) {
Log.e(TAG, "surfaceChanged");
try {
if (mPreviewRunning) {
mCamera.stopPreview();
mPreviewRunning = false;
}
Camera.Parameters p = mCamera.getParameters();
p.setPreviewSize(w, h);
mCamera.setParameters(p);
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
mPreviewRunning = true;
} catch(Exception e) {
Log.d("",e.toString());
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e(TAG, "surfaceCreated");
mCamera = Camera.open();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e(TAG, "surfaceDestroyed");
mCamera.stopPreview();
mPreviewRunning = false;
mCamera.release();
mCamera=null;
}
}

Perlu dicatat preview kamera dari hardware kamera tidak distandarisasi, dan beberapa perangkat android mungkin menunjukkan preview dengan cara yang lain. Dalam kasus ini, cukup tambahkan kode berikut pada method onCreate() dari activity CameraPreview:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
cara ini saya dapat dari buku : James Steele, Nelso To. The Android Developer’s Cookbook. Addison-Wesley.
soruce code lengkap dan contoh projectnya bisa anda download di sini

3 comments:

  1. mau tanya bang, kalo untuk aplikasi yang membaca piksel di livepreview camera berarti ditaruh di method surfaceChanged()bukan?
    dan juga saya kesulitan untuk mengambil nilai piksel dari livepreview tsb, karena pada objek surfaceview itu tidak bisa digunakan getPixel() seperti pada imageview.
    mohon bantuannya..

    ReplyDelete
  2. gan kalo mau gunain kamera untuk mendeteksi bentuk benda berdasarkan warnanya bisa g..??

    ReplyDelete