Ok, so what you have to do is have a valid SurfaceView for the camera
preview to start, but you can't just hide it after passing it to
setPreviewDisplay() because the surface will detect that and will stop
previewing. So...
I got the inspiration from the following posts:
Create a FrameLayout to overlay two surfaces
http://stackoverflow.com/questions/2933882/how-to-draw-an-overlay-on-a-surfaceview-used-by-camera-on-android
Then change the Z order to put the real surface on top:
http://stackoverflow.com/questions/5778647/how-to-properly-use-setzordermediaoverlay-on-android
Putting it all together.
The "Tutorial 2 Advanced" example in the SDK instantiates the
Sample3View class inside the onCreate function. I moved that out to
layout xml:
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="
http://schemas.android.com/apk/res/
android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- the fake surface view has to start on top in order for the
preview to start correctly -->
<SurfaceView android:id="@+id/fakeCameraView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!-- the actual opencv drawing class -->
<org.opencv.samples.tutorial3.Sample3View
android:id="@+id/cvsurface"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
The following constructors have to be added (ones that accept the
layout xml attributes) to:
Sample3View.java
public Sample3View (Context context, AttributeSet attrs) {
super(context, attrs);
}
and
SampleViewBase.java for this to work:
public SampleViewBase(Context context, AttributeSet attrs) {
super(context, attrs);
mHolder = getHolder();
mHolder.addCallback(this);
Log.i(TAG, "Instantiated new " + this.getClass());
}
Then update Sample3Native onCreate as follows
- setContentView(new Sample3View(this));
+ setContentView(R.layout.main);
+ SurfaceView fakeview = (SurfaceView)
this.findViewById(R.id.fakeCameraView);
+ fakeview.setZOrderMediaOverlay(false); // This is the magic call
that states things may be drawn over this surface
+ SurfaceView trueview = (SurfaceView)
this.findViewById(R.id.cvsurface);
+ trueview.setZOrderMediaOverlay(true); // This is the magic call that
tells this surface it's an overlay
Finally, the SampleViewBase.java needs to use the now hidden preview:
+ SurfaceView fakeview = (SurfaceView) ((View)
getParent()).findViewById(R.id.fakeCameraView);
try {
- mCamera.setPreviewDisplay(null);
+ mCamera.setPreviewDisplay(fakeview.getHolder());
My guess is that this works because setZOrderMediaOverlay s a way to
partially draw over a camera preview canvas for augmented reality
(that's the context of the hints I found), in this case we completely
cover the camera preview SurfaceView.
There are probably more elegant ways to do this where the "fake"
preview canvas is actually a custom class that instantiates the camera
and and then the SampleViewBase.java class just needs to take care of
the drawing. However, this was the quickest way that I could get the
samples to work.
Best,
Dmitry Kit