Android - HDR Camera

 

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

Теперь давайте перейдем в режим правки 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 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. Уже сейчас можно скомпилировать и запустить проект - мы будем видеть результат “зрения” нашей камеры.

Давайте теперь научим наше приложение делать снимки и сохранять их. Сначала нужно добавить обработчик нажатия кнопки “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();
	}
};

На этом пока остановимся. Продолжим в следующей части статьи.

Скачать исходный код к статье:
AndroidHDRCam.zip (1508)

 Оставить комментарий

(required)

(required)

Вы можете использовать HTML теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2011 3D-Orange.com.ua
e-mail me

3D-Orange.com.ua is proudly powered by WordPress.
Suffusion theme by Sayontan Sinha