J'ai créé une activité Android implémentant un peu d'OpenCV. Cela consiste simplement à créer une vue de caméra personnalisée, et lorsque vous touchez l'écran, la photo est enregistrée.
Mon seul problème est que le code mOpenCvCameraView.setOnTouchListener(MainActivity.this);
à l'intérieur de BaseLoaderCallback contient un avertissement.
mOpenCvCameraView.setOnTouchListener(MainActivity.this);
met en garde sur
La vue personnalisée avec exemple/zcameratestv2/Version2CameraView a été appelée par setOnTouchListener mais ne remplace pas performClick
Contrairement à d'autres questions, ma classe étend une activité et non une vue. Par conséquent, lorsque j'essaie de remplacer la fonction private boolean performClick() { ...super.performClick(); }
, elle n'est pas reconnue. Voici mes cours
package com.example.zcameratestv2;
import Java.text.SimpleDateFormat;
import Java.util.Date;
import org.opencv.Android.BaseLoaderCallback;
import org.opencv.Android.OpenCVLoader;
import org.opencv.Android.CameraBridgeViewBase.CvCameraViewListener;
import org.opencv.Android.LoaderCallbackInterface;
import org.opencv.core.Mat;
import Android.annotation.SuppressLint;
import Android.app.Activity;
import Android.os.Bundle;
import Android.os.Environment;
import Android.util.Log;
import Android.view.Menu;
import Android.view.MenuItem;
import Android.view.MotionEvent;
import Android.view.SurfaceView;
import Android.view.View;
import Android.view.WindowManager;
import Android.view.View.OnTouchListener;
import Android.widget.Toast;
public class MainActivity extends Activity implements CvCameraViewListener, OnTouchListener {
private Version2CameraView mOpenCvCameraView;
private static final String TAG = "Version 2::Activity";
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
mOpenCvCameraView.setOnTouchListener(MainActivity.this);
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
public MainActivity() {
Log.i(TAG, "Version 2 Class instantiated");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main);
mOpenCvCameraView = (Version2CameraView) findViewById(R.id.Java_surface_view);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
}
public void onPause()
{
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onCameraViewStarted(int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void onCameraViewStopped() {
// TODO Auto-generated method stub
}
@Override
public Mat onCameraFrame(Mat inputFrame) {
// TODO Auto-generated method stub
return null;
}
@SuppressLint("SimpleDateFormat")
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//some code....
break;
case MotionEvent.ACTION_UP:
Log.i(TAG,"onTouch event");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String currentDateandTime = sdf.format(new Date());
String fileName = Environment.getExternalStorageDirectory().getPath() +
"/sample_picture_" + currentDateandTime + ".jpg";
mOpenCvCameraView.takePicture(fileName);
Toast.makeText(this, fileName + " saved", Toast.LENGTH_SHORT).show();
v.performClick();
break;
default:
break;
}
return true;
}
}
Auparavant, l'événement public boolean onTouch(View v, MotionEvent event)
avait un avertissement similaire à celui de OnTouchListener. Il indique que je devrais utiliser un performClick (); méthode, mais je ne peux pas l’écarter car j’étends un Activity
pas un View
. Et j'ai découvert que l'application de v.PerformClick();
résout ce problème.
Cette autre classe gère les processus de la caméra
package com.example.zcameratestv2;
import Java.io.FileOutputStream;
import org.opencv.Android.JavaCameraView;
import Android.content.Context;
import Android.hardware.Camera;
import Android.hardware.Camera.PictureCallback;
import Android.util.AttributeSet;
import Android.util.Log;
public class Version2CameraView extends JavaCameraView implements PictureCallback {
private static final String TAG = "Version2::CameraView";
private String mPictureFileName;
public Version2CameraView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void takePicture(final String fileName) {
Log.i(TAG, "Taking picture");
this.mPictureFileName = fileName;
// Postview and jpeg are sent in the same buffers if the queue is not empty when performing a capture.
// Clear up buffers to avoid mCamera.takePicture to be stuck because of a memory issue
mCamera.setPreviewCallback(null);
// PictureCallback is implemented by the current class
mCamera.takePicture(null, null, this);
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.i(TAG, "Saving a bitmap to file");
// The camera preview was automatically stopped. Start it again.
mCamera.startPreview();
mCamera.setPreviewCallback(this);
// Write the image in a file (in jpeg format)
try {
FileOutputStream fos = new FileOutputStream(mPictureFileName);
fos.write(data);
fos.close();
} catch (Java.io.IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e);
}
}
}
J'ai inclus les autorisations requises dans le fichier manifeste, tel que CAMERA et WRITE_EXTERNAL_STORAGE
Quelqu'un peut-il déterminer le problème? Besoin de votre aide. Merci d'avance!
La méthode onTouch()
récupère chaque événement tactile de la vue sous-jacente qui n'a pas été marquée comme "traitée". Si votre Version2CameraView
ne gère pas les événements tactiles, ils sont traités dans Activity et votre Version2CameraView
est transmis en tant que paramètre View v
.
Malheureusement, votre JavaCameraView
ne remplace pas performClick()
, mais vous essayez de l'appeler dans cette vue. Solution? Ajoutez cette méthode à votre classe Version2CameraView
:
@Override
public boolean performClick() {
// do what you want
return true;
}
Je pense que c'est un peu tard mais la solution est simple. Des classes telles que Button
, TextView
sont des sous-classes de View
ainsi que SurfaceView
qui est le parent des sous-classes JavaCameraView
et Version2CameraView
.
Alors quelle est la différence? La différence est que TextView
implémente une interface 'ViewTreeObserver.OnPreDrawListener'. Pour cette raison, Button (qui est la sous-classe de TextView
) peut remplacer la méthode performClick()
.
Comment puis-je faire avec ma classe Version2CameraView
? Il suffit d'implémenter une interface pour remplacer la méthode performClick()
. Lequel 'ViewTreeObserver.OnPreDrawListener'? Non, vous devriez utiliser SurfaceHolder.Callback
comme ceci:
public class Version2CameraView extends JavaCameraView implements PictureCallback, SurfaceHolder.Callback
{
...
/**
* Process the MotionEvent.
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (getHolder()) {
// Do something
...
return true;
}
}
@Override
public boolean performClick() {
// Calls the super implementation, which generates an AccessibilityEvent
// and calls the onClick() listener on the view, if any
super.performClick();
// Handle the action for the custom click here
return true;
}
...
}
Cette solution doit supprimer l'avertissement que vous avez.
Vous devez ajouter une méthode pour gérer les événements tactiles car votre vue a appelé setOnTouchListener()
, ajouter un remplacement de la méthode par défaut, assurez-vous d'appeler la super méthode à l'intérieur pour éviter des erreurs telles que "La méthode ne substitue pas la méthode à partir de sa super-classe". peut le laisser comme mon échantillon si vous n'allez pas traiter les événements tactiles qui s'y trouvent:
@Override
public boolean performClick() {
super.performClick();
return true;
}