Rotate camera preview to Portrait Android OpenCV Camera

前端 未结 17 1529
日久生厌
日久生厌 2020-12-07 15:45

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.

相关标签:
17条回答
  • 2020-12-07 16:13

    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 !!!

    0 讨论(0)
  • 2020-12-07 16:14

    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);
      
    0 讨论(0)
  • 2020-12-07 16:14

    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.

    0 讨论(0)
  • 2020-12-07 16:14

    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.

    0 讨论(0)
  • 2020-12-07 16:25

    "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.

    0 讨论(0)
  • 2020-12-07 16:27

    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.

    0 讨论(0)
提交回复
热议问题