问题
I'm working with augmented reality app and I want to draw a line that connects two movable objects on top of the camera. However I get this exception
Process: test.job.reality.augument.job.com.augumentrealitytest, PID: 15056
java.lang.IllegalArgumentException
at android.view.Surface.nativeLockCanvas(Native Method)
at android.view.Surface.lockCanvas(Surface.java:266)
at custom.MyCameraView$MyThread.run(MyCameraView.java:447)
Here's my code as you can see I start my thread in surfaceCreted
method. I'm thinking that I can't lockCanvas because it's a;ready locked by camera, am I right? However I to draw line is it possible (I'm using beyondAR
augumented reality library)
public class MyCameraView extends SurfaceView implements SurfaceHolder.Callback, Camera.PictureCallback {
private MyThread thread;
public MyCameraView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
@SuppressWarnings("deprecation")
private void init(Context context) {
mIsPreviewing = false;
mHolder = getHolder();
mHolder.addCallback(this);
configureCamera();
if (Build.VERSION.SDK_INT <= 10) {// Android 2.3.x or lower
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
thread=new MyThread(getHolder(),this);
getHolder().addCallback(this);
setFocusable(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
thread.startrun(true);
thread.start();
try {
if (mCamera == null) {
init(getContext());
if (mCamera == null) {
return;
}
}
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
if (mCamera != null) {
mCamera.release();
}
mCamera = null;
Logger.e(TAG, "CameraView -- ERROR en SurfaceCreated", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCamera();
thread.startrun(false);
thread.stop();
}
public class MyThread extends Thread{
private SurfaceHolder msurfaceHolder;
private MyCameraView mSurfaceView;
private boolean mrun =false;
public MyThread(SurfaceHolder holder, MyCameraView mSurfaceView) {
this.msurfaceHolder = holder;
this.mSurfaceView=mSurfaceView;
}
public void startrun(boolean run) {
mrun=run;
}
@SuppressLint("WrongCall")
@Override
public void run() {
super.run();
Canvas canvas;
while (mrun) {
canvas=null;
try {
canvas = msurfaceHolder.lockCanvas();
synchronized (msurfaceHolder) {
mSurfaceView.onDraw(canvas);
}
} finally {
if (canvas != null) {
msurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
回答1:
When a surface is used to display camera preview, you cannot draw on it anymore. You could, in principle, open a separate transparent canvas on top of the preview surface, and draw on that canvas. It may be much easier to switch to OpenGL preview (using SurfaceTexture); then you can use the same OpenGL context for your drawings (but they must be expressed in OpenGL, too). You can find a simple demo project at GitHub to begin with.
But even in this case, there is another problem with your task: even if your CV is very fast, there is no synchornization between your augmentation and the camera frame that goes straight from the sensors to the screen. In the case of OpenGL, there are some simple things that can be done in 0 time (e.g. simple convolution on the received texture). But anything more interesting requires something different.
We usually hide the live preview from the user, get the frames in the onPreviewFrame()
callback, process them and draw the frame and whatever additional lines or objects manually. This introduces some delay, but if your algorithms are really efficient, this delay may be negligible.
Again, OpenGL is usually of great help here.
回答2:
Don't lockCanvas and stop thread call & just put the below code in on Draw method. I hope it will work.
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = new Paint();
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
screenHeight = (int) (metrics.heightPixels * 0.6290);
paint.setAntiAlias(true);
paint.setStrokeWidth(1);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.argb(255, 255, 255, 255));
canvas.drawLine((screenWidth / 4), 0,
(screenWidth / 4), screenHeight + 500, paint);
if(screenWidth == 1280 && screenHeight == 473) // this condition for 10" tab only
canvas.drawLine((screenWidth / 2f), 0,
(screenWidth / 2f), screenHeight + 500, paint);
else
canvas.drawLine((screenWidth / 2.20f), 0,
(screenWidth / 2.20f), screenHeight + 500, paint);
canvas.drawLine(0, (screenHeight / 2.15f) * 2, screenWidth,
(screenHeight / 2.15f) * 2, paint);
canvas.drawLine(0, (screenHeight / 2.15f) , screenWidth,
(screenHeight / 2.15f), paint);
}
来源:https://stackoverflow.com/questions/35341021/android-canvas-draw-line-on-camera