Saltar al contenido

Problema de orientación de la cámara OpenCV

Este grupo de redactores ha pasado mucho tiempo investigando la solución a tus interrogantes, te ofrecemos la respuestas por esto deseamos serte de gran ayuda.

Solución:

Ok, encontré esto como una solución:

Primero me meto en JavaCameraView.java clase en el Biblioteca OpenCV – 2.4.5

y luego en initializeCamera() función antes mCamera.startPreview(); Agregué estas 2 funciones:

            setDisplayOrientation(mCamera, 90);
            mCamera.setPreviewDisplay(getHolder());

y la primera función implementada así:

protected void setDisplayOrientation(Camera camera, int angle)
    Method downPolymorphic;
    try
    
        downPolymorphic = camera.getClass().getMethod("setDisplayOrientation", new Class[]  int.class );
        if (downPolymorphic != null)
            downPolymorphic.invoke(camera, new Object[]  angle );
    
    catch (Exception e1)
    
        e1.printStackTrace();
    

Solo les recuerdo que trabajo con OpenCV.

Espero que esto ayude a alguien.

Estoy usando OpenCV 3.1, lo soluciono aplicando la transformación cuando dibujo el mapa de bits en el método deliverAndDrawFrame de la clase CameraBridgeViewBase, espero que sea útil:

En CameraBridgeViewBase.java:

//I added new field
private final Matrix mMatrix = new Matrix();

//added updateMatrix method 
private void updateMatrix() 
    float hw = this.getWidth() / 2.0f;
    float hh = this.getHeight() / 2.0f;
    boolean isFrontCamera = Camera.CameraInfo.CAMERA_FACING_FRONT == mCameraIndex;
    mMatrix.reset();
    if (isFrontCamera) 
        mMatrix.preScale(-1, 1, hw, hh);
    
    mMatrix.preTranslate(hw, hh);
    if (isFrontCamera)
        mMatrix.preRotate(270);
    else
        mMatrix.preRotate(90);
    mMatrix.preTranslate(-hw, -hh);


//then We need call updateMatrix on layout
@Override
public void layout(int l, int t, int r, int b) 
    super.layout(l, t, r, b);
    updateMatrix();


//I think we should also call updateMatrix on measure
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    updateMatrix();



//then We need update deliverAndDrawFrame
protected void deliverAndDrawFrame(CvCameraViewFrame frame) 
    //....Origin Code...

    //Set matrix before OpenCV draw bitmap
    int saveCount = canvas.save();
    canvas.setMatrix(mMatrix);

    //Begin OpenCv origin source
    if (mScale != 0) 
        canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
             new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2),
             (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2),
             (int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
             (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null);
     else 
         canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
             new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,
             (canvas.getHeight() - mCacheBitmap.getHeight()) / 2,
             (canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(),
             (canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null);
    
    //End OpenCv origin source

    //Restore canvas after draw bitmap
    canvas.restoreToCount(saveCount);

    //....Origin code...




//After that We can see that the camera preview is so small, the easiest way is change mScale Value (should we change mScale to "private" instead "protected" ?)
protected void deliverAndDrawFrame(CvCameraViewFrame frame) 
    //....Origin Code...

    //Set matrix before OpenCV draw bitmap to screen
    int saveCount = canvas.save();
    canvas.setMatrix(mMatrix);


    //Change mScale to "Aspect to fill"
    mScale = Math.max((float) canvas.getHeight() / mCacheBitmap.getWidth(), (float) canvas.getWidth() / mCacheBitmap.getHeight());

    //Begin OpenCv origin source
    if (mScale != 0) 
        canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
             new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2),
             (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2),
             (int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
             (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null);
     else 
         canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
             new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,
             (canvas.getHeight() - mCacheBitmap.getHeight()) / 2,
             (canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(),
             (canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null);
    
    //End OpenCv origin source

    //Restore canvas after draw bitmap
    canvas.restoreToCount(saveCount);

    //....Origin Code...

Puede obtener el código fuente completo aquí: https://gist.github.com/thongdoan/d73267eb58863f70c77d1288fe5cd3a4

El problema es que el código que pinta no comprueba los parámetros de la cámara. El tapete se dibuja en la vista de superficie en la función “deliverAndDrawFrame” en la clase “CameraBridgeViewBase”.

Con una modificación muy simple en la clase CameraBridgeViewBase, podemos crear una función que gire la forma en que se dibuja el mapa de bits.

int userRotation= 0;

public void setUserRotation(int userRotation) 
    this.userRotation = userRotation;


/**
 * This method shall be called by the subclasses when they have valid
 * object and want it to be delivered to external client (via callback) and
 * then displayed on the screen.
 * @param frame - the current frame to be delivered
 */
protected void deliverAndDrawFrame(CvCameraViewFrame frame) 
    Mat modified;

    if (mListener != null) 
        modified = mListener.onCameraFrame(frame);
     else 
        modified = frame.rgba();
    

    boolean bmpValid = true;
    if (modified != null) 
        try 
            Utils.matToBitmap(modified, mCacheBitmap);
         catch(Exception e) 
            Log.e(TAG, "Mat type: " + modified);
            Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
            Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
            bmpValid = false;
        
    

    if (bmpValid && mCacheBitmap != null) 
        Canvas canvas = getHolder().lockCanvas();
        if (canvas != null) 
            canvas.drawColor(Color.parseColor("#8BC34A"), PorterDuff.Mode.SRC_IN);
 //this is the rotation part
            canvas.save();
            canvas.rotate(userRotation,  (canvas.getWidth()/ 2),(canvas.getHeight()/ 2));

            if (mScale != 0) 
                canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                     new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2),
                     (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2),
                     (int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
                     (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null);
             else 
                 canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                     new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,
                     (canvas.getHeight() - mCacheBitmap.getHeight()) / 2,
                     (canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(),
                     (canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null);
            

            if (mFpsMeter != null) 
                mFpsMeter.measure();
                mFpsMeter.draw(canvas, 20, 30);
            
//remember to restore the canvas 
            canvas.restore();
            getHolder().unlockCanvasAndPost(canvas);
        
    

Probé la solución más común que usa la función Core.flip que gira el tapete pero consume muchos recursos, esta solución no afecta la detección y no afecta el rendimiento, solo cambia la forma en que se dibuja la imagen en el lienzo.

Espero que esto ayude.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *