Mengatur Wilayah Focus Pada Kamera Di Android


Kamera pada dasarnya bekerja mirip seperti pada mata manusia. Bedanya, pada mata manusia, tergantung pada jarak benda yang dilihat, lensa mata manusia akan melakukan perubahan bentuk. Proses yang disebut accomodation ini dibutuhkan agar cahaya tetap dipantulkan secara benar pada retina. Sebagai contoh, pada saat melihat benda yang jauh, lensa mata akan menjadi pipih (sehingga terlihat tipis) dan pada saat melihat benda dalam jarak sangat dekat, lensa mata akan berkontraksi sehingga menjadi tebal.

Lalu bagaimana dengan lensa pada kamera? Karena tidak bisa fleksibel seperti mata manusia, lensa kamera perlu melakukan pergeseran posisi. Bila tidak tepat, gambar yang dihasilkan oleh kamera akan terlihat kabur. Pada era manual focus, pengguna kamera perlu mengukur jarak objek yang hendak dipotret secara manual lalu mengubah posisi lensa kamera sesuai dengan jarak tersebut. Kamera pada perangkat Android umumnya tidak memiliki kemampuan manual focus, melainkan auto focus.

Berkat auto focus, pengguna tidak perlu mengatur fokus secara manual. Driver kamera akan melakukan kalkulasi dan menentukan apakah gambar buram atau tidak. Bila buram, fokus akan terus berubah hingga tercapai sebuah gambar yang jernih. Selain itu, bila method startFaceDetection() dari Camera dipanggil, driver kamera akan mendeteksi wajah dan secara otomatis melakukan fokus ke wajah supaya tidak ada wajah yang ‘buram’. Bila tidak memotret wajah, driver kamera juga bisa melakukan auto focus berdasarkan informasi wilayah di preview kamera yang diberikan oleh pengguna melalui method setFocusAreas() milik Camera.Parameters. Informasi ini hanya sebagai masukan bagi driver kamera sehingga hasil akhir fokus kamera bisa saja berbeda.

Sebagai latihan, saya akan meneruskan latihan pada proyek Memakai Efek Warna Di Kamera Pada Android dan menambahkan fitur dimana pengguna bisa menentukan wilayah dan nilai fokus. Saya akan membuat sebuah View yang memiliki ukuran yang sama dengan CameraPreview dimana pengguna dapat menarik layar untuk membuat persegi panjang. Sebagai contoh, saya akan memberinya nama FocusEditView dengan isi kode program seperti berikut ini:

public class FocusEditView extends View {

    private CameraPreview cameraPreview;
    private RectF kotakFokus;
    private Paint paintKotak;
    private boolean drawing;
    private int width, height;

    public FocusEditView(Context context, CameraPreview cameraPreview) {
        super(context);
        paintKotak = new Paint();
        paintKotak.setStyle(Paint.Style.STROKE);
        paintKotak.setColor(Color.YELLOW);
        paintKotak.setStrokeWidth(2);
        drawing = false;
        this.cameraPreview = cameraPreview;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (kotakFokus != null) {
            canvas.drawRect(kotakFokus, paintKotak);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                kotakFokus = new RectF(event.getX(), event.getY(), event.getX(), event.getY());
                drawing = true;
                break;
            case MotionEvent.ACTION_MOVE:
                if (drawing) {
                    kotakFokus.set(kotakFokus.left, kotakFokus.top, event.getX(), event.getY());
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                kotakFokus.set(kotakFokus.left, kotakFokus.top, event.getX(), event.getY());
                invalidate();
                drawing = false;                
                break;
        }
        return true;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        width = cameraPreview.getMeasuredWidth();
        height = cameraPreview.getMeasuredHeight();
        setMeasuredDimension(width, height);
    }

    public Camera.Area getArea() {
        RectF kotakF = new RectF();
        Matrix matrix = new Matrix();
        matrix.postScale(2000.0f / width, 2000.0f / height);
        matrix.postTranslate(-1000, -1000);
        matrix.mapRect(kotakF, kotakFokus);
        Rect kotak = new Rect();
        kotakF.round(kotak);
        Camera.Area hasil = new Camera.Area(kotak, 1000);
        return hasil;
    }

}

Pada View di atas, pengguna dapat menggambar sebuah kotak dengan menahan dan menggeser jarinya di layar sentuh. Saya menyimpan kotak yang dibuat oleh pengguna dalam sebuah variabel bernama kotakFokus yang bertipe RectF. Agar kotak ini dapat dipakai sebagai wilayah fokus kamera, saya perlu menerjemahkannya ke dalam koordinat yang dibutuhkan oleh Camera.Area. Pada Canvas, titik (0,0) adalah posisi kiri atas layar dan titik (width,height) adalah posisi kanan bawah layar. Sementara itu, pada Camera.Area, titik (-1000,-1000) adalah posisi kiri atas layar dan titik (1000,1000) adalah posisi kanan bawah layar. Nilai 0 sampai 1.000 ini tidak dipengaruhi oleh ukuran layar sehingga layar selalu dianggap sebagai sebuah kotak dengan ukuran 2.000 x 2.000. Untuk menerjemahkan koordinat Canvas menjadi koordinat Camera.Area, saya menggunakan bantuan Matrix yang diaplikasikan pada RectF dengan menggunakan method mapRect(). Setelah itu, saya perlu menerjemahkan RectF yang memiliki nilai dalam tipe float menjadi Rect yang memiliki nilai dalam tipe integer. Caranya adalah dengan memanggil method round() milik RectF. Setelah selesai, saya menghasilkan sebuah Camera.Area dengan nilai weight berupa 1.000 yang berarti fokus maksimal pada wilayah ini.

FocusEditView harus ditampilkan secara transparan di atas CameraPreview sehingga memberikan kesan seolah-olah pengguna menggambar kotak pada CameraPreview. Untuk itu, saya menambahkan baris berikut ini pada method onCreateView() di PreviewFragment:

public class PreviewFragment extends Fragment implements View.OnClickListener {

    private CameraPreview cameraPreview;
    private FocusEditView focusEditView;

    public PreviewFragment() {}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ...
        FrameLayout framePreview = (FrameLayout) view.findViewById(R.id.preview);
        cameraPreview = new CameraPreview(activity, activity.getCamera());
        framePreview.addView(cameraPreview);
        focusEditView = new FocusEditView(activity, cameraPreview);
        focusEditView.setBackgroundResource(android.R.color.transparent);
        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
        focusEditView.setLayoutParams(lp);
        framePreview.addView(focusEditView);
        ...
    }

}

Sekarang, bila saya menjalankan aplikasi, saya bisa menggambar kotak di layar seperti pada gambar berikut ini:

Menggambar Kotak Pada Preview Kamera

Menggambar Kotak Pada Preview Kamera

Untuk mengatur fokus pada kotak yang digambar pengguna, saya menambahkan sebuah Button baru di preview_fragment.xml dengan id berupa btnFokus. Handler untuk Button ini akan memanggil method pilihFokus() yang isinya seperti berikut ini:

public void pilihFokus(final Camera.Area areaFokus) {
  camera.cancelAutoFocus();
  Camera.Parameters params = camera.getParameters();
  params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
  List<Camera.Area> daftarFokus = new ArrayList<>();
  daftarFokus.add(areaFokus);
  params.setFocusAreas(daftarFokus);
  camera.setParameters(params);
  camera.autoFocus(new Camera.AutoFocusCallback() {
    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        Log.d("MyCam", "Mengatur fokus ke " + areaFokus.rect + ". Status sukses: " + success);
    }
  });
}

Pada kode program di atas, saya berpindah ke modus Camera.Parameters.FOCUS_MODE_AUTO dengan menggunakan setFocusMode(). Setelah itu, saya mengatur wilayah yang disarankan sebagai sasaran fokus dengan menggunakan setFocusAreas(). Setelah itu, saya harus memanggil method autoFocus() dari Camera agar pencarian fokus dilakukan.

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: