Android摄像头预览界面上画线

来源:互联网 发布:电脑绣花制版软件 编辑:程序博客网 时间:2024/05/17 07:00

http://divided-games.com/drawing-with-canvas-on-top-of-a-camera-preview/


Home Android Android: How to draw on a Camera Preview

Android: How to draw on a Camera Preview

Published on July 26, 2012, by Jonathan Haslow-Hall in Android, Java, Tutorials.

In this tutorial I’m going to describe how you can draw on top of a Camera Preview with Canvas.

Part 1: Make an Android Project

To start make an Android project in your work space. I’m using Android version 2.1 for this tutorial, but later versions should work as well.

First the following two lines will need to be added to the Android Manifest of the project.

?
1
2
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera"/>

These two lines are necessary in order to use the camera on the phone.

Part 2: Making the camera preview class

Next Lets make a camera preview class. I’m using the preview class directly from the API Guides on Google foundhere. The code posted below is the same code. With one addition. Add the following method to the class.

?
1
2
3
4
public void onPause() {
    mCamera.release();
    mCamera =null;
}

This method will release the camera and then nullify it when we are done using it.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class CameraPreview extendsSurfaceView implementsSurfaceHolder.Callback {
    privateSurfaceHolder mHolder;
    privateCamera mCamera;
    publicCameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }
    publicvoid surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try{
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        }catch (IOException e) {
            Log.d("CameraView","Error setting camera preview: " + e.getMessage());
        }
     }
    publicvoid surfaceDestroyed(SurfaceHolder holder) {
       // empty. Take care of releasing the Camera preview in your activity.
    }
    publicvoid surfaceChanged(SurfaceHolder holder,int format, int w, inth) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        if(mHolder.getSurface() == null){
             // preview surface does not exist
             return;
        }
        // stop preview before making changes
        try{
            mCamera.stopPreview();
        }catch (Exception e){
            // ignore: tried to stop a non-existent preview
        }
        // set preview size and make any resize, rotate or
        // reformatting changes here
        // start preview with new settings
        try{
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
       }catch (Exception e){
           Log.d("CameraView","Error starting camera preview: " + e.getMessage());
       }
    }
    publicvoid onPause() {
        mCamera.release();
        mCamera =null;
    }
}

This code is off the API Guides as I mentioned above, so if you have trouble understanding it, please refer to the link above as they do a very good job in explaining it. Or if you are still having trouble, just post a comment below.

Part 3: Making the draw class

Next lets make our draw class. Create a new class called “DrawView” and have it extend “SurfaceView” so that we can use its “onDraw” method.

?
1
2
public class DrawView extendsSurfaceView{
}

Next lets make a paint variable so that we can test our app.

?
1
private Paint textPaint = new Paint();

And now make the constructor if it has not already been made. It should look like this.

?
1
2
3
4
public DrawView(Context context) {
    super(context);
 
}

And add the following two lines to the constructor. These lines just tell our paint what color we want it to be and what text size.

?
1
2
textPaint.setARGB(255,200, 0,0);
textPaint.setTextSize(60);

And now for the most important line of the constructor.

?
1
setWillNotDraw(false);

Without this line, onDraw will not be called at all. So we need to make sure it is included.

Now lets make the draw method.

?
1
2
3
4
@Override
protectedvoid onDraw(Canvas canvas){
    canvas.drawText("Hello World!",50, 50, textPaint);
}

This is just a simple override of the onDraw method that SurfaceView has, with a call added to canvas that draws the text “Hello World”.

The following is it all thrown together.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class DrawView extendsSurfaceView{
private Paint textPaint = new Paint();
 
 publicDrawView(Context context) {
 super(context);
 // Create out paint to use for drawing
 textPaint.setARGB(255,200, 0,0);
 textPaint.setTextSize(60);
 // This call is necessary, or else the
 // draw method will not be called.
 setWillNotDraw(false);
 }
 
 @Override
 protectedvoid onDraw(Canvas canvas){
 // A Simple Text Render to test the display
 canvas.drawText("Hello World!",50, 50, textPaint);
 }
}

Part 4: Putting it all together

Finally lets make our activity class. If you are using eclipse, this class will be generated so I will just tell you what needs to be added.

Lets add some variables that we will need for our activity. The first two here are for keeping track of our views, and the third one is going to be our content view. We are using a FrameLayout because it allows us to layer views on the Z axis and therefore we can put our DrawView on top of the CameraPreview.

?
1
2
3
CameraPreview cv;
DrawView dv;
FrameLayout alParent;

Next add these lines to the onCreate method.

?
1
2
3
4
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
       WindowManager.LayoutParams.FLAG_FULLSCREEN);

The first line here tells Android that we want our application to be in landscape and to stay in landscape. Without this line your camera will switch orientations if the user turns their phone, and the portrait orientation will skew the image from camera preview.

The next two lines here just tell android that we don’t want a title bar and that we want our application to be full screen.

Now add these two methods to the class.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
protectedvoid onPause() {
    super.onPause();
    if(cv != null){
        cv.onPause();
        cv =null;
    }
}
@Override
protectedvoid onResume(){
    super.onResume();
    Load();
}

If you are familiar with the states off an Android app, then you will know that onPause will be called each time the app closes and onResume will be called each time it is opened. Because of this we will call the CameraPreview’s onPause method in this method to release the camera each time we close the app.

Next is the onResume method. There is a call to a Load method here, we have not created this method yet but we will shortly. The load method we are going to create will make our apps layout and initialize the views. Instead of adding it in the onCreate method like you would normally do, we are going to be calling it from the onResume method. This is because in certain circumstances the app will not load correctly if it is just in the onCreate method.

Before we make the Load method we need to make a quick method to fetch the camera.

?
1
2
3
4
5
6
7
8
9
10
public static Camera getCameraInstance(){
    Camera c =null;
    try{
        c = Camera.open();
    }
    catch(Exception e){
        e.printStackTrace();
    }
    returnc;
}

This method simply tries to get a camera reference, and returns null if it is unable to.

Here is the load method, I will explain it below.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void Load(){
    Camera c = getCameraInstance();
    if(c != null){
        alParent =new FrameLayout(this);
        alParent.setLayoutParams(newLayoutParams(
           LayoutParams.FILL_PARENT,
           LayoutParams.FILL_PARENT));
 
        cv =new CameraPreview(this,c);
        alParent.addView(cv);
 
        dv =new DrawView(this);
        alParent.addView(dv);
        setContentView(alParent);
    }
    else{
       Toast toast = Toast.makeText(getApplicationContext(),
          "Unable to find camera. Closing.", Toast.LENGTH_SHORT);
       toast.show();
       finish();
    }
}

The first thing that happens here is we try and get the camera. If the call to get the camera returns null then we display a message telling the user that the app was unable to find the camera, and then we tell the app to close. But if the call to get the camera does not return null, then we create the layout.

The first part in creating the layout is to initialize our FrameLayout object.

?
1
2
3
4
alParent = new FrameLayout(this);
alParent.setLayoutParams(newLayoutParams(
   LayoutParams.FILL_PARENT,
   LayoutParams.FILL_PARENT));

That is what these lines did. We first created our object and then we told it to fill the parent.
Next we just initialized our CameraPreview and DrawView. The important part here is to add the CameraPreview first so that the Draw View is on top of it.

?
1
2
3
4
5
cv = newCameraPreview(this,c);
alParent.addView(cv);
 
dv = newDrawView(this);
alParent.addView(dv);

And finally we just tell our app that our frame layout is the content view.

?
1
setContentView(alParent);

Here is it all added together with some comments.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public class CameraTestActivity extendsActivity {
    // Our variables
    CameraPreview cv;
    DrawView dv;
    FrameLayout alParent;
 
    @Override
    publicvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Set the screen orientation to landscape, because
        // the camera preview will be in landscape, and if we
        // don't do this, then we will get a streached image.
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 
        // requesting to turn the title OFF
        requestWindowFeature(Window.FEATURE_NO_TITLE);
 
        // making it full screen
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
 
    publicvoid Load(){
        // Try to get the camera
        Camera c = getCameraInstance();
 
        // If the camera was received, create the app
        if(c != null){
            // Create our layout in order to layer the
            // draw view on top of the camera preview.
 
            alParent =new FrameLayout(this);
            alParent.setLayoutParams(newLayoutParams(
                LayoutParams.FILL_PARENT,
                LayoutParams.FILL_PARENT));
 
            // Create a new camera view and add it to the layout
            cv =new CameraPreview(this,c);
            alParent.addView(cv);
 
            // Create a new draw view and add it to the layout
            dv =new DrawView(this);
            alParent.addView(dv);
 
            // Set the layout as the apps content view
            setContentView(alParent);
        }
        // If the camera was not received, close the app
        else{
            Toast toast = Toast.makeText(getApplicationContext(),
                "Unable to find camera. Closing.", Toast.LENGTH_SHORT);
            toast.show();
            finish();
        }
    }
 
    // This method is strait for the Android API
    // A safe way to get an instance of the Camera object.
    publicstatic Camera getCameraInstance(){
        Camera c =null;
 
        try{
            c = Camera.open();// attempt to get a Camera instance
        }
        catch(Exception e){
            // Camera is not available (in use or does not exist)
            e.printStackTrace();
        }
        returnc; // returns null if camera is unavailable
    }
 
    // Override the onPause method so that we
    // can release the camera when the app is closing.
 
    @Override
    protectedvoid onPause() {
        super.onPause();
 
        if(cv != null){
            cv.onPause();
            cv =null;
        }
    }
 
    // We call Load in our Resume method, because
    // the app will close if we call it in onCreate
    @Override
    protectedvoid onResume(){
        super.onResume();
        Load();
    }
}

原创粉丝点击