Rotate camera preview to Portrait Android OpenCV Camera
Asked Answered
I

20

43

I am trying to use OpenCV 2.4.3.2 to create a camera app and do some opencv processing. I would like it to be able to have multiple UI orientations, not just Landscape.

The problem is that when I change the orientation to portrait, the image comes out sideways.

I understand that I could just rotate the input image before doing image processing (and thus leave the orientation as landscape only), which is fine and works, but doesn't solve the problem that the rest of my UI will be in the wrong orientation.

I have also tried using this code to rotate the camera 90deg, but it just doesn't seem to work.

mCamera.setDisplayOrientation(90);

It either has no effect, or sometimes just causes the preview to be blacked out

Has anyone done this successfully with OpenCV? My class extends from JavaCameraView. portrait image with sideways preview

Edit

I have made an improvement, which is that I have rotated the image inside of OpenCV as it is displayed in the CameraBridgeViewBase.java class.

In the deliver and draw frame method:

if (canvas != null) {
            canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
            //canvas.drawBitmap(mCacheBitmap, (canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2, null);
            //Change to support portrait view
            Matrix matrix = new Matrix();
            matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);

            if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
                matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
            canvas.drawBitmap(mCacheBitmap, matrix, new Paint());

... Basically, this just roatates the input image like so

input image rotated 90

This is better, but I obviously want this to be full screen.

Incantatory answered 11/2, 2013 at 16:15 Comment(15)
Why not simply set the screenorientation on Android?Besnard
I just added an image to explain the behavior, I didnt explain it well enough before. I actually am setting the orientation to portraitIncantatory
Is your code based on the opencv android samples? I highly recommend that you build your code on top of one of those samples because its code already fixes camera issues you might have in the future.Premise
Which sample? I think I've tried all of them and they all seem to be the same (and wrong)Incantatory
@ruimarques Also, the desired behavior is not that it simply remains in portrait (although this CAN sometime be ok, it is not what I am looking for)Incantatory
Ok i would have to take a look at the new samples, maybe something is wrong with them.Premise
@Incantatory I am currently experiencing the same difficulty. I am brand new to openCv as well. I have an idea (I don't know whether it makes sense or not), but do you think it is possible, if we use the Android Camera API, e.g. the surface view etc, to display the camera neatly (correct orientation, full screen or as desired) yet as the backend camera logic, use openCv for processing data. The only obstacle presented would be that probably two cameras would have to be opened. I'm not quite sure about this idea. Comments are appreciatedBezel
I have considered this as well. The problem is, I spent several days looking at the source code to try to figure out what CameraBridgeViewBase.java actually does, and I still dont really understand how frames are converted. I still dont have a good solution to this, my main concern is why doesnt setOrienation work??Incantatory
I'm experiencing this problem too - I think it is because deliverAndDrawFrame is drawing the image as delivered to the onPreviewFrame callback, which is not affected by setDisplayOrientation (if I'm reading the android docs correctly). I think your rotation of the image in the deliverAndDrawFrame method is the right approach...Exodontist
@Incantatory -- ever figure this out? It's now 6+ months later and I just found this via google. I'm facing the same problem trying to render the camera display in native code in openCV for android. I can't figure out how to make it portrait.Hamlet
No, this issue still haunts me. I ended up just locking the app into landscape mode, and manually rotating any user interface elements. Big pain. But, at the time, people from openCV were talking about fixing it, so id be surprised if it wasnt fixed yetIncantatory
@Incantatory -- Did you find any solution for this ? I am also facing the same problem. Please help.Methuselah
Where do u get the var canvas? i'm ussing OpenCV 3.1.0Pyroclastic
still 2018 not fixed :(Revelry
I can't believe we're in 2021 and still working on this issue :/Szeged
E
13

I had the same problem trying to implement OpenCV. I was able to fix it by making the following changes to the deliverAndDrawFrame method.

  1. Rotate the canvas object

    Canvas canvas = getHolder().lockCanvas();
    // Rotate canvas to 90 degrees
    canvas.rotate(90f, canvas.getWidth()/2, canvas.getHeight()/2);
    
  2. Resize the bitmap to fit entire size of canvas before drawing

    // Resize
    Bitmap bitmap = Bitmap.createScaledBitmap(mCacheBitmap, canvas.getHeight(), canvas.getWidth(), true);
    // Use bitmap instead of mCacheBitmap
    canvas.drawBitmap(bitmap, new Rect(0,0,bitmap.getWidth(), bitmap.getHeight()), new Rect(
        (int)((canvas.getWidth() - mScale*bitmap.getWidth()) / 2),
        (int)((canvas.getHeight() - mScale*bitmap.getHeight()) / 2),
        (int)((canvas.getWidth() - mScale*bitmap.getWidth()) / 2 + mScale*bitmap.getWidth()),
        (int)((canvas.getHeight() - mScale*bitmap.getHeight()) / 2 + mScale*bitmap.getHeight()
      )), null);
    
    // Unlock canvas
    getHolder().unlockCanvasAndPost(canvas);
    
Exogenous answered 6/10, 2016 at 23:37 Comment(4)
Wrboleski, the problem is that when you use a FeatureDetector, this doesn't work. The feature detector views the image sideways now.Cacie
This crashes my camera when I run it.Vocabulary
To fit the screen canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()), new Rect(-(canvas.getHeight() - canvas.getWidth()) / 2, (canvas.getHeight() - canvas.getWidth()) / 2, (canvas.getHeight() - canvas.getWidth()) / 2 + canvas.getWidth(), canvas.getHeight() - (canvas.getHeight() - canvas.getWidth()) / 2), null);Filigreed
@KelvinNg this is working but the image is being captured in low resolution. how to improve that?Fraktur
H
10

