Android摄像头预览界面上画线
来源:互联网 发布:电脑绣花制版软件 编辑:程序博客网 时间:2024/05/17 07:00
http://divided-games.com/drawing-with-canvas-on-top-of-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.
<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.
public
void
onPause() {
mCamera.release();
mCamera =
null
;
}
This method will release the camera and then nullify it when we are done using it.
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.
public
class
DrawView
extends
SurfaceView{
}
Next lets make a paint variable so that we can test our app.
private
Paint textPaint =
new
Paint();
And now make the constructor if it has not already been made. It should look like this.
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.
textPaint.setARGB(
255
,
200
,
0
,
0
);
textPaint.setTextSize(
60
);
And now for the most important line of the constructor.
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.
@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.
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.
CameraPreview cv;
DrawView dv;
FrameLayout alParent;
Next add these lines to the onCreate method.
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.
@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.
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.
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.
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.
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.
setContentView(alParent);
Here is it all added together with some comments.
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();
}
}
- Android摄像头预览界面上画线
- Android下摄像头预览数据
- android 调起摄像头预览
- Android Camera开发:给摄像头预览界面加个ZoomBar(附完整代码下载)
- Android Camera开发:给摄像头预览界面加个ZoomBar(附完整代码下载)
- android上用opengl画线
- Android开发:巧用延迟实现欢迎界面 及 摄像头预览后绘制背景标示(如坐标系、矩形框)
- Opencv For Android: 如何显示摄像头预览
- 关于降低android手机摄像头预览分辨率
- Android 获取摄像头数据并压缩预览
- android camera 摄像头预览画面变形
- Android camera2预览界面流程
- Android社交系统----界面预览
- qt界面上显示摄像头视频
- Android手势识别 Camera 预览界面上显示文字 布局注意事项(merge布局)
- Android手势识别 Camera 预览界面上显示文字 布局注意事项(merge布局)
- FLEX画线+预览+撤销重做
- Android学习【1】解决android摄像头预览的变形问题
- Windows7 SxsTrace工具使用方法
- 搜索引擎索引系统总结
- android 是如何找到触摸屏设备节点
- 实现Java连接mysql
- java设计模式之代理模式
- Android摄像头预览界面上画线
- Sicily 1172 Queens, Knights and Pawns
- ArcEngine查询、添加、删除要数的方法
- spring ,ioc ,dependency injection 的设计模式
- sqlite增删查改
- Spring AOP (上)
- mysql 创建 主键索引 唯一索引 全文索引 多列索引 添加索引
- 最简方法,js得到标准时间格式
- 等待队列和工作队列