J'ai travaillé sur la création de mon activité de caméra personnalisée sur Android, mais lors de la rotation de la caméra, le rapport hauteur / largeur de la vue de surface est perturbé.
Dans mon oncreate pour l'activité, j'ai défini la disposition du cadre qui contient la vue de surface qui affiche les paramètres de la caméra.
//FrameLayout that will hold the camera preview
FrameLayout previewHolder = (FrameLayout) findViewById(R.id.camerapreview);
//Setting camera's preview size to the best preview size
Size optimalSize = null;
camera = getCameraInstance();
double aspectRatio = 0;
if(camera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
optimalSize = CameraPreview.getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
aspectRatio = (float)optimalSize.width/optimalSize.height;
}
if(optimalSize!= null){
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
previewHolder.setLayoutParams(params);
LayoutParams surfaceParams = new LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
cameraPreview.setLayoutParams(surfaceParams);
}
cameraPreview.setCamera(camera);
//Adding the preview to the holder
previewHolder.addView(cameraPreview);
Ensuite, dans la vue Surface, j'ai défini les paramètres de la caméra à afficher
public void setCamera(Camera camera) {
if (mCamera == camera) { return; }
mCamera = camera;
if (mCamera != null) {
requestLayout();
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
if(mCamera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = mCamera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(parameters);
}
/*
Important: Call startPreview() to start updating the preview surface. Preview must
be started before you can take a picture.
*/
mCamera.startPreview();
}
}
Vous pouvez voir que l'homme LEGO grandit et maigre lorsque le téléphone tourne:
Comment puis-je m'assurer que le rapport hauteur / largeur de la vue de ma caméra est correct?
android
android-camera
surfaceview
preview
aspect-ratio
scientifique
la source
la source
Réponses:
J'utilise cette méthode -> basée sur les démos d'API pour obtenir ma taille d'aperçu:
Comme vous pouvez le voir, vous devez saisir la largeur et la hauteur de votre écran. Cette méthode calculera le rapport d'écran en fonction de ces valeurs, puis dans la liste des tailles de prévisualisation prises en charge, elle choisira le meilleur pour vous parmi celles disponibles. Obtenez votre liste pris en chargePreviewSize en place là où l'objet Camera n'est pas nul en utilisant
Et puis dans onMeasure, vous pouvez obtenir votre aperçu optimal
Et puis (dans mon code dans la méthode surfaceChanged, comme je l'ai dit, j'utilise la structure API Demos du code CameraActivity, vous pouvez le générer dans Eclipse):
Et un indice pour vous, car j'ai fait presque la même application que vous. La bonne pratique pour l'activité de la caméra consiste à masquer la barre d'état. Des applications comme Instagram le font. Il réduit la valeur de la hauteur de votre écran et change la valeur de votre ratio. Il est possible d'obtenir des tailles d'aperçu étranges sur certains appareils (votre SurfaceView sera un peu coupée)
Et pour répondre à votre question, comment vérifier si votre ratio de prévisualisation est correct? Ensuite, obtenez la hauteur et la largeur des paramètres que vous avez définis:
votre rapport défini est égal à hauteur / largeur. Si vous voulez que la caméra apparaisse bien sur votre écran, le rapport hauteur / largeur des paramètres que vous définissez sur la caméra doit être le même que le rapport hauteur (moins la barre d'état) / largeur de votre écran.
la source
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height)
.La solution de F1Sher est agréable mais parfois ne fonctionne pas. En particulier, lorsque votre surfaceView ne couvre pas tout l'écran. Dans ce cas, vous devez remplacer la méthode onMeasure (). J'ai copié mon code ici pour votre référence.
Depuis que j'ai mesuré surfaceView en fonction de la largeur, il y a un petit espace blanc à la fin de mon écran que je l'ai rempli par conception. Vous pouvez résoudre ce problème si vous conservez la hauteur et augmentez la largeur en la multipliant par rapport. Cependant, cela écrasera légèrement surfaceView.
la source
getOptimalPreviewSize
pour que cela fonctionne pour moi. est-ce parce que l'orientation d'affichage a été réglée sur 90? Sinon, les calculs de rapport ne sont pas même à proximité ( la cible était de 1,7 et le ratio de la caméra était inférieur à 1)REMARQUE: MA SOLUTION EST UNE SUITE DE LA SOLUTION HESAM: https://stackoverflow.com/a/22758359/1718734
Ce que j'adresse: Hesam a dit qu'il y avait un petit espace blanc qui pouvait apparaître sur certains téléphones, comme ceci:
Hesam a suggéré une deuxième solution, mais cela écrase l'aperçu. Et sur certains appareils, il déforme fortement.
Alors, comment pouvons-nous résoudre ce problème. C'est simple ... en multipliant les proportions jusqu'à ce qu'il remplisse l'écran. J'ai remarqué que plusieurs applications populaires telles que Snapchat, WhatsApp, etc. fonctionnent de la même manière.
Tout ce que vous avez à faire est d'ajouter ceci à la méthode onMeasure:
Cela calculera la hauteur de l'écran et obtiendra le rapport entre la hauteur de l'écran et la hauteur mPreviewSize. Ensuite, il multiplie la largeur et la hauteur de la caméra par le nouveau rapport de hauteur et définit la dimension mesurée en conséquence.
Et la prochaine chose que vous savez, vous vous retrouvez avec ceci: D
Cela fonctionne également bien avec la caméra frontale. Je pense que c'est la meilleure façon de procéder. Maintenant, la seule chose qui reste pour mon application est d'enregistrer l'aperçu lui-même en cliquant sur «Capturer». Mais toi, c'est ça.
la source
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
méthode, j'obtiens toujours width = 0 et height = 0;OK, donc je pense qu'il n'y a pas de réponse suffisante pour le problème général d'étirement de l'aperçu de la caméra. Ou du moins je n'en ai pas trouvé. Mon application a également souffert de ce syndrome d'étirement et il m'a fallu un certain temps pour trouver une solution à partir de toutes les réponses des utilisateurs sur ce portail et sur Internet.
J'ai essayé la solution de @ Hesam mais cela n'a pas fonctionné et j'ai laissé l'aperçu de ma caméra très déformé.
Je montre d'abord le code de ma solution (les parties importantes du code) puis j'explique pourquoi j'ai pris ces mesures. Il y a place pour des modifications de performance.
Mise en page XML de l'activité principale:
Aperçu de la caméra:
Activité principale:
Mon commentaire:
Le point de tout cela est que, même si vous calculez la taille de la caméra optimale en
getOptimalPreviewSize()
vous ne choisissez le rapport le plus proche de correspondre à votre écran. Ainsi, à moins que le rapport ne soit exactement le même, l'aperçu s'étirera.Pourquoi cela va-t-il s'étirer? Parce que l'aperçu de votre caméra FrameLayout est défini dans layout.xml sur match_parent en largeur et en hauteur. C'est pourquoi l'aperçu s'étendra en plein écran.
Ce qu'il faut faire est de définir la largeur et la hauteur de la mise en page de l'aperçu de la caméra pour qu'elles correspondent au rapport de taille de caméra choisi , afin que l'aperçu conserve son rapport hauteur / largeur et ne se déforme pas.
J'ai essayé d'utiliser la
CameraPreview
classe pour faire tous les calculs et les changements de mise en page, mais je ne pouvais pas le comprendre. J'ai essayé d'appliquer cette solution , mais jeSurfaceView
ne reconnais pasgetChildCount ()
ougetChildAt (int index)
. Je pense que je l'ai finalement fait fonctionner avec une référence àmaLayoutPreview
, mais il se comportait mal et a appliqué le rapport défini à l'ensemble de mon application et cela a été fait après la première photo. J'ai donc laissé tomber et déplacé les modifications de mise en page vers leMainActivity
.Dans
CameraPreview
j'ai changéprSupportedPreviewSizes
etgetOptimalPreviewSize()
en public afin que je puisse l'utiliser dansMainActivity
. Ensuite, j'avais besoin des dimensions de l' écran (moins la barre de navigation / d'état s'il y en a une) et choisi la taille optimale de la caméra . J'ai essayé d'obtenir la taille RelativeLayout (ou FrameLayout) au lieu de la taille d'affichage, mais cela retournait une valeur nulle. Cette solution n'a pas fonctionné pour moi. La mise en page a sa valeur aprèsonWindowFocusChanged
(vérifiée dans le journal).J'ai donc mes méthodes pour calculer les dimensions de la mise en page pour qu'elles correspondent au rapport hauteur / largeur de la taille de caméra choisie. Il vous suffit maintenant de définir
LayoutParams
la disposition d'aperçu de votre appareil photo. Modifiez la largeur, la hauteur et centrez-la dans le parent.Il existe deux choix pour calculer les dimensions de l'aperçu. Soit vous voulez qu'il s'adapte à l'écran avec des barres noires (si windowBackground est défini sur null) sur les côtés ou en haut / en bas. Ou vous voulez que l'aperçu soit agrandi en plein écran . J'ai laissé un commentaire avec plus d'informations
calcCamPrevDimensions()
.la source
Salut le getOptimalPreview () qui est ici n'a pas fonctionné pour moi donc je veux partager ma version:
la source
Juste pour rendre ce fil plus complet, j'ajoute ma version de réponse:
Ce que je voulais réaliser: La vue de la surface ne doit pas être étirée et elle doit couvrir tout l'écran.De plus, il n'y avait qu'un mode paysage dans mon application.
Solution:
La solution est une extension extrêmement petite à la solution de F1sher:
=> La première étape consiste à intégrer la solution de F1sher.
=> Maintenant, il peut se produire un scénario dans la solution de F1sher lorsque la vue de surface ne couvre pas tout l'écran, la solution est de rendre la vue de surface plus grande que les dimensions de l'écran afin qu'elle couvre tout l'écran, pour cela:
la source
J'ai compris quel était le problème - c'est avec les changements d' orientation . Si vous changez l'orientation de la caméra à 90 ou 270 degrés, vous devez permuter la largeur et la hauteur des tailles prises en charge et tout ira bien.
La vue de surface doit également se trouver dans une disposition de cadre et avoir une gravité centrale.
Voici un exemple sur C # (Xamarin):
Faites attention que les paramètres de la caméra doivent être définis comme taille d'origine (non échangés) et que la taille de la vue de surface doit être permutée.
la source
J'ai essayé toutes les solutions ci-dessus mais aucune d'elles ne fonctionne pour moi. Finalement, je l'ai résolu moi-même, et je trouve en fait que c'est assez facile. il y a deux points dont vous devez faire attention.
cette previewSize doit être l'une des résolutions prises en charge par la caméra, qui peut être obtenue comme ci-dessous:
généralement l'un des rawSupportedSize est égal à la résolution de l'appareil.
Deuxièmement, placez votre SurfaceView dans un FrameLayout et définissez la hauteur et la largeur de la disposition de la surface dans la méthode surfaceChanged comme ci-dessus.
Ok, les choses sont faites, j'espère que cela pourra vous aider.
la source
Mes exigences sont que l'aperçu de la caméra doit être plein écran et conserver le rapport hauteur / largeur. La solution de Hesam et Yoosuf était excellente, mais je vois un problème de zoom élevé pour une raison quelconque.
L'idée est la même, avoir le centre du conteneur de prévisualisation dans le parent et augmenter la largeur ou la hauteur en fonction des proportions jusqu'à ce qu'il puisse couvrir tout l'écran.
Une chose à noter est que la taille de l'aperçu est en paysage car nous définissons l'orientation de l'affichage.
Le conteneur auquel nous ajouterons la vue SurfaceView:
Ajoutez l'aperçu à son conteneur avec le centre du parent dans votre activité.
À l'intérieur de la classe CameraPreview:
la source
Vous devez définir cameraView.getLayoutParams (). Height et cameraView.getLayoutParams (). Width en fonction du rapport hauteur / largeur souhaité.
la source
J'ai abandonné les calculs et obtenir simplement la taille de la vue où je veux que l'aperçu de la caméra soit affiché et définir la taille de l'aperçu de la caméra de la même manière (juste inversée en largeur / hauteur en raison de la rotation) dans ma mise en œuvre SurfaceView personnalisée:
la source