Обработка предварительного просмотра камеры на Android - PullRequest
1 голос
/ 02 марта 2012

Я делаю линейного последователя для своего робота на Android (для изучения программирования на Java / Android), в настоящее время я сталкиваюсь с проблемой обработки изображений: предварительный просмотр камеры возвращает формат изображения с именем YUV, который я хочу преобразовать в порог, чтобы узнать, где находится линия, как можно это сделать?

На данный момент мне удалось получить что-то , то есть я определенно могу читать данные из предварительного просмотра с камеры и каким-то чудом даже знать, превышает ли интенсивность света определенное значение или превышает его на определенном уровне. область на экране. Моя цель - нарисовать путь робота с помощью наложения поверх предварительного просмотра камеры, что тоже в некоторой степени работает, но проблема в управлении YUV.

Galaxy Nexus Screenshot

Как вы видите, не только темная область нарисована вбок, но также повторяется 4 раза и изображение предварительного просмотра растянуто, я не могу понять, как решить эти проблемы.

Вот соответствующая часть кода:

public void surfaceCreated(SurfaceHolder arg0) {
    // TODO Auto-generated method stub

    // camera setup
    mCamera = Camera.open();

    Camera.Parameters parameters = mCamera.getParameters();
    List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
    for(int i=0; i<sizes.size(); i++)
    {
        Log.i("CS", i+" - width: "+sizes.get(i).width+" height: "+sizes.get(i).height+" size: "+(sizes.get(i).width*sizes.get(i).height));
    }

    // change preview size
    final Camera.Size cs = sizes.get(8);
    parameters.setPreviewSize(cs.width, cs.height);

    // initialize image data array
    imgData = new int[cs.width*cs.height];

    // make picture gray scale
    parameters.setColorEffect(Camera.Parameters.EFFECT_MONO);
    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
    mCamera.setParameters(parameters);

    // change display size
    LayoutParams params = (LayoutParams) mSurfaceView.getLayoutParams();
    params.height = (int) (mSurfaceView.getWidth()*cs.height/cs.width);
    mSurfaceView.setLayoutParams(params);

    LayoutParams overlayParams = (LayoutParams) swOverlay.getLayoutParams();
    overlayParams.width = mSurfaceView.getWidth();
    overlayParams.height = mSurfaceView.getHeight();
    swOverlay.setLayoutParams(overlayParams);

    try
    {
        mCamera.setPreviewDisplay(mSurfaceHolder);
        mCamera.setDisplayOrientation(90);
        mCamera.startPreview();
    }
    catch (IOException e)
    {
        e.printStackTrace();
        mCamera.stopPreview();
        mCamera.release();
    }

    // callback every time a new frame is available
    mCamera.setPreviewCallback(new PreviewCallback() {
        public void onPreviewFrame(byte[] data, Camera camera)
        {
            // create bitmap from camera preview
            int pixel, pixVal, frameSize = cs.width*cs.height;
            for(int i=0; i<frameSize; i++)
            {
                pixel = (0xff & ((int) data[i])) - 16;
                if(pixel < threshold)
                {
                    pixVal = 0;
                }
                else
                {
                    pixVal = 1;
                }
                imgData[i] = pixVal;
            }

            int cp = imgData[(int) (cs.width*(0.5+(cs.height/2)))];

            //Log.i("CAMERA", "Center pixel RGB: "+cp);
            debug.setText("Center pixel: "+cp);

            // process preview image data
            Paint paint = new Paint();
            paint.setColor(Color.YELLOW);


            int start, finish, last;
            start = finish = last = -1;
            float x_ratio = mSurfaceView.getWidth()/cs.width;
            float y_ratio = mSurfaceView.getHeight()/cs.height;

            // display calculated path on overlay using canvas
            Canvas overlayCanvas = overlayHolder.lockCanvas();
            overlayCanvas.drawColor(0, Mode.CLEAR);

            // start by finding the tape from bottom of the screen      
            for(int y=cs.height; y>0; y--)
            {
                for(int x=0; x<cs.width; x++)
                {
                    pixel = imgData[y*cs.height+x];

                    if(pixel == 1 && last == 0 && start == -1)
                    {
                        start = x;
                    }
                    else if(pixel == 0 && last == 1 && finish == -1)
                    {
                        finish = x;
                        break;
                    }
                    last = pixel;
                }
                //overlayCanvas.drawLine(start*x_ratio, y*y_ratio, finish*x_ratio, y*y_ratio, paint);
                //start = finish = last = -1;
            }
            overlayHolder.unlockCanvasAndPost(overlayCanvas);
        }
    });
}

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


UPDATE:

Теперь, когда проблема с ориентацией устранена (ориентация датчика CCD) Я все еще сталкиваюсь с проблемой повторения, это, вероятно, связано с моим управлением данными YUV ...

enter image description here

1 Ответ

2 голосов
/ 02 марта 2012

Ваше управление поверхностью и камерой выглядит корректно, но я бы дважды проверил, чтобы камера действительно принимала настройки размера предварительного просмотра (некоторые реализации камеры отклоняют некоторые настройки молча)

Поскольку вы работаете с портретным режимом, вы должны иметь в виду, что камера не дает никаких шуток в отношении ориентации телефона - ее начало координат определяется ПЗС-матрицей и всегда направо, а направление сканирования - сверху вниз и справа налево - сильно отличается от вашего наложения холста. (Но если вы находитесь в ландшафтном режиме, все правильно;)) - это определенно источник нечетного результата рисования

Ваш порог немного наивен и не очень полезен в реальной жизни - я бы предложил адаптивный порог. В нашем проекте javaocr (чистая java, также есть демоверсии Android) мы реализовали эффективную бинаризацию сауволы (см. Демонстрации):

http://sourceforge.net/projects/javaocr/

Бинаризация производительности может быть улучшена для работы только с одиночными строками изображения (исправления приветствуются)

Проблема с ультрафиолетовой частью изображения проста - по умолчанию используется формат NV21, сначала идет яркость и это всего лишь поток байтов, и вам вообще не нужна ультрафиолетовая часть изображения (см. демонстрацию выше)

...