简体   繁体   English

旋转相机预览到人像 Android OpenCV 相机

[英]Rotate camera preview to Portrait Android OpenCV Camera

I am trying to use OpenCV 2.4.3.2 to create a camera app and do some opencv processing.我正在尝试使用 OpenCV 2.4.3.2 创建相机应用程序并进行一些 opencv 处理。 I would like it to be able to have multiple UI orientations, not just Landscape.我希望它能够有多个 UI 方向,而不仅仅是横向。

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.我知道我可以在进行图像处理之前旋转输入图像(因此只将方向保留为横向),这很好并且有效,但不能解决我的 UI 的其余部分将处于错误方向的问题.

I have also tried using this code to rotate the camera 90deg, but it just doesn't seem to work.我也尝试使用此代码将相机旋转 90 度,但它似乎不起作用。

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?有没有人用 OpenCV 成功地做到了这一点? My class extends from JavaCameraView.我的课程从 JavaCameraView 扩展而来。带有横向预览的纵向图像

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.我做了一个改进,即我在 OpenCV 内部旋转了图像,因为它显示在 CameraBridgeViewBase.java 类中。

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 ...基本上,这只是像这样旋转输入图像

输入图像旋转 90

This is better, but I obviously want this to be full screen.这更好,但我显然希望它是全屏的。

I had the same problem trying to implement OpenCV.我在尝试实现 OpenCV 时遇到了同样的问题。 I was able to fix it by making the following changes to the deliverAndDrawFrame method.我能够通过对 deliveryAndDrawFrame 方法进行以下更改来修复它。

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

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.只需修改比例。

I modified the CameraBridgeViewBase.java as follows:我修改了 CameraBridgeViewBase.java 如下:

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":在函数“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:其中rotateMe定义如下:

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.与横向模式相比,预览 FPS 较慢,因为计算开销较大。

Unfortunately Opencv4Android does not support portrait camera.不幸的是 Opencv4Android 不支持人像相机。 But there's a way how to overcome it.但是有一种方法可以克服它。 1)Write your custom Camera and set it's orientation to portrait. 1)编写您的自定义相机并将其方向设置为纵向。 2)Register for it's preview callback. 2)注册它的预览回调。 3)In onPreviewFrame(byte[]data, Camera camera) create Mat of preview bytes: 3)在onPreviewFrame(byte[]data, Camera camera)创建预览字节的Mat

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. CvType取决于您的相机使用的预览格式。

PS.附注。 do not forget to release all the Mat instances you've created when you're done.完成后不要忘记释放您创建的所有 Mat 实例。

PPS.聚苯乙烯。 it's good to manage your camera on a separate thread in order not to overload UI thread while doing some detection.最好在单独的线程上管理您的相机,以免在进行某些检测时使 UI 线程过载。

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:作为第一部分,在CameraBridgeViewBase.Java两个构造函数中,添加 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 ,然后,您需要将函数deliverAndDrawFrame(CvCameraViewFrame frame)替换如下,

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没关系,如果这个答案对您有用,请标记“已接受”帮助信誉

All answers here are hacks.这里的所有答案都是黑客。 i prefer this solution :我更喜欢这个解决方案:

change in JavaCameraView code :更改 JavaCameraView 代码:

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

As in other answers, I've written my personal version of deliverAndDrawFrame (I've also notified through comments where my code starts and ends):与其他答案一样,我已经编写了我的个人版本的deliveryAndDrawFrame (我还通过评论通知了我的代码开始和结束的位置):

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:预览现在处于纵向模式,如您所见:

人像预览

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.似乎新的 OpenCV CameraBridgeViewBase.java类太高级了,无法对相机预览的布局提供足够的控制。 Take a look at my sample code , which is based on some of the older OpenCV samples and uses pure Android code.看看我的示例代码,它基于一些较旧的 OpenCV 示例并使用纯 Android 代码。 To use the byte array passed in onPreviewFrame , put() it into a Mat and convert from YUV to RGB:要使用传入onPreviewFrame的字节数组, put()其放入 Mat 并从 YUV 转换为 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.您可能可以在互联网上找到旧的 OpenCV4Android 示例,尽管它们是在几个版本之前取出的。 However, the linked sample code and the snippet above should be enough to get you started.但是,链接的示例代码和上面的代码段应该足以让您入门。

If you're using the openCV 2.4.9 , try : 1) to copy the content of opencv tutorial-mixed processing in your code;如果您使用的是 openCV 2.4.9 ,请尝试: 1) 在您的代码中复制 opencv 教程混合处理的内容; 2) correct the mismatching errors (activity name and probably layout reference); 2)纠正不匹配的错误(活动名称和可能的布局参考); 3)Modify your manifest by adding android:screenOrientation ="landscape" 4) correct minors errors and run !!!! 3) 通过添加android:screenOrientation ="landscape"修改您的清单 4) 更正未成年人错误并运行 !!!! bbaamm (it should work properly now) bbaamm(现在应该可以正常工作了)

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 !!!希望能帮助到你 !!!

You have to consider a few things:您必须考虑以下几点:

  • onPreviewFrame() always delivers the raw camera data in its assambled rotation onPreviewFrame() 始终在其组合旋转中提供原始相机数据
  • getSupportedPreviewSizes() gives corresponding aspect ratios getSupportedPreviewSizes() 给出相应的纵横比
  • 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用于存储结果帧的位图创建(Java 端)也需要正确的纵横比

So, for a fast and high-resolution solution i changed JavaCameraView.java and my JNI-part.因此,为了获得快速和高分辨率的解决方案,我更改了 JavaCameraView.java 和我的 JNI 部分。 in JavaCameraView.java:在 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).通过这些更改,我们确保使用可用于纵向的最高结果(在 calculateCameraFrameSize 中切换高度/宽度)。 We are still handling landscape as input from onPreviewFrame() but created a Bitmap to draw in portrait (AllocateCache).我们仍然将横向作为 onPreviewFrame() 的输入处理,但创建了一个位图以纵向绘制 (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);
...

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我已经使用 CameraBridgeViewBase 获得了纵向方向,但我不得不在 OpenCV 中更改 JavaCameraView.java :( 想法是下一个:在相机初始化之后,做下一个

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

and setDisplayOrientation method和 setDisplayOrientation 方法

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

"jaiprakashgogi" developer answer is working for me. “jaiprakashgogi”开发人员回答对我有用。 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.这意味着如果我们将预览设置为 imageview,那么它会显示为横向。

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将矩阵旋转 90 度并应用于位图
  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.它完全解决了我的问题。

Thanks to @Kaye Wrobleski for his answer.感谢@Kaye Wrobleski 的回答。 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在 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然后修改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现在替换 JavaCameraView CameraWorkerClass 中的这些行,run() 方法

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.要在方向之间切换,只需在 JavaCameraView 对象上调用 setLandscapeMode() 或 setPortraitMode() 即可。

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.您需要将它们旋转 180 度以使它们正面朝上,这可以使用 OpenCV 的 warpAffine() 方法轻松完成。 Note when using the back camera (LENS_FACING_BACK), portrait mode will flip the images upside down.请注意,使用后置摄像头 (LENS_FACING_BACK) 时,纵向模式会将图像上下颠倒。

Maybe this help anyone.也许这可以帮助任何人。 tested on android 9 with opencv343.使用 opencv343 在 android 9 上测试。 Now this full screen and DETECT face in portrait and landscape modes.现在这个全屏和 DETECT 脸在纵向和横向模式下。 small changes in CameraBridgeViewBase class: CameraBridgeViewBase 类的小改动:

private final Matrix matrix = new Matrix();

...... change deliverAndDrawFrame() method: ......改变deliverAndDrawFrame()方法:

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:并在 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;
}

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;

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答案部分在于 CameraBridgeViewBase.java 文件

1. Go to the CameraBridgeViewBase Class 1.进入CameraBridgeViewBase类

2. Make Function update matrix 2. 制作函数更新矩阵

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 3. 覆盖 onMeasure 和 layout 功能

@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 4.替换现有的deliverAndDrawFrame函数

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

After a lot of searching around, I found this -经过大量的搜索,我发现了这个——

https://answers.opencv.org/question/23972/face-detect-with-portrait-mode-and-front-camera/ 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另外,请确保您在 AndroidManifest.xml 中设置了纵向模式

    android:screenOrientation="portrait"

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).并且预览图像放下(预览图像旋转由CameraBridgeViewBase.java中的相机图像的宽度和高度决定)。

As the solution, use landscape orientation (decide landscape mode in the manifest.xml as Activity).作为解决方案,使用横向(将 manifest.xml 中的横向模式确定为 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.我的相机图像是 720、480/横向 1280、1080。

Modify your code in JavaCameraView.java as outlined on this page本页所述,修改JavaCameraView.java的代码

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM