Android摄像头预览界面上画线

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

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 found here. 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 extends SurfaceView implements SurfaceHolder.Callback {
     private SurfaceHolder mHolder;
     private Camera mCamera;
     public CameraPreview(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);
     }
     public void 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());
         }
      }
     public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
     }
     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
         // 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());
        }
     }
     public void 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 extends SurfaceView{
}

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
protected void 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 extends SurfaceView{
private Paint textPaint = new Paint();
 
  public DrawView(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
  protected void 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
protected void onPause() {
     super .onPause();
     if (cv != null ){
         cv.onPause();
         cv = null ;
     }
}
@Override
protected void 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();
     }
     return c;
}

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( new LayoutParams(
            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( new LayoutParams(
    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 = new CameraPreview( this ,c);
alParent.addView(cv);
 
dv = new DrawView( 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 extends Activity {
     // Our variables
     CameraPreview cv;
     DrawView dv;
     FrameLayout alParent;
 
     @Override
     public void 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);
     }
 
     public void 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( new LayoutParams(
                 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.
     public static 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();
         }
         return c; // returns null if camera is unavailable
     }
 
     // Override the onPause method so that we
     // can release the camera when the app is closing.
 
     @Override
     protected void 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
     protected void onResume(){
         super .onResume();
         Load();
     }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值