web-dev-qa-db-fra.com

Android Taille de l'aperçu de l'appareil photo 2 et rapport d'aspect des appareils

J'implémente l'API Camera 2 dans mon projet. J'utilise TextureView et ces lignes de codes pour définir la taille de l'aperçu plein écran de la caméra:

StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0];

Cela semble être la plus grande taille d'aperçu prise en charge par l'appareil. Je ne sais pas si cette taille fonctionne avec tous les appareils et convient au format de son appareil sans être étirée. Est-ce que quelqu'un sait?

10
TrungNVT

Si les résolutions de votre caméra, la vue de la texture et les dimensions d'affichage de votre appareil ne sont pas identiques, vous devez ajuster les dimensions. Pour cela, vous devez mettre votre TextureView à l'intérieur de FrameLayout. Le code ci-dessous s'applique à tous les appareils avec différentes résolutions d'affichage.

Prenez vos dimensions d'affichage si vous prévisualisez en plein écran. Prenez int DSI_height, int DSI_width variable globale.

    DisplayMetrics displayMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    DSI_height = displayMetrics.heightPixels;
    DSI_width = displayMetrics.widthPixels;

sélectionnez vos résolutions requises dans Camera2 API et attribuez-les à Size imageDimension, Prenez private Size imageDimension globalement et utiliser

setAspectRatioTextureView(imageDimension.getHeight(),imageDimension.getWidth());

et utiliser ci-dessous la logique

private void setAspectRatioTextureView(int ResolutionWidth , int ResolutionHeight )
    {
        if(ResolutionWidth > ResolutionHeight){
            int newWidth = DSI_width;
            int newHeight = ((DSI_width * ResolutionWidth)/ResolutionHeight);
            updateTextureViewSize(newWidth,newHeight);

        }else {
            int newWidth = DSI_width;
            int newHeight = ((DSI_width * ResolutionHeight)/ResolutionWidth);
            updateTextureViewSize(newWidth,newHeight);
        }

    }

    private void updateTextureViewSize(int viewWidth, int viewHeight) {
        Log.d(TAG, "TextureView Width : " + viewWidth + " TextureView Height : " + viewHeight);
        textureView.setLayoutParams(new FrameLayout.LayoutParams(viewWidth, viewHeight));
    }
9
Ronak Patel

Il pourrait y avoir des cas Edge où cette approche échouerait, mais je n'ai pas de réponse parfaite à votre question pourquoi.

En revanche, j'ai une bonne approche sur la façon de mettre en œuvre une version qui fonctionnera très certainement:

En regardant les démonstrations de l'API Google pour la caméra 2 , j'ai trouvé un exemple de code qui devrait vous être utile pour vous assurer qu'il s'adaptera à tous les écrans correctement:

/**
 * Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that
 * is at least as large as the respective texture view size, and that is at most as large as the
 * respective max size, and whose aspect ratio matches with the specified value. If such size
 * doesn't exist, choose the largest one that is at most as large as the respective max size,
 * and whose aspect ratio matches with the specified value.
 *
 * @param choices           The list of sizes that the camera supports for the intended output
 *                          class
 * @param textureViewWidth  The width of the texture view relative to sensor coordinate
 * @param textureViewHeight The height of the texture view relative to sensor coordinate
 * @param maxWidth          The maximum width that can be chosen
 * @param maxHeight         The maximum height that can be chosen
 * @param aspectRatio       The aspect ratio
 * @return The optimal {@code Size}, or an arbitrary one if none were big enough
 */
private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
        int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {

    // Collect the supported resolutions that are at least as big as the preview Surface
    List<Size> bigEnough = new ArrayList<>();
    // Collect the supported resolutions that are smaller than the preview Surface
    List<Size> notBigEnough = new ArrayList<>();
    int w = aspectRatio.getWidth();
    int h = aspectRatio.getHeight();
    for (Size option : choices) {
        if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
                option.getHeight() == option.getWidth() * h / w) {
            if (option.getWidth() >= textureViewWidth &&
                option.getHeight() >= textureViewHeight) {
                bigEnough.add(option);
            } else {
                notBigEnough.add(option);
            }
        }
    }

    // Pick the smallest of those big enough. If there is no one big enough, pick the
    // largest of those not big enough.
    if (bigEnough.size() > 0) {
        return Collections.min(bigEnough, new CompareSizesByArea());
    } else if (notBigEnough.size() > 0) {
        return Collections.max(notBigEnough, new CompareSizesByArea());
    } else {
        Log.e(TAG, "Couldn't find any suitable preview size");
        return choices[0];
    }
}

Source

Vous devriez également jeter un œil à l'ensemble des classes Camera2BasicFragment.Java et AutoFitTextureView.Java pour une implémentation correcte.

4
anthonymonori

Changer la AutoFitTextureView.Java fichier et définissez la valeur comme ci-dessous:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width, height);
    } else {
        if (width < height * mRatioWidth / mRatioHeight) {
            setMeasuredDimension(width, height);
            Log.d("rlijeolid1",String.valueOf(width)+"\t"+String.valueOf(height));
        } else {
            setMeasuredDimension(width , height);
            Log.d("rlijeolid2",String.valueOf(height * mRatioWidth / mRatioHeight)+"\t"+String.valueOf(height));
        }
    }
}
3
Soni_ji

J'ai résolu ce problème via une approche différente. J'obtiens la largeur et la hauteur de l'écran et calcule à quel point l'aperçu devrait être plus large ou plus élevé pour remplir tout l'écran et conserver les proportions. Cela fonctionne assez bien pour moi sans aucune distorsion.

Ajoutez une variable de membre de classe:

public DisplayMetrics mMetrics = new DisplayMetrics();

Utilisez ce qui suit comme onMeasure:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width, height);
    } else {
        WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(mMetrics);
        double ratio = (double)mRatioWidth / (double)mRatioHeight;
        double invertedRatio = (double)mRatioHeight / (double)mRatioWidth;
        double portraitHeight = width * invertedRatio;
        double portraitWidth = width * (mMetrics.heightPixels / portraitHeight);
        double landscapeWidth = height * ratio;
        double landscapeHeight = (mMetrics.widthPixels / landscapeWidth) * height;

        if (width < height * mRatioWidth / mRatioHeight) {
            setMeasuredDimension((int)portraitWidth, mMetrics.heightPixels);
        } else {
            setMeasuredDimension(mMetrics.widthPixels, (int)landscapeHeight);
        }
    }
}

Tout commentaire est grandement apprécié;)

Meilleur M

3
Michel