root@home‎ > ‎

Android - HDR Camera

Здравствуйте уважаемые читатели. Как уже многие из вас знают, в iOS 4.1 появилась новая “фишка” - HDR Photo. Вещь крайне спорная, но довольно интересная. Вот и загорелся я сделть то же и на Android. В Android Market’е конечно же есть программы с похожим функционалом, но нам ведь интересно сделать самим, верно? Итак, приступим. Для начала стоит прочитать мою первую статью “Android: Hello World!” дабы лучше понимать материал.


Для начала нам нужно сделать обычную камеру, а затем добавить в нее обработку HDR. Создадим внешний вид приложения: на AbsoluteLayout положим SurfaceView, а на него - CheckBox и Button. Все это должно выглядеть примерно так:


Рисунок 1 - Внешний вид нашего приложения

    Теперь давайте перейдем в режим правки XML и заменим тег SurfaceView на com.iorange.hdrcam.PreviewSurface (у вас название класса может отличаться). PreviewSurface будет у нас основным классом логики камеры, а так же на него будет выводиться Preview камеры.

public class PreviewSurface extends SurfaceView implements SurfaceHolder.Callback

Этот класс должен реализовывать три метода: surfaceChanged, surfaceCreated и surfaceDestroyed. Так же этот Surface нужно зарегистрировать на получение сообщений в SurfaceHolder’e.

public PreviewSurface(Context context, AttributeSet attrs)
{
super(context, attrs);

m_Holder = getHolder();
m_Holder.addCallback(this);
m_Holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

Для доступа к камере нам нужно заявить о своих намерениях в манифесте. Для этого добавьте в manifest сразу за application следующие теги:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Последний тег нужен для записи файлов на SD-карточку. Для доступа к Camera API есть класс android.hardware.Camera. Документация по нему есть на сайте разработчиков Android - http://developer.android.com/reference/android/hardware/Camera.html.

Для начала создадим объект класса Camera вызовом статического метода Camera.open(); Лучше всего это сделать в методе surfaceCreated.

@Override
public void surfaceCreated(SurfaceHolder holder)
{
m_Camera = Camera.open();
try
{
m_Camera.setPreviewDisplay(holder);
}
catch (IOException e)
{
e.printStackTrace();
m_Camera.release();
m_Camera = null;
}
}

После создания камеры мы устанавливаем нашу поверхность (Surface) в качестве экрана предпросмотра методом setPreviewDisplay. Этот метод может бросаться исключениями - посему окружим его try-catch. Следуя хорошим традициям сразу же позаботимся об освобождении камеры - добавим в метод surfaceDestroyed код для освобождения камеры:

@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
m_Camera.stopPreview();
m_Camera.release();
m_Camera = null;
}

Отлично, камера инициализируется и корректно освобождается. Теперь нужно заставить камеру выводить изображение на нашу поверхность. Для этого в у класса Camera есть метод startPreview, однако вызывать его можно только если камере установлен SurfaceHolder требуемой поверхности (что мы сделали раньше в методе surfaceCreated) и сама поверхность полностью иниализирована и готова. То есть делать это лучше всего в методе surfaceChanged:

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
Camera.Parameters parameters = m_Camera.getParameters();

List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, width, height);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);

m_Camera.setParameters(parameters);
m_Camera.startPreview();
m_CanDoPhoto = true;
}

Здесь мы узнаем у камеры список поддерживаемых ею размеров превью и подбиравем подходящий методом getOptimalPreviewSize (реализация которого была полностью содрана с Android SDK). И в конце-концов стартуем превью методом startPreview. Уже сейчас можно скомпилировать и запустить проект - мы будем видеть результат “зрения” нашей камеры.

Рисунок 2 - скриншот рабочей программы


Давайте теперь научим наше приложение делать снимки и сохранять их. Сначала нужно добавить обработчик нажатия кнопки “Photo!”. Сделаем это в нашем Activity:

btnPhoto.setOnClickListener(btnPhoto_OnClick);
View.OnClickListener btnPhoto_OnClick = new View.OnClickListener()
{
public void onClick(View v)
{
m_View.TakePicture();
}
};

Теперь реализуем метод TakePicture в нашем PreviewSurface.

public void TakePicture()
{
if (m_Camera != null && m_CanDoPhoto)
{
m_CanDoPhoto = false;
m_Camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
}
Метод takePicture принимает 3 колбека - shutterCallback, rawCallback и jpegCallback.
shutterCallback вызывается сразу после захвата кадра - здесь, например, можно проигрывать звук щелчка затвора.
rawCallback даст нам сырые (RAW) данные картинки - без обработок и сжатия (именно эти данные мы и будем использовать для HDR корректировки).
jpegCallback даст нам уже готовую JPEG-сжатую картинку.

Давайте для начала сделаем возможность простой съемки - без HDR корректировки. Для этого для первых 2-х коллбеков мы сделаем пустые заглушки и реализуем jpegCallback. В jpegCallback мы просто будем записывать пришедшую картинку на SD-карточку.

ShutterCallback shutterCallback = new ShutterCallback()
{
public void onShutter()
{
   // TODO Do something when the shutter closes.
}
};

PictureCallback rawCallback = new PictureCallback()
{
public void onPictureTaken(byte[] _data, Camera _camera)
{
   // TODO Do something with the image RAW data.
}
};

PictureCallback jpegCallback = new PictureCallback()
{
public void onPictureTaken(byte[] _data, Camera _camera)
{
String path = Environment.getExternalStorageDirectory().toString();
File file = new File(path, "MyTestPhoto.jpg");
try
{
FileOutputStream fOut = new FileOutputStream(file);
fOut.write(_data);
fOut.flush();
            fOut.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}

m_CanDoPhoto = true;
m_Camera.startPreview();
}
};


На этом пока остановимся. Продолжим в следующей части статьи.
PS. Как обычно - исходник к статье прилагается.
ċ
HDRCam.zip
(49k)
Sergey iOrange,
Sep 13, 2010, 4:25 AM
Comments