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.