Actually, you can just make width or height match parent (full screen).

if (canvas != null) {
        Bitmap bitmap = Bitmap.createScaledBitmap(mCacheBitmap, canvas.getHeight(), canvas.getWidth(), true);
        canvas.rotate(90,0,0);
        float scale = canvas.getWidth() / (float)bitmap.getHeight();
        float scale2 = canvas.getHeight() / (float)bitmap.getWidth();
        if(scale2 > scale){
            scale = scale2;
        }
        if (scale != 0) {
            canvas.scale(scale, scale,0,0);
        }
        canvas.drawBitmap(bitmap, 0, -bitmap.getHeight(), null);

...

Also, you can make the preview size larger than the screen. Just modify the scale.

Hamite answered 28/2, 2015 at 7:54 Comment(0)
E
10

I modified the CameraBridgeViewBase.java as follows:

protected Size calculateCameraFrameSize(List<?> supportedSizes, ListItemAccessor accessor, int surfaceWidth, int surfaceHeight) {
    int calcWidth = 0;
    int calcHeight = 0;

    if(surfaceHeight > surfaceWidth){
        int temp = surfaceHeight;
        surfaceHeight = surfaceWidth;
        surfaceWidth = temp;
    }

And in the function "deliverAndDrawFrame":

            if (mScale != 0) {
                if(canvas.getWidth() > canvas.getHeight()) {
                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, rotateMe(canvas, mCacheBitmap), null);
                }

where rotateMe is defined as follows:

private Matrix rotateMe(Canvas canvas, Bitmap bm) {
    // TODO Auto-generated method stub
    Matrix mtx=new Matrix();
    float scale = (float) canvas.getWidth() / (float) bm.getHeight();
    mtx.preTranslate((canvas.getWidth() - bm.getWidth())/2, (canvas.getHeight() - bm.getHeight())/2);
    mtx.postRotate(90,canvas.getWidth()/2, canvas.getHeight()/2);
    mtx.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
    return mtx;
}

The preview FPS is slower because for computational overhead when compared to landscape mode.

Exclamation answered 26/5, 2015 at 8:18 Comment(3)
this works neatly. however the face detection example i am using is then not recognizing any faces anymore. it presumes landscape mode. any ideas on that? thxGarnishee
The camera slows down in portrait mode. And the landscape mode doesnt work for both sidesVehicular
This works but as you said fps goes down dramatically which kind of beats the purpose. Is there an efficient way to achieve a similar result?Catie
S
9

As in other answers, I've written my personal version of deliverAndDrawFrame (I've also notified through comments where my code starts and ends):

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(0, android.graphics.PorterDuff.Mode.CLEAR);
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "mStretch value: " + mScale);
            }

            // Start of the fix
            Matrix matrix = new Matrix();
            matrix.preTranslate( ( canvas.getWidth() - mCacheBitmap.getWidth() ) / 2f, ( canvas.getHeight() - mCacheBitmap.getHeight() ) / 2f );
            matrix.postRotate( 90f, ( canvas.getWidth()) / 2f, canvas.getHeight() / 2f );
            float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
            matrix.postScale(scale, scale, canvas.getWidth() / 2f , canvas.getHeight() / 2f );
            canvas.drawBitmap( mCacheBitmap, matrix, null );

            // Back to original OpenCV code
            if (mFpsMeter != null) {
                mFpsMeter.measure();
                mFpsMeter.draw(canvas, 20, 30);
            }

            getHolder().unlockCanvasAndPost(canvas);
        }
    }

}

Preview is now in Portrait mode, as you can see:

Portrait preview

Spaak answered 24/7, 2019 at 10:49 Comment(1)
Hi @Spaak did you worked on the screen resolution ? your code is working fine but picture resolution is stuck to a constant resolution in my the resolution is 480*864 but my device support more than that how to fix this?Fraktur
K
6

Unfortunately Opencv4Android does not support portrait camera. But there's a way how to overcome it. 1)Write your custom Camera and set it's orientation to portrait. 2)Register for it's preview callback. 3)In onPreviewFrame(byte[]data, Camera camera) create Mat of preview bytes:

Mat mat = new Mat(previewSize.height, previewSize.width, CvType.CV_8UC1);
mat.put(0, 0, data);

Core.transpose(mat, mat);
Core.flip(mat, mat, -1); // rotates Mat to portrait

CvType depends on a preview format your camera is using.

PS. do not forget to release all the Mat instances you've created when you're done.

PPS. it's good to manage your camera on a separate thread in order not to overload UI thread while doing some detection.

Kernan answered 10/2, 2017 at 11:48 Comment(0)
L
3

I have the same issue, i have had figure out it!! and there is my solution:

as the part of first, In CameraBridgeViewBase.Java, the two constructor, add initialization of WindowManager:

public CameraBridgeViewBase(Context context, int cameraId) {  
   super(context);  
   mCameraIndex = cameraId;  
   getHolder().addCallback(this);  
   mMaxWidth = MAX_UNSPECIFIED;  
   mMaxHeight = MAX_UNSPECIFIED;  
   windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);  
}  


public CameraBridgeViewBase(Context context, AttributeSet attrs) {  
   super(context, attrs);  
   int count = attrs.getAttributeCount();  
   Log.d(TAG, "Attr count: " + Integer.valueOf(count));  

   TypedArray styledAttrs = getContext().obtainStyledAttributes(attrs, R.styleable.CameraBridgeViewBase);  
   if (styledAttrs.getBoolean(R.styleable.CameraBridgeViewBase_show_fps, false))  
       enableFpsMeter();  

   mCameraIndex = styledAttrs.getInt(R.styleable.CameraBridgeViewBase_camera_id, -1);  

   getHolder().addCallback(this);  
   mMaxWidth = MAX_UNSPECIFIED;  
   mMaxHeight = MAX_UNSPECIFIED;  
   windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);  
   styledAttrs.recycle();  
}  

then ,You need to replace function deliverAndDrawFrame(CvCameraViewFrame frame) as follows ,

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(0, android.graphics.PorterDuff.Mode.CLEAR);  
          int rotation = windowManager.getDefaultDisplay().getRotation();  
          int degrees = 0;  
          // config degrees as you need  
          switch (rotation) {  
              case Surface.ROTATION_0:  
                  degrees = 90;  
                  break;  
              case Surface.ROTATION_90:  
                  degrees = 0;  
                  break;  
              case Surface.ROTATION_180:  
                  degrees = 270;  
                  break;  
              case Surface.ROTATION_270:  
                  degrees = 180;  
                  break;  
          }  

          Matrix matrix = new Matrix();  
          matrix.postRotate(degrees);  
          Bitmap outputBitmap = Bitmap.createBitmap(mCacheBitmap, 0, 0, mCacheBitmap.getWidth(), mCacheBitmap.getHeight(), matrix, true);  

          if (outputBitmap.getWidth() <= canvas.getWidth()) {  
              mScale = getRatio(outputBitmap.getWidth(), outputBitmap.getHeight(), canvas.getWidth(), canvas.getHeight());  
          } else {  
              mScale = getRatio(canvas.getWidth(), canvas.getHeight(), outputBitmap.getWidth(), outputBitmap.getHeight());  
          }  

          if (mScale != 0) {  
              canvas.scale(mScale, mScale, 0, 0);  
          }  
          Log.d(TAG, "mStretch value: " + mScale);  

          canvas.drawBitmap(outputBitmap, 0, 0, null);  

          if (mFpsMeter != null) {  
              mFpsMeter.measure();  
              mFpsMeter.draw(canvas, 20, 30);  
          }  
          getHolder().unlockCanvasAndPost(canvas);
      }  
   }  
}  

and add this function extra,

private float getRatio(int widthSource, int heightSource, int widthTarget, int heightTarget) {  
   if (widthTarget <= heightTarget) {  
       return (float) heightTarget / (float) heightSource;  
   } else {  
       return (float) widthTarget / (float) widthSource;  
   }  
}  

it's okey ,and If this answer useful to you, please mark 'accepted' Help Reputation

Levite answered 17/3, 2017 at 10:40 Comment(1)
I get an error accessing windowManager in deliverAndDrawFrame even though it is in the constructor. And I can't declare windowManager without error unless I say WindowManager windowManager = ...Vocabulary
C
2

All answers here are hacks. i prefer this solution :

change in JavaCameraView code :

mBuffer = new byte[size];
mCamera.setDisplayOrientation(90); //add this
mCamera.addCallbackBuffer(mBuffer);

Second Change :

//                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
//                        mSurfaceTexture = new SurfaceTexture(MAGIC_TEXTURE_ID);
//                        mCamera.setPreviewTexture(mSurfaceTexture);
//                    } else
//                       mCamera.setPreviewDisplay(null);
                    mCamera.setPreviewDisplay(getHolder());
Calchas answered 19/5, 2017 at 10:33 Comment(3)
this removes the green face detection frameMontelongo
This solution works just to preview the image, but anything painted over it or any type of object detection won't work.Lydon
This also breaks down displaying result of any sort of processing such as adaptive filtering...etc.Szeged
C
1

It seems like the new OpenCV CameraBridgeViewBase.java class is too high-level and doesn't give enough control over the layout of the camera preview. Take a look at my sample code, which is based on some of the older OpenCV samples and uses pure Android code. To use the byte array passed in onPreviewFrame, put() it into a Mat and convert from YUV to RGB:

mYuv = new Mat(previewHeight + previewHeight/2, previewWidth, CvType.CV_8UC1);
mYuv.put(0, 0, mBuffer);
Imgproc.cvtColor(mYuv, mRgba, Imgproc.COLOR_YUV420sp2RGBA, 4);

You may be able to find the old OpenCV4Android samples on the internet, though they were taken out a few versions ago. However, the linked sample code and the snippet above should be enough to get you started.

Cesaria answered 8/8, 2013 at 3:3 Comment(0)
D
1

If you're using the openCV 2.4.9 , try : 1) to copy the content of opencv tutorial-mixed processing in your code; 2) correct the mismatching errors (activity name and probably layout reference); 3)Modify your manifest by adding android:screenOrientation ="landscape" 4) correct minors errors and run !!!! bbaamm (it should work properly now)

Note: with this method the status bar appaear on the right side when the phone is in portrait position . Since we are developing camera project, I advise you to remove the status bar from the preview.

Hope it helps !!!

Dowd answered 19/2, 2015 at 5:42 Comment(0)
L
1

You have to consider a few things:

  • onPreviewFrame() always delivers the raw camera data in its assambled rotation
  • getSupportedPreviewSizes() gives corresponding aspect ratios
  • Algorithm needs to analyze the frame in portrait to detect objects correct.
  • the Bitmap created (Java-side) to store the resulting frame also needs the correct aspect ratio

So, for a fast and high-resolution solution i changed JavaCameraView.java and my JNI-part. in JavaCameraView.java:

...

      if (sizes != null) {
         /* Select the size that fits surface considering maximum size allowed */
         Size frameSize;
         if(width > height)
         {
            frameSize = calculateCameraFrameSize(sizes, new JavaCameraSizeAccessor(), width, height);
         }else{
            frameSize = calculateCameraFrameSize(sizes, new JavaCameraSizeAccessor(), height, width);
         }
...

         mCamera.setParameters(params);
         params = mCamera.getParameters();

         int bufFrameWidth, bufFrameHeight;
         bufFrameWidth = params.getPreviewSize().width;
         bufFrameHeight = params.getPreviewSize().height;

         if(width > height) {
             mFrameWidth = params.getPreviewSize().width;
             mFrameHeight = params.getPreviewSize().height;
         }else{
             mFrameWidth = params.getPreviewSize().height;
             mFrameHeight = params.getPreviewSize().width;
         }
...

         mFrameChain = new Mat[2];
         mFrameChain[0] = new Mat(bufFrameHeight + (bufFrameHeight/2), bufFrameWidth, CvType.CV_8UC1);
         mFrameChain[1] = new Mat(bufFrameHeight + (bufFrameHeight/2), bufFrameWidth, CvType.CV_8UC1);

         AllocateCache();

         mCameraFrame = new JavaCameraFrame[2];
         mCameraFrame[0] = new JavaCameraFrame(mFrameChain[0], bufFrameWidth, bufFrameHeight);
         mCameraFrame[1] = new JavaCameraFrame(mFrameChain[1], bufFrameWidth, bufFrameHeight);

With these changes, we made sure we are using the highest resultion available for portrait (switches height/width in calculateCameraFrameSize). We are still handling landscape as input from onPreviewFrame() but created a Bitmap to draw in portrait (AllocateCache).

Last, we need to give the algorithm the portrait-frame in order to let him detect "standing" objects and return it for saving and rendering the bitmap. So following modifications to your Activity:

public Mat rot90(Mat matImage, int rotflag){
    //1=CW, 2=CCW, 3=180
    Mat rotated = new Mat();
    if (rotflag == 1){
        rotated = matImage.t();
        flip(rotated, rotated, 1); //transpose+flip(1)=CW
    } else if (rotflag == 2) {
        rotated = matImage.t();
        flip(rotated, rotated,0); //transpose+flip(0)=CCW
    } else if (rotflag ==3){
        flip(matImage, rotated,-1);    //flip(-1)=180
    } else if (rotflag != 0){ //if not 0,1,2,3:
       Log.e(TAG, "Unknown rotation flag("+rotflag+")");
    }
    return rotated;
}

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

    mRgba = rot90(inputFrame.rgba(), 1);
    mGray = rot90(inputFrame.gray(), 1);
...
Libenson answered 14/4, 2016 at 12:44 Comment(0)
E
1

Another solution. i think this better

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(0, android.graphics.PorterDuff.Mode.CLEAR);
            if (BuildConfig.DEBUG)
                Log.d(TAG, "mStretch value: " + mScale);

            int currentOrientation = getResources().getConfiguration().orientation;
            if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
                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);
                }
            } else {

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

            if (mFpsMeter != null) {
                mFpsMeter.measure();
                mFpsMeter.draw(canvas, 20, 30);
            }
            getHolder().unlockCanvasAndPost(canvas);
        }
    }
}

and...

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    MatOfRect faces = new MatOfRect();
    int currentOrientation = getResources().getConfiguration().orientation;
    if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) { 
        mRgba = inputFrame.rgba();
        mGray = inputFrame.gray();

        int height = mGray.rows();
        if (Math.round(height * 0.2) > 0) {
            mFaceSize = (int) Math.round(height * 0.2);
        }

        cascadeClassifier.detectMultiScale(mGray, faces, 1.1, 3, 2,
                new Size(mFaceSize, mFaceSize));
        Rect[] facesArray = faces.toArray();
        for (int i = 0; i < facesArray.length; i++) {
            Point center = new Point(facesArray[i].x + facesArray[i].width / 2,
                    facesArray[i].y + facesArray[i].height / 2);
            rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
        }

    } else {
        mRgba = inputFrame.rgba();
        mGray = inputFrame.gray();

        Mat rotImage = Imgproc.getRotationMatrix2D(new Point(mRgba.cols() / 2,
                mRgba.rows() / 2), 90, 1.0);

        Imgproc.warpAffine(mRgba, mRgba, rotImage, mRgba.size());
        Imgproc.warpAffine(mGray, mGray, rotImage, mRgba.size());

        Core.flip(mRgba, mRgba, 1);
        Core.flip(mGray, mGray, 1);

        int height = mGray.rows();
        if (Math.round(height * 0.2) > 0) {
            mFaceSize = (int) Math.round(height * 0.2);
        }

        cascadeClassifier.detectMultiScale(mGray, faces, 1.1, 3, 2,
                new Size(mFaceSize, mFaceSize));
        Rect[] facesArray = faces.toArray();
        for (int i = 0; i < facesArray.length; i++) {
            Point center = new Point(facesArray[i].x + facesArray[i].width / 2,
                    facesArray[i].y + facesArray[i].height / 2);
            rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
        }
    }

    return mRgba;
Eudora answered 8/4, 2020 at 4:0 Comment(0)
G
1

After a lot of searching around, I found this -

https://answers.opencv.org/question/23972/face-detect-with-portrait-mode-and-front-camera/

This works.

Also, make sure you set the portrait mode in AndroidManifest.xml

    android:screenOrientation="portrait"
Gumbotil answered 28/12, 2021 at 7:35 Comment(0)
O
0

I`ve got portrait orientation with CameraBridgeViewBase, but I had to change JavaCameraView.java inside the OpenCV :( The idea is next: after camera init, do next

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

and setDisplayOrientation method

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)
    {
    }
}
Onomatopoeia answered 21/5, 2015 at 12:9 Comment(3)
Hi, i am also facing the orientation issue. could describe in more detail your solution? i tried to add (JavaCamerView) setDisplayOrientation(mCamera, 90); mCamera.setPreviewDisplay(getHolder()); after if (!initializeCamera(width, height)) return false; However this results in black preview screen.Garnishee
This method corrects the orientation for me but preview callback stops working and it also keeps throwing the following exception -Funches
E/SurfaceHolder: Exception locking surface java.lang.IllegalArgumentExceptionFunches
M
0

"jaiprakashgogi" developer answer is working for me. but the problem is the preview still saved as landscape only. that means if we set the preview to imageview then it displayed as landscape.

The above solution works upto showing the preview as portrait but not saved as portrait persistently.

I was resolved that issue as the following way.

  1. convert the byte or mat data into bitmap
  2. rotate the matrix to 90 degrees and apply to bitmap
  3. convert bitmap to byte array and save it.

please see the my code here...

 public String writeToSDFile(byte[] data, int rotation){


    byte[]  portraitData=null;

   if(rotation==90){
       Log.i(TAG,"Rotation is : "+rotation);
       Bitmap bitmap= BitmapFactory.decodeByteArray(data,0,data.length);
       Matrix matrix = new Matrix();

       matrix.postRotate(90);

       Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap , 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
   portraitData=bitmapToByte(rotatedBitmap);


   }

    File dir=getDirectory();
    String imageTime=""+System.currentTimeMillis();

    String fileName=Constants.FILE_NAME+imageTime+"."+Constants.IMAGE_FORMAT;
    File file = new File(dir, fileName);

    try {
        FileOutputStream f = new FileOutputStream(file);

        if(rotation==90){
            f.write(portraitData);
        }else {
            f.write(data);
        }

        f.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        Log.i(TAG, "******* File not found. Did you" +
                " add a WRITE_EXTERNAL_STORAGE permission to the   manifest?");
    } catch (IOException e) {
        e.printStackTrace();
    }
    Log.i(TAG,"\n\nFile written to "+file);

    return fileName;
}

 // convert bitmap to Byte Array

  public byte[] bitmapToByte(Bitmap bitmap){

    ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
  bitmap.compress(Bitmap.CompressFormat.JPEG,100,outputStream);

    byte[] array=outputStream.toByteArray();
   return array;
}

It solves the my problem completely.

Microelement answered 9/3, 2017 at 8:13 Comment(0)
J
0

Thanks to @Kaye Wrobleski for his answer. I have extended it to allow both landscape and portrait orientation. This is basically just a little extra code to allow easily switching between the default code that gives landscape orientation, and his code for portrait.

Insert his code as a new method in CameraBridgeViewBase.java

protected void deliverAndDrawFramePortrait(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();
            // Rotate canvas to 90 degrees
            canvas.rotate(90f, canvas.getWidth()/2, canvas.getHeight()/2);
            if (canvas != null) {
                canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
                Log.d(TAG, "mStretch value: " + mScale);

                if (mScale != 0) {
                    // Resize
                    Bitmap bitmap = Bitmap.createScaledBitmap(mCacheBitmap, canvas.getHeight(), canvas.getWidth(), true);
                    // Use bitmap instead of mCacheBitmap
                    canvas.drawBitmap(bitmap, new Rect(0,0,bitmap.getWidth(), bitmap.getHeight()), new Rect(
                            (int)((canvas.getWidth() - mScale*bitmap.getWidth()) / 2),
                            (int)((canvas.getHeight() - mScale*bitmap.getHeight()) / 2),
                            (int)((canvas.getWidth() - mScale*bitmap.getWidth()) / 2 + mScale*bitmap.getWidth()),
                            (int)((canvas.getHeight() - mScale*bitmap.getHeight()) / 2 + mScale*bitmap.getHeight())), null);
                } else {
                    Bitmap bitmap = Bitmap.createScaledBitmap(mCacheBitmap, canvas.getHeight(), canvas.getWidth(), true);
                    // Use bitmap instead of mCacheBitmap
                    canvas.drawBitmap(bitmap, new Rect(0,0,bitmap.getWidth(), bitmap.getHeight()), new Rect(
                            (int)((canvas.getWidth() - bitmap.getWidth()) / 2),
                            (int)((canvas.getHeight() - bitmap.getHeight()) / 2),
                            (int)((canvas.getWidth() - bitmap.getWidth()) / 2 + bitmap.getWidth()),
                            (int)((canvas.getHeight() - bitmap.getHeight()) / 2 + bitmap.getHeight())), null);
                }

                if (mFpsMeter != null) {
                    mFpsMeter.measure();
                    mFpsMeter.draw(canvas, 20, 30);
                }
                getHolder().unlockCanvasAndPost(canvas);
            }
        }
    }

Then modify JavaCameraView.java

Add a new variable to track whether we are in portrait or landscape mode

private boolean portraitMode;

Add two methods to set the orientation mode

public void setLandscapeMode() {
        portraitMode = false;
    }
    public void setPortraitMode() {
        portraitMode = true;
    }

Now replace these lines in the JavaCameraView CameraWorkerClass, run() method

if (!mFrameChain[1 - mChainIdx].empty())
                        deliverAndDrawFrame(mCameraFrame[1 - mChainIdx]);

With these lines:

if (!mFrameChain[1 - mChainIdx].empty()) {
                        if (!portraitMode) {
                            deliverAndDrawFrame(mCameraFrame[1 - mChainIdx]);
                        } else {
                            deliverAndDrawFramePortrait(mCameraFrame[1 - mChainIdx]);
                        }
                    }

To switch between orientations, simply call either setLandscapeMode() or setPortraitMode() on your JavaCameraView object.

Please note that reverse portrait and reverse landscape orientations will still be upside-down. You will need to rotate them 180 degrees to get them right-side up, which is easily done with OpenCV's warpAffine() method. Note when using the back camera (LENS_FACING_BACK), portrait mode will flip the images upside down.

Jailbird answered 29/8, 2019 at 19:58 Comment(0)
E
0

Maybe this help anyone. tested on android 9 with opencv343. Now this full screen and DETECT face in portrait and landscape modes. small changes in CameraBridgeViewBase class:

private final Matrix matrix = new Matrix();

...... change deliverAndDrawFrame() method:

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) {
        int currentOrientation = getResources().getConfiguration().orientation;
        if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
            Canvas canvas = getHolder().lockCanvas();
            if (canvas != null) {
                canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
                if (BuildConfig.DEBUG)
                    Log.d(TAG, "mStretch value: " + mScale);

                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);
                }
                getHolder().unlockCanvasAndPost(canvas);
            }
        } else {
            Canvas canvas = getHolder().lockCanvas();
            if (canvas != null) {
                int saveCount = canvas.save();
                canvas.setMatrix(matrix);
                mScale = Math.max((float) canvas.getHeight() / mCacheBitmap.getWidth(), (float) canvas.getWidth() / mCacheBitmap.getHeight());
                canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);

                if (mScale != 0) {
                    canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                            new Rect((int)((canvas.getWidth() - mCacheBitmap.getWidth()) - mCacheBitmap.getWidth())/2,
                                    (int)(canvas.getHeight() - mScale*mCacheBitmap.getHeight() - mScale*mCacheBitmap.getHeight()/2),
                                    (int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
                                    (int)((canvas.getHeight() - 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);
                }
                canvas.restoreToCount(saveCount);

                if (mFpsMeter != null) {
                    mFpsMeter.measure();
                    mFpsMeter.draw(canvas, 20, 30);
                }
                getHolder().unlockCanvasAndPost(canvas);
            }
        }
    }
}

and in MainActivity:

public Mat rotateMat(Mat matImage) {
    Mat rotated = matImage.t();
    Core.flip(rotated, rotated, 1);
    return rotated;
}

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    MatOfRect faces = new MatOfRect();
    int currentOrientation = getResources().getConfiguration().orientation;
    if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
        mRgba = inputFrame.rgba();
        mGray = inputFrame.gray();
        int height = mGray.rows();
        if (Math.round(height * 0.2) > 0) {
            mFaceSize = (int) Math.round(height * 0.2);
        }

        cascadeClassifier.detectMultiScale(mGray, faces, 1.1, 3, 2,
                new Size(mFaceSize, mFaceSize));
        Rect[] facesArray = faces.toArray();
        for (int i = 0; i < facesArray.length; i++) {
            rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
        }
    } else {

        mRgba = inputFrame.rgba();
        mGray = rotateMat(inputFrame.gray());

        if (mFaceSize == 0) {
            int height = mGray.cols();
            if (Math.round(height * 0.2) > 0) {
                mFaceSize = (int) Math.round(height * 0.2);
            }
        }
        Mat newMat = rotateMat(mRgba);
        if(!isBackCameraOn){
            flip(newMat, newMat, -1);
            flip(mGray, mGray, -1);
        }
        if (cascadeClassifier != null)
            cascadeClassifier.detectMultiScale(mGray, faces, 1.1, 3, 2, new Size(mFaceSize, mFaceSize));
        mGray.release();

        Rect[] facesArray = faces.toArray();
        for (int i = 0; i < facesArray.length; i++) {
            rectangle(newMat, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
        }

        Imgproc.resize(newMat, mRgba, new Size(mRgba.width(), mRgba.height()));

        newMat.release();
    }

    if(!isBackCameraOn){
        flip(mRgba, mRgba, 1);
        flip(mGray, mGray, 1);
    }


    return mRgba;
}
Eudora answered 5/4, 2020 at 0:57 Comment(0)
T
0

I don't think there is a way to do this, without some pixel manipulation. However, if we simply modified the matrix into which all of those pixels get drawn. The answer lies, in part, in the CameraBridgeViewBase.java file

1. Go to the CameraBridgeViewBase Class

2. Make Function update matrix

private final Matrix mMatrix = new Matrix();
private void updateMatrix() {
float mw = this.getWidth();
float mh = this.getHeight();

float hw = this.getWidth() / 2.0f;
float hh = this.getHeight() / 2.0f;

float cw  = (float)Resources.getSystem().getDisplayMetrics().widthPixels; //Make sure to import Resources package
float ch  = (float)Resources.getSystem().getDisplayMetrics().heightPixels;

float scale = cw / (float)mh;
float scale2 = ch / (float)mw;
if(scale2 > scale){
    scale = scale2;
}

boolean isFrontCamera = mCameraIndex == CAMERA_ID_FRONT;

mMatrix.reset();
if (isFrontCamera) {
    mMatrix.preScale(-1, 1, hw, hh); //MH - this will mirror the camera
}
mMatrix.preTranslate(hw, hh);
if (isFrontCamera){
    mMatrix.preRotate(270);
} else {
    mMatrix.preRotate(90);
}
mMatrix.preTranslate(-hw, -hh);
mMatrix.preScale(scale,scale,hw,hh);
}

3. Override onMeasure and layout function

@Override
public void layout(int l, int t, int r, int b) {
  super.layout(l, t, r, b);
  updateMatrix();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  updateMatrix();
}

4. Replace existing deliverAndDrawFrame function

protected void deliverAndDrawFrame(CvCameraViewFrame frame) { //replaces existing deliverAndDrawFrame
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(0, android.graphics.PorterDuff.Mode.CLEAR);
        int saveCount = canvas.save();
        canvas.setMatrix(mMatrix);

        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);
        }

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

        if (mFpsMeter != null) {
            mFpsMeter.measure();
            mFpsMeter.draw(canvas, 20, 30);
        }
        getHolder().unlockCanvasAndPost(canvas);
    }
}
}
Triturate answered 23/2, 2021 at 13:23 Comment(0)
T
0

I was able to extend from JavaCameraView and hack around to allow portrait and other orientations. This is what worked for me in OpenCV 4.5.3 (com.quickbirdstudios:opencv-contrib:4.5.3.0):

package com.reactnativemapexplorer.opencv;

import android.content.Context;
import android.graphics.Bitmap;

import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.JavaCameraView;
import org.opencv.core.Core;
import org.opencv.core.Mat;

import java.lang.reflect.Field;

public class CustomJavaCameraView extends JavaCameraView {

    public enum Orientation {
        LANDSCAPE_LEFT,
        PORTRAIT,
        LANDSCAPE_RIGHT;
        boolean isLandscape() {
            return this == LANDSCAPE_LEFT || this == LANDSCAPE_RIGHT;
        }
        boolean isLandscapeRight() {
            return this == LANDSCAPE_RIGHT;
        }
    };

    // scale camera by this coefficient - using mScale seems to more performant than upsizing frame Mat
    // orientation is immutable because every attempt to change it dynamically failed with 'null pointer dereference' and similar exceptions
    // tip: re-creating camera from the outside should allow changing orientation
    private final Orientation orientation;

    public CustomJavaCameraView(Context context, int cameraId, Orientation orientation) {
        super(context, cameraId);
        this.orientation = orientation;
    }

    @Override
    protected void AllocateCache() {
        if (orientation.isLandscape()) {
            super.AllocateCache();
            return;
        }
        try {
            Field privateField = CameraBridgeViewBase.class.getDeclaredField("mCacheBitmap");
            privateField.setAccessible(true);
            privateField.set(this, Bitmap.createBitmap(mFrameHeight, mFrameWidth, Bitmap.Config.ARGB_8888));
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    private class CvCameraViewFrameImplHack implements CvCameraViewFrame {
        private Mat rgbMat;
        public CvCameraViewFrameImplHack(Mat rgbMat) {
            this.rgbMat = rgbMat;
        }
        @Override
        public Mat rgba() {
            return this.rgbMat;
        }
        @Override
        public Mat gray() {
            return null;
        }
    }

    private Mat rotateToPortrait(Mat mat) {
        Mat transposed = mat.t();
        Mat flipped = new Mat();
        Core.flip(transposed, flipped, 1);
        transposed.release();
        return flipped;
    }

    private Mat rotateToLandscapeRight(Mat mat) {
        Mat flipped = new Mat();
        Core.flip(mat, flipped, -1);
        return flipped;
    }

    @Override
    protected void deliverAndDrawFrame(CvCameraViewFrame frame) {
        Mat frameMat = frame.rgba();
        Mat rotated;
        if (orientation.isLandscape()) {
            if (orientation.isLandscapeRight()) {
                rotated = rotateToLandscapeRight(frameMat);
            } else {
                rotated = frameMat;
            }
            mScale = (float)getWidth() / (float)frameMat.width();
        } else {
            rotated = rotateToPortrait(frameMat);
            mScale = (float)getHeight() / (float)rotated.height();
        }
        CvCameraViewFrameImplHack hackFrame = new CvCameraViewFrameImplHack(rotated);

        super.deliverAndDrawFrame(hackFrame);
    }
}

Triable answered 13/10, 2022 at 13:34 Comment(0)
T
-1

I don't know well, but camera size is decided from screen width. Because screen width is low, camera height also is decided by low in the portrait orientation. Therefore, camera resolution is decided by low too. And preview image lay down (preview image rotation is decided as camera image's width and height in CameraBridgeViewBase.java).

As the solution, use landscape orientation (decide landscape mode in the manifest.xml as Activity). As a result, because screen width is high, height will be high also and your app decide high resolution. Also, you don't have to rotate the camera image and always full-screen mode. But the disadvantage is the origin point is different. I tried variety method about high-resolution image as the portrait orientation but I couldn't find a way.

My app : portrait orientation

my camera image is 720, 480 / landscape orientation 1280, 1080.

Tyishatyke answered 15/3, 2019 at 3:4 Comment(0)
U
-3

Modify your code in JavaCameraView.java as outlined on this page

It is really easy to fix.

Before

Log.d(TAG, "startPreview");

mCamera.startPreview();

After

Log.d(TAG, "startPreview");

setDisplayOrientation(mCamera, 90);

mCamera.setPreviewDisplay(getHolder());

mCamera.startPreview();
Unclose answered 26/11, 2019 at 13:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.