1

I'm trying to do a Camera app that measures the pixels colors in an specific zone of the camera preview. For doing that, the user has a grid over the camera preview that indicates him which specific area is going to be measured. As I want to have good resolution, I don't want to measure directly from the surfaceView holding the preview, but I want to do it over the picture after it has been taken, so then I have to play a bit with layouts and picture sizes, positions and rules of 3 in order to go from preview dimensions to real picture dimensions.

The camera activity I'm using is the one shown here:

Android Camera Preview Stretched

with a slight modification to be sure that the ratio of the preview and the final picture are the same.

I added a small piece of code that saves the fragment of the picture which supposedly is under the grid as bitmap. And here comes my problem, I don't know what I'm doing wrong here, since the saved picture doesn't corresponds with that under the grid in the camera preview. (It is more or less shifted right and top).

1) May you please indicate me if this is the right way of doing this, and in the negative case, which approximation would you use?

Illustrative example

2) In order to set a proper size for the surfaceView camera_view (the one holding the preview of the camera), I want to retrieve the size and ratio of the optimal preview size, which is calculated on Camera.Size getOptimalPreviewSize by the CameraPreview class. For that to happen, camera needs to be started, and as far as I know, this occurs when onCreate method happened already.

Where can I put the camera_view.setLayoutParams(new FrameLayout.LayoutParams(x, y)) so it gets called after the optimalPreviewSize has been retrieved?

Thank you very much in advance!

MainActivity.onCreate

     protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        verticalSeekBar = (VerticalSeekBar)            findViewById(R.id.vertical_Seekbar);
        verticalSeekBar.setOnSeekBarChangeListener(zoomSeekBarListener);

        shotButton = (Button) findViewById(R.id.shotButton);
        shotButton.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (myCameraView.safeToTakePicture)
                    myCamera.takePicture(null, null, jpegCallback);
                myCameraView.safeToTakePicture = false;
                return false;
            }
        });

        try {
            myCamera = Camera.open();
        } catch (Exception e) {
            Log.d("ERROR", "Failed to get camera: " + e.getMessage());
        }

        if (myCamera != null) {
            myCameraView = new CameraView(this, myCamera);//create a SurfaceView to show camera data
            camera_view = (FrameLayout) findViewById(R.id.camera_view);
            camera_view.addView(myCameraView);//add the SurfaceView to the layout

        } 
    }

MainActivity.PictureCallback

The resizing calculations are done here, so probably here is the mistake I cannot see...

     Camera.PictureCallback jpegCallback = new Camera.PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {

            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

            int viewH = camera_view.getHeight();
            int viewW = camera_view.getWidth();

            ImageView grid = (ImageView) findViewById(R.id.grid);

        int x = grid.getRight();  //As image is rotated 90ยบ, the right side of the grid will be the top side after Bitmap generation
        int y = grid.getTop();

        int relation = bitmap.getWidth()/ camera_view.getLayoutParams().height; //Relation between width of bitmap and height of surfaceview tells the relation between sizes of surfaceView and bitmap

        int scaled_x = relation * y;  //Theoretical position of the grid in the bitmap
        int scaled_y = relation * x;

        int scaledWidth = grid.getWidth() * relation;

        Matrix matrix = new Matrix();
        matrix.postRotate(90);

        Bitmap resizedbitmap = Bitmap.createBitmap(bitmap, scaled_x, scaled_y, scaledWidth, scaledWidth, matrix, true);


            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            resizedbitmap.compress(Bitmap.CompressFormat.JPEG, 70, bos);

            File sdCard = Environment.getExternalStorageDirectory();
            File dir = new File(sdCard.getAbsolutePath() + "/camtest");
            dir.mkdirs();

            String fileName = String.format("%d.jpg", System.currentTimeMillis());

            File outFile = new File(dir, fileName);

            myCameraView.safeToTakePicture = true;

            if (outFile == null) {
                return;
            }

            try {
                FileOutputStream fos = new FileOutputStream(outFile);
                bos.writeTo(fos);
                fos.close();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

CameraPreview.onMeasure

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
         int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

        if (mSupportedPreviewSizes != null) {
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }


        float ratio;
        if (mPreviewSize.height >= mPreviewSize.width)
            ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
        else
            ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;


        Log.i(TAG, "Ratio Preview " + ratio);

        getOptimalPictureSize(ratio);

        // One of these methods should be used, second method squishes preview slightly
        setMeasuredDimension((int) (width), (int) (width * ratio));

        _width = mPreviewSize.width;
        _height = mPreviewSize.height;


        waitFlag = false;

    }

CameraPreview.getOptimalPictureSize

    private void getOptimalPictureSize(float ratio) {
        List<Camera.Size> pictureSizes = mCamera.getParameters().getSupportedPictureSizes();

        int lastWidth = 0;
        int candidate = 0;

        for (int i = 0; i < pictureSizes.size(); i++) {

            float ratioPictureSizes = (float) pictureSizes.get(i).width / pictureSizes.get(i).height;

            Log.i(TAG, "Picture Sizes: " + pictureSizes.get(i).width + "," + pictureSizes.get(i).height + ", " + ratioPictureSizes);

            if (ratioPictureSizes / ratio < 1 + TOLERANCE || ratioPictureSizes / ratio < 1 - TOLERANCE) {
                int thisWidth = pictureSizes.get(i).width;
                if (thisWidth < lastWidth) continue;
                else {
                    lastWidth = thisWidth;
                    candidate = i;
                }
            }
        }


        Log.i(TAG, "Size found: " + pictureSizes.get(candidate).width + "," + pictureSizes.get(candidate).height + ", " + (float) pictureSizes.get(candidate).width / pictureSizes.get(candidate).height);
        mCamera.stopPreview();

        Camera.Parameters parameters = mCamera.getParameters();

        parameters.setPictureSize(pictureSizes.get(candidate).width, pictureSizes.get(candidate).height);

        mCamera.setParameters(parameters);

        mCamera.startPreview();
    }

Layout

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="#000000">

    <FrameLayout
        android:id="@+id/camera_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center">

    </FrameLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/root"
        android:layout_gravity="center">

        <com.example.raulgotor.phmeter2.DrawGrid
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:id="@+id/grid"
            android:layout_centerInParent="true" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:id="@+id/linearLayout"
            android:layout_alignParentBottom="true"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"
            android:layout_marginBottom="20dp">

            <com.example.raulgotor.phmeter2.VerticalSeekBar android:id="@+id/vertical_Seekbar"
                android:layout_width="50dp"
                android:layout_height="110dp"
                android:minHeight="110dip"
                android:maxHeight="110dip"
                android:indeterminate="false" />

            <View
                android:layout_width="1dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:layout_centerInParent="true"/>

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Foto"
                android:id="@+id/shotButton"
                android:layout_gravity="center|right" />
        </LinearLayout>

    </RelativeLayout>

</FrameLayout>


  [1]: http://i.stack.imgur.com/70Ni5.jpg
Community
  • 1
  • 1
gotramaval
  • 59
  • 7

0 Answers0