Подтвердить что ты не робот

Поверните предварительный просмотр камеры на портретную камеру OpenCV для Android

Я пытаюсь использовать OpenCV 2.4.3.2 для создания приложения для камеры и обработки некоторых opencv. Я хотел бы, чтобы он мог иметь несколько ориентаций пользовательского интерфейса, а не только Landscape.

Проблема заключается в том, что когда я меняю ориентацию на портрет, изображение выходит сбоку.

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

Я также попытался использовать этот код для поворота камеры 90deg, но он просто не работает.

mCamera.setDisplayOrientation(90);

Он либо не имеет никакого эффекта, либо иногда просто заставляет черновик прерваться

Кто-нибудь сделал это успешно с OpenCV? Мой класс распространяется из JavaCameraView. portrait image with sideways preview

Изменить

Я сделал улучшение, а именно, что я повернул изображение внутри OpenCV, поскольку оно отображается в классе CameraBridgeViewBase.java.

В методе доставки и рисования:

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

... В принципе, это просто загружает входное изображение так:

input image rotated 90

Это лучше, но я, очевидно, хочу, чтобы это было полноэкранным.

4b9b3361

Ответ 1

У меня была та же проблема, которая пыталась реализовать OpenCV. Я смог исправить это, внеся следующие изменения в метод deliverAndDrawFrame.

  1. Поворот объекта холста

    Canvas canvas = getHolder().lockCanvas();
    // Rotate canvas to 90 degrees
    canvas.rotate(90f, canvas.getWidth()/2, canvas.getHeight()/2);
    
  2. Измените размер растрового изображения до размера всего холста перед рисованием

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

Ответ 2

на самом деле, вы можете просто сделать родителями высоту или высоту (полный экран).

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

...

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

Ответ 3

Я изменил 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;
    }

И в функции "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);
                }

где 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;
}

Предварительный просмотр FPS медленнее, поскольку для вычислительных накладных расходов по сравнению с ландшафтным режимом.

Ответ 4

К сожалению, Opencv4Android не поддерживает портретную камеру. Но есть способ преодолеть это. 1) Напишите свою собственную камеру и настройте ее ориентацию на портрет. 2) Зарегистрируйте для этого предварительный просмотр. 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 зависит от формата предварительного просмотра, который использует ваша камера.

PS. не забудьте выпустить все экземпляры Mat, которые вы создали, когда закончите.

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

Ответ 5

У меня такая же проблема, я выяснил это! и есть мое решение:

как часть первого, In 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();  

}

то вам нужно заменить функцию 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);  

      }  
  }  

}

и добавьте этот funtion 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 okey, и если этот ответ вам полезен, отметьте "принятую" репутацию справки

Ответ 6

Все ответы здесь - это хаки. я предпочитаю это решение:

изменение кода JavaCameraView:

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

Второе изменение:

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

Ответ 7

Похоже, что новый класс OpenCV CameraBridgeViewBase.java слишком высокоуровневый и не дает достаточного контроля над макетом предварительного просмотра камеры. Взгляните на мой образец кода, который основан на некоторых старых образцах OpenCV и использует чистый код Android. Чтобы использовать массив байтов, прошедший в 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);

Вы можете найти старые образцы OpenCV4Android в Интернете, хотя они были вывезены несколько версий назад. Однако связанный примерный код и фрагмент выше должны быть достаточными для начала работы.

Ответ 8

Если вы используете openCV 2.4.9, попробуйте: 1) скопировать содержимое opencv tutorial-mixed processing в ваш код; 2) исправить ошибки несоответствия (название действия и, возможно, ссылку на макет); 3) Измените манифест, добавив android:screenOrientation ="landscape" 4) исправить ошибки несовершеннолетних и бежать!!!! bbaamm (теперь он должен работать правильно)

Примечание. С помощью этого метода панель состояния отображается справа, когда телефон находится в портретном положении. Поскольку мы разрабатываем проект камеры, я советую вам удалить строку состояния из предварительного просмотра.

Надеюсь, это поможет!!!

Ответ 9

У меня была портретная ориентация с CameraBridgeViewBase, но мне пришлось изменить JavaCameraView.java внутри OpenCV:( Идея следующая: после инициализации камеры, сделайте следующее

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

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

Ответ 10

Вы должны рассмотреть несколько вещей:

  • onPreviewFrame() всегда поставляет необработанные данные камеры в своем объявленном ротации
  • getSupportedPreviewSizes() дает соответствующие пропорции
  • Алгоритм должен анализировать кадр в портрете для правильного определения объектов.
  • Созданный Bitmap (Java-side) для хранения результирующего кадра также нуждается в правильном соотношении сторон

Итак, для быстрого и высокого разрешения я изменил JavaCameraView.java и мою JNI-часть. в 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);

С этими изменениями мы убедились, что мы используем самый высокий результат, доступный для портрета (переключаем высоту/ширину в calcCameraFrameSize). Мы по-прежнему обрабатываем ландшафт в качестве входных данных из onPreviewFrame(), но создали Bitmap для рисования в портрете (AllocateCache).

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

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

Ответ 11

Ответ разработчика для разработчиков "jaiprakashgogi" работает для меня. но проблема заключается в том, что предварительный просмотр сохраняется только как пейзаж. это означает, что если мы установим предварительный просмотр в изображение, тогда он будет отображаться как альбомный.

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

Я решил эту проблему следующим образом.

  • преобразовать данные байта или мата в растровые изображения
  • поверните матрицу на 90 градусов и примените к растровому изображению
  • преобразовать битмап в массив байтов и сохранить его.

см. мой код здесь...

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

Он полностью решает мою проблему.

Ответ 12

Я не знаю, если вы написали свой вопрос, вы включили весь свой код, но это простое исправление. Я делал нечто подобное в Python, и все, что вам нужно сделать, это то, что вызов функции возвращает измененное изображение. чтобы изменить ваш код.

myCamera = mCamera.setDisplayOrientation(90);

Это сработало в Python, и я думаю, это будет работать и на Java. Я знаю, что вопрос уже давно, но, возможно, кто-то еще с этим вопросом получает помощь от ответа.

Ответ 13

Как и в других ответах, я написал свою личную версию 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);
        }
    }

}

Предварительный просмотр теперь в портретном режиме, как вы можете видеть:

Portrait preview

Ответ 14

Спасибо @Kaye Wrobleski за его ответ. Я расширил его, чтобы позволить как альбомную, так и портретную ориентацию. По сути, это всего лишь небольшой дополнительный код, позволяющий легко переключаться между кодом по умолчанию, который задает альбомную ориентацию, и его кодом для портрета.

Вставьте его код в качестве нового метода в 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);
            }
        }
    }

Затем измените JavaCameraView.java

Добавьте новую переменную, чтобы отслеживать, находимся ли мы в портретном или ландшафтном режиме

private boolean portraitMode;

Добавьте два метода для установки режима ориентации

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

Теперь замените эти строки в JavaCameraView CameraWorkerClass, метод run()

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

С этими строками:

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

Чтобы переключаться между ориентациями, просто вызовите setLandscapeMode() или setPortraitMode() для вашего объекта JavaCameraView.

Обратите внимание, что обратный портрет и обратная альбомная ориентация все равно будут перевернутыми. Вам нужно будет повернуть их на 180 градусов, чтобы поднять их правой стороной вверх, что легко сделать с помощью метода OpenCV warpAffine(). Обратите внимание, что при использовании задней камеры (LENS_FACING_BACK) портретный режим переворачивает изображения вверх ногами.

Ответ 15

Я не очень хорошо знаю, но размер камеры определяется по ширине экрана. Поскольку ширина экрана мала, высота камеры также определяется низкой ориентацией портрета. Следовательно, разрешение камеры также определяется низким. И предварительное изображение ложится (поворот изображения предварительного просмотра определяется как ширина и высота изображения камеры в CameraBridgeViewBase.java).

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

Мое приложение: книжная ориентация

изображение с моей камеры 720, 480/альбомная ориентация 1280, 1080.

Ответ 16

Вам не нужно поворачивать экран.

Измените файл Manifest.xml со следующей строкой:

 <activity
        android:screenOrientation="landscape"
        android:configChanges="keyboardHidden|orientation|screenSize">

Это обеспечит предварительный просмотр в полноэкранном режиме, который работает так же, как и предварительный просмотр системной камеры.