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

Можно ли обрезать предварительный просмотр камеры?

Я не нашел способ обрезать ppreview камеры, а затем отобразить его на SurfaceView.

Android - Можно ли обрезать предварительный просмотр камеры?

4b9b3361

Ответ 1

Не напрямую. API-камера теперь позволяет компенсировать смещения и сжимать изображение на поверхность держатель. Но вы можете обойтись, разместив над ним надписи (другие виды).

Ответ 2

Вы можете сделать это без наложений (которые не будут работать во всех ситуациях).

Подкласс ViewGroup, добавьте SurfaceView в качестве единственного дочернего элемента, а затем:

  • В onMeasure поставьте требуемые размеры.
  • в onLayout, поместите SurfaceView с необрезанными размерами.

в основном,

public class CroppedCameraPreview extends ViewGroup {
  private SurfaceView cameraPreview;
  public CroppedCameraPreview( Context context ) {
    super( context );
    // i'd probably create and add the SurfaceView here, but it doesn't matter
  }
  @Override
  protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec ) {
    setMeasuredDimension( croppedWidth, croppedHeight );
  }
  @Override
  protected void onLayout( boolean changed, int l, int t, int r, int b ) {
    if ( cameraPreview != null ) {
      cameraPreview.layout( 0, 0, actualPreviewWidth, actualPreviewHeight );
    }
  }
}

Ответ 3

Вы можете поместить предварительный просмотр камеры (SurfaceView) внутри LinearLayout, который находится внутри ScrollView. Когда выход камеры больше установленного вами LinearLayout, вы можете программно прокручивать его и отключать прокрутку пользователя. Таким образом вы можете легко эмулировать обрезку камеры:

<ScrollView 
                     android:id="@+id/scrollView"
                     android:layout_width="640dip"
                     android:layout_height="282dip"
                     android:scrollbars="none"
                     android:fillViewport="true">

                        <LinearLayout
                                android:id="@+id/linearLayoutBeautyContent"
                                android:layout_width="fill_parent"
                                android:layout_height="fill_parent"
                                android:orientation="vertical">

                                <SurfaceView
                                            android:layout_width="match_parent"
                                            android:layout_height="match_parent"
                                            android:id="@+id/surfaceViewBeautyCamera"/>
                      </LinearLayout>
</ScrollView>

Ответ 4

Код для программной прокрутки изображения будет примерно таким:

public void setCameraOrientationOnOpen() 
    {   
        mCamera.stopPreview();
        int rotation = getRotation();
        Camera.Parameters currentCameraParameters = mCamera.getParameters();
        List<Camera.Size> previewSizes = currentCameraParameters.getSupportedPreviewSizes();

        mOptimalCameraSize = getOptimaPreviewCameraSize(previewSizes, (double)9/16);            
        currentCameraParameters.setPreviewSize(mOptimalCameraSize.width, mOptimalCameraSize.height);
        mCamera.setParameters(currentCameraParameters);
        float ratio = 100;
        int ratio1 = (mSurfaceView.getLayoutParams().height * 100) / mOptimalCameraSize.width; //height
        int ratio2 = (mSurfaceView.getLayoutParams().width * 100) / mOptimalCameraSize.height; //width 
        ratio = Math.max(ratio1, ratio2);
        mSurfaceView.getLayoutParams().height = (int) ((mOptimalCameraSize.width * ratio) / 100);
        mSurfaceView.getLayoutParams().width = (int) ((mOptimalCameraSize.height * ratio) / 100);
        if(ratio > 100)
        {
            int offset = (mSurfaceView.getLayoutParams().height - mBoxHeight)/2;
            mScrollView.scrollTo(0, offset); //center the image
        }
        mCamera.setDisplayOrientation(rotation);
        mOptimalCameraSize = mCamera.getParameters().getPreviewSize();
    }

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

Ответ 5

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

XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000" >

<FrameLayout 
    android:id="@+id/camera_preview_frame"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_centerVertical="true" />

<View
    android:id="@+id/transparent_window"
    android:layout_width="fill_parent"
    android:layout_height="50dip"
    android:layout_centerVertical="true"
    android:background="@android:color/transparent" />

<View 
    android:id="@+id/black_top_box"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_above="@id/transparent_window"
    android:background="#000"/>

<View 
    android:id="@+id/black_bottom_box"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_below="@id/transparent_window"
    android:background="#000"/>  
</RelativeLayout>

Затем в методе OnCreate() вашего класса активности вы можете растянуть прозрачный вид следующим образом.

CameraActivity.java

final View transView = findViewById(R.id.transparent_window);

transView.post(new Runnable() {

    @Override
    public void run() {
        RelativeLayout.LayoutParams params;
        params = (RelativeLayout.LayoutParams) transView.getLayoutParams();
        params.height = transView.getWidth();
        transView.setLayoutParams(params);
        transView.postInvalidate();
    }
});

Это снимок экрана из моего телефона. Серая капля в середине представляет собой вид камеры на полу через прозрачный вид

Ответ 6

Вот решение для ориентации = пейзаж, чтобы закончить отличный ответ @drees.

Просто добавьте папку макета в папку res, дублируйте весь макет xml и измените часть макета кода @drees, чтобы выглядеть так:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/background_dark" >

    <FrameLayout
        android:id="@+id/frameSurface"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:background="@android:color/background_light"/>

    <View
        android:id="@+id/transparent_window"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_centerInParent="true"
        android:background="@android:color/transparent" />

    <View
        android:id="@+id/black_top_box"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_toLeftOf="@id/transparent_window"
        android:background="@android:color/background_dark"/>

    <View
        android:id="@+id/black_bottom_box"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_toRightOf="@id/transparent_window"
        android:background="@android:color/background_dark"/>
</RelativeLayout>

Ответ 7

Это решение является одной из многих проблем для вашей ситуации. Некоторый код устарел и не рекомендуется для использования в корпоративных проектах, но если вам нужно просто показать предварительный просмотр камеры без сжатия, достаточно.
Если вам нужно обработать изображение перед просмотром, вы должны посмотреть SurfaceTexture

public class CameraPreview
        extends SurfaceView
        implements SurfaceHolder.Callback, Camera.PreviewCallback {

    public static final String TAG = CameraPreview.class.getSimpleName();

    private static final int PICTURE_SIZE_MAX_WIDTH = 1280;
    private static final int PREVIEW_SIZE_MAX_WIDTH = 640;
    private static final double ASPECT_RATIO = 3.0 / 4.0;

    private Camera mCamera;
    private SurfaceHolder mHolder;
    private boolean mIsLive;
    private boolean mIsPreviewing;

    public CameraPreview(Context context) {
        super(context);
        init(context);
    }

    public CameraPreview(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = (int) (width / ASPECT_RATIO + 0.5);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        //L.g().d(TAG, "onVisibilityChanged: visibility=" + visibility);
        if (mIsLive) {
            if (visibility == VISIBLE && !mIsPreviewing) {
                startCameraPreview();
            } else {
                stopCameraPreview();
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        startCamera();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        stopCamera();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        //L.g().d(TAG, "surfaceChanged: format=" + format + ", width=" + w + ", height=" + h);
        if (mHolder.getSurface() == null || mCamera == null) return;
        mHolder = holder;
        try {
            mCamera.stopPreview();
        } catch (Exception ignored) {}
        try {
            mCamera.setPreviewDisplay(mHolder);
            if (mIsLive && mIsPreviewing) mCamera.startPreview();
        } catch (Exception ignored) {}
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {

        //work with camera preview

        if (mIsPreviewing) camera.setOneShotPreviewCallback(this);
    }

    private Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
        return determineBestSize(parameters.getSupportedPreviewSizes(), PREVIEW_SIZE_MAX_WIDTH);
    }

    private Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
        return determineBestSize(parameters.getSupportedPictureSizes(), PICTURE_SIZE_MAX_WIDTH);
    }

    /**
     * This code I found in this repository
     * https://github.com/boxme/SquareCamera/blob/master/squarecamera/src/main/java/com/desmond/squarecamera/CameraFragment.java#L368
     */
    private Camera.Size determineBestSize(List<Camera.Size> sizes, int widthThreshold) {
        Camera.Size bestSize = null;
        Camera.Size size;
        int numOfSizes = sizes.size();
        for (int i = 0; i < numOfSizes; i++) {
            size = sizes.get(i);
            boolean isDesireRatio = (size.width / 4) == (size.height / 3);
            boolean isBetterSize = (bestSize == null) || size.width > bestSize.width;

            if (isDesireRatio && isBetterSize) {
                bestSize = size;
            }
        }
        if (bestSize == null) {
            return sizes.get(sizes.size() - 1);
        }
        return bestSize;
    }

    private void init(Context context) {
        mHolder = getHolder();
        mHolder.addCallback(this);
    }

    public void startCamera() {
        if (!mIsLive) {
            //L.g().d(TAG, "startCamera");
            mIsPreviewing = false;
            mCamera = Camera.open();
            if (mCamera != null) {
                try {
                    Camera.Parameters param = mCamera.getParameters();
                    Camera.Size bestPreviewSize = determineBestPreviewSize(param);
                    Camera.Size bestPictureSize = determineBestPictureSize(param);
                    param.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
                    param.setPictureSize(bestPictureSize.width, bestPictureSize.height);
                    mCamera.setParameters(param);
                } catch (RuntimeException ignored) {}
                try {
                    mCamera.setDisplayOrientation(90);
                    mCamera.setPreviewCallback(this);
                    mCamera.setPreviewDisplay(mHolder);
                    mIsLive = true;
                } catch (Exception ignored) {}
            }
            //else L.g().d(TAG, "startCamera: error launching the camera");
        }
    }

    public void stopCamera() {
        if (mCamera != null && mIsLive) {
            //L.g().d(TAG, "stopCamera");
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
            mIsPreviewing = false;
            mIsLive = false;
        }
    }

    public void startCameraPreview() {
        if (mCamera != null && mIsLive && !mIsPreviewing) {
            //L.g().d(TAG, "startCameraPreview");
            mCamera.setPreviewCallback(this);
            mCamera.startPreview();
            mIsPreviewing = true;
        }
    }

    public void stopCameraPreview() {
        if (mCamera != null && mIsLive && mIsPreviewing) {
            //L.g().d("stopCameraPreview");
            mCamera.stopPreview();
            mIsPreviewing = false;
        }
    }
}

Ответ 8

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

Единственное, что мне удалось сделать, и он работает хорошо, - это добавить масштаб.

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

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

mPreviewSize = chooseOptimalSize(...);

int viewHeight = getDP(this, R.dimen.videoCaptureHeight);
float scaleY = mPreviewSize.getHeight() / viewHeight;
setScaleY(scaleY);