Comment obtenir des données d'aperçu de caméra Android?
Mon application appareil photo affiche une prévisualisation de la caméra sur l'écran et également les processus en arrière-plan. Voici le code correspondant, résumés autant que possible (par exemple, pas d'erreur de manipulation ou d'un champ déclarations montré):
public final class CameraView extends SurfaceView implements
SurfaceHolder.Callback, Runnable, PreviewCallback {
public CameraView(Context context, AttributeSet attrs) {
super(context, attrs);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
void openCamera() {
//Called from parent activity after setting content view to CameraView
mCamera = Camera.open();
mCamera.setPreviewCallbackWithBuffer(this);
}
public void surfaceCreated(SurfaceHolder holder) {
new Thread(this).start();
//Set CameraView to the optimal camera preview size
final Camera.Parameters params = mCamera.getParameters();
final List<Camera.Size> sizes = params.getSupportedPreviewSizes();
final int screenWidth = ((View) getParent()).getWidth();
int minDiff = Integer.MAX_VALUE;
Camera.Size bestSize = null;
if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
//Find the camera preview width that best matches the
//width of the surface.
for (Camera.Size size : sizes) {
final int diff = Math.abs(size.width - screenWidth);
if (diff < minDiff) {
minDiff = diff;
bestSize = size;
}
}
} else {
//Find the camera preview HEIGHT that best matches the
//width of the surface, since the camera preview is rotated.
mCamera.setDisplayOrientation(90);
for (Camera.Size size : sizes) {
final int diff = Math.abs(size.height - screenWidth);
if (Math.abs(size.height - screenWidth) < minDiff) {
minDiff = diff;
bestSize = size;
}
}
}
final int previewWidth = bestSize.width;
final int previewHeight = bestSize.height;
ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.height = previewHeight;
layoutParams.width = previewWidth;
setLayoutParams(layoutParams);
params.setPreviewFormat(ImageFormat.NV21);
mCamera.setParameters(params);
int size = previewWidth * previewHeight *
ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
mBuffer = new byte[size];
mCamera.addCallbackBuffer(mBuffer);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
}
public void onPreviewFrame(byte[] data, Camera camera) {
CameraView.this.notify();
}
public void run() {
mThreadRun = true;
while (mThreadRun) {
synchronized (this) {
this.wait();
processFrame(mBuffer); //convert to RGB and rotate - not shown
}
//Request a new frame from the camera by putting
//the buffer back into the queue
mCamera.addCallbackBuffer(mBuffer);
}
mHolder.removeCallback(this);
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
public void surfaceDestroyed(SurfaceHolder holder) {
mThreadRun = false;
}
}
Sur tous les appareils, l'aperçu de la caméra s'affiche correctement, et sur la plupart des (émulateur, Samsung Galaxy S3, etc.) les données stockées dans mBuffer
est également correcte (après NV21 de conversion RGB et de la rotation, bien sûr). Cependant, un certain nombre de dispositifs ne fournissent pas les données correctes dans onPreviewFrame. Je suis sûr que les données sont converties au format RVB correctement après qu'il est reçu, de sorte que le problème semble être dans les données brutes fournies à mBuffer
. J'ai remarqué ce rapport de bug relatives à la YV12 (alias YUV420p) aperçu de l'appareil photo de format, mais je suis en utilisant l'ancienne valeur par défaut, NV21 (alias YUV420sp), qui doit être pris en charge selon les compatibilité standard (voir 7.5.3.2, en bas de page 29).
Par exemple, pour la scène (ici, dans la Prévisualisation de la Caméra sur la Samsung Galaxy Tab 2):
les données transmises à mBuffer
sur l'Onglet 2 ressemble:
et sur le Motorola Droid 4 ressemble à:
Quelle est la bonne façon d'obtenir de l'appareil photo Android aperçu des données sur tous les appareils?
Edit: pour processFrame()
j'ai utilisé OpenCV pour convertir RVB et de rotation. Voir cette réponse et cette réponse.
source d'informationauteur 1''
Vous devez vous connecter pour publier un commentaire.
Le seul problème était que je n'ai pas l'aperçu de la largeur et de la hauteur:
Cela signifie que la hauteur et la largeur je alloué pour la matrice (proportionnelle à previewWidth * previewHeight) ont tendance à être beaucoup plus grande que la taille des données réelles d'être renvoyé (proportionnelle à la par défaut aperçu de la largeur et de l'aperçu de la hauteur). Sur certains téléphones, la valeur par défaut était de la même taille que previewWidth et previewHeight, donc il n'y a pas de problème.
De travailler sur un Scanner de code-Barres, qui s'appuie fortement sur les données de l'aperçu, je me sens comme j'ai vu tous les bugs sous le soleil. Ma suggestion est tout simplement pour ne pas appeler
setPreviewFormat()
et permettre d'utiliser la valeur par défaut. La valeur par défaut est ce que vous voulez ici, heureusement. Il semble y avoir moins d'appareils qui ne parviennent pas à obtenir la droite par défaut, que le dispositif de balles de l'appel àsetPreviewFormat()
. Essayez, au moins, peut ou peut ne pas l'être.Vous pouvez également essayer cette