Применение пользовательских фильтров к выходу камеры

Как применить специальные фильтры к одиночным кадрам на выходе камеры и показать их.

То, что я пробовал до сих пор:

mCamera.setPreviewCallback(new CameraGreenFilter()); public class CameraGreenFilter implements PreviewCallback { @Override public void onPreviewFrame(byte[] data, Camera camera) { final int len = data.length; for(int i=0; i<len; ++i){ data[i] *= 2; } } } 

Есть ли более простой способ? Иначе, как это будет работать с openGL-surfaceView?

Хорошо, есть несколько способов сделать это. Но есть существенная проблема с производительностью. Байт [] из камеры находится в формате YUV , который нужно преобразовать в какой-то формат RGB, если вы хотите его отобразить. Это преобразование довольно дорогостоящее и значительно снижает выходной сигнал fps.

Это зависит от того, что вы на самом деле хотите сделать с предварительным просмотром камеры. Потому что лучшим решением является нарисовать предварительный просмотр камеры без обратного вызова и внести некоторые эффекты в предварительный просмотр камеры. Это обычный способ сделать аргументированный материал для повторного использования.

Но если вам действительно нужно отображать вывод вручную, есть несколько способов сделать это. Ваш пример не работает по нескольким причинам. Во-первых, вы не показываете изображение вообще. Если вы вызываете это:

 mCamera.setPreviewCallback(new CameraGreenFilter()); mCamera.setPreviewDisplay(null); 

чем ваша камера не отображает предварительный просмотр вообще, вы должны отображать ее вручную. И вы не можете делать никаких дорогостоящих операций в методе onPreviewFrame, поскольку срок службы данных ограничен, он перезаписывается в следующем кадре. Один намек, используйте setPreviewCallbackWithBuffer , он быстрее, потому что он повторно использует один буфер и не должен выделять новую память для каждого кадра.

Поэтому вам нужно сделать что-то вроде этого:

 private byte[] cameraFrame; private byte[] buffer; @Override public void onPreviewFrame(byte[] data, Camera camera) { cameraFrame = data; addCallbackBuffer(data); //actually, addCallbackBuffer(buffer) has to be called once sowhere before you call mCamera.startPreview(); } private ByteOutputStream baos; private YuvImage yuvimage; private byte[] jdata; private Bitmap bmp; private Paint paint; @Override //from SurfaceView public void onDraw(Canvas canvas) { baos = new ByteOutputStream(); yuvimage=new YuvImage(cameraFrame, ImageFormat.NV21, prevX, prevY, null); yuvimage.compressToJpeg(new Rect(0, 0, width, height), 80, baos); //width and height of the screen jdata = baos.toByteArray(); bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length); canvas.drawBitmap(bmp , 0, 0, paint); invalidate(); //to call ondraw again } 

Чтобы выполнить эту работу, вам нужно вызвать setWillNotDraw (false) в конструкторе classа или где-нибудь.

В onDraw вы можете, например, применить paint.setColorFilter (фильтр) , если хотите изменить цвета. Я могу опубликовать несколько примеров этого, если хотите.

Таким образом, это будет работать, но производительность будет низкой (менее 8 кадров в секунду), поэтому BitmapFactory.decodeByteArray работает медленно. Вы можете попробовать конвертировать данные из YUV в RGB с помощью собственного кода и Android NDK, но это довольно сложно.

Другой вариант – использовать openGL ES. Вам нужен GLSurfaceView, где вы привязываете рамку камеры как текстуру (в GLSurfaceView реализуется Camera.previewCallback, поэтому вы используете onPreviewFrame так же, как и на обычной поверхности). Но есть одна и та же проблема, вам нужно преобразовать данные YUV. Есть один шанс – вы можете отображать только данные яркости из предварительного просмотра (изображение в оттенках серого) довольно быстро, потому что первая половина байтового массива в YUV – это только данные яркости без цветов. Итак, onPreviewFrame вы используете arraycopy для копирования первой половины массива, и вы привязываете текстуру следующим образом:

 gl.glGenTextures(1, cameraTexture, 0); int tex = cameraTexture[0]; gl.glBindTexture(GL10.GL_TEXTURE_2D, tex); gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_LUMINANCE, this.prevX, this.prevY, 0, GL10.GL_LUMINANCE, GL10.GL_UNSIGNED_BYTE, ByteBuffer.wrap(this.cameraFrame)); //cameraFrame is the first half od byte[] from onPreviewFrame gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); 

Вы не можете получить около 16-18 кадров в секунду, и вы можете использовать openGL для создания некоторых фильтров. Я могу отправить вам еще несколько кодов, если вы захотите, но это слишком долго, чтобы войти сюда …

Для получения дополнительной информации вы можете увидеть мой simillar вопрос , но нет и хорошего решения …

Interesting Posts

Учебное пособие по камерам для Android (с использованием поверхностного обзора)

Почему основному методу в Java всегда нужны аргументы?

android TextView: настройка фонового цвета динамически не работает

В чем разница между «Class.forName ()» и «Class.forName (). NewInstance ()»?

Как исправить ошибки «Неверное строковое значение»?

Как найти качество JPG?

Сбросить разрешение экрана

Все мои папки и файлы на моем флеш-накопителе были переименованы автоматически, и я больше не могу их открывать … Мне нужны эти файлы

Могу ли я писать в файловую систему на лазурном веб-сайте?

Неявное намерение удалить приложение?

VIM, показывающий «m» возле белого пространства на Cygwin

Передача пустого массива в качестве значения по умолчанию для необязательного параметра

В C #, что происходит, когда вы вызываете метод расширения на нулевом объекте?

Как read.table () несколько файлов в одну таблицу в R?

Контурный эффект для текста

Давайте будем гением компьютера.