我用的是opencvforandroid2.4.6,调用opencv自己封装的类来实现拍照功能
程序具体流程如下所述:先启动CameraActivity,,屏幕显示摄像头以及两个菜单,一个菜单可以转换摄像头,一个菜单拍照,,
当按下拍照菜单后会设置mIsPhotoPending 为true,此后程序自动调用onCameraFrame方法,因为mIsPhotoPending 为true所以可以在onCameraFrame方法中进行照片的保存等工作,由于保存照片很繁琐所以独立用了一个方法
takePhoto(),,在该方法中程序会跳转到LabActivity,该activity中有三个菜单,删除,编辑,分享,,可对拍摄好的照片进行这些操作。
下面是具体代码,,可以在手机(android4.2以上的系统上)实现
CameraActivity.java
package com.nummist.secondsight;
import java.io.File;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.NativeCameraView;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;
import com.nummist.secondsight.filters.Filter;
import com.nummist.secondsight.filters.NoneFilter;
import com.nummist.secondsight.filters.convolution.StrokeEdgesFilter;
import com.nummist.secondsight.filters.curve.CrossProcessCurveFilter;
import com.nummist.secondsight.filters.curve.PortraCurveFilter;
import com.nummist.secondsight.filters.curve.ProviaCurveFilter;
import com.nummist.secondsight.filters.curve.VelviaCurveFilter;
import com.nummist.secondsight.filters.mixer.RecolorCMVFilter;
import com.nummist.secondsight.filters.mixer.RecolorRCFilter;
import com.nummist.secondsight.filters.mixer.RecolorRGVFilter;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
public class CameraActivity extends FragmentActivity
implements CvCameraViewListener2 {
// A tag for log output.
//一个标记为日志输出
private static final String TAG = "MainActivity";
// A key for storing the index of the active camera.
//一个关键的,用于存储有效的照相机的索引。
private static final String STATE_CAMERA_INDEX = "cameraIndex";
// The index of the active camera.
//活动摄像头的索引
private int mCameraIndex;
// Whether the active camera is front-facing.
//活动相机是前置
// If so, the camera view should be mirrored.
//如果是这样,相机视图要显示
private boolean mIsCameraFrontFacing;
// The number of cameras on the device.
//这个数表示设备上相机的数量
private int mNumCameras;
// The camera view.
private CameraBridgeViewBase mCameraView;
// Whether the next camera frame should be saved as a photo.
//无论下一相机框架是哪一个都应该保存照片
private boolean mIsPhotoPending;
// A matrix that is used when saving photos.
//一个矩阵是用于保存照片的
private Mat mBgr;
//Whether an asynchronous menu action is in progress.
//If so, menu interaction should be disabled.
//如果一个菜单在进行,菜单交互应该被禁止
private boolean mIsMenuLocked;
//The OpenCV loader callback.
//Opencv 程序回调
private BaseLoaderCallback mLoaderCallback =
new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(final int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
Log.d(TAG, "OpenCV loaded successfully");
mCameraView.enableView();
mBgr = new Mat();
break;
default:
super.onManagerConnected(status);
break;
}
}
};
@SuppressLint("NewApi")
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Window window = getWindow();
window.addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
if (savedInstanceState != null) {
mCameraIndex = savedInstanceState.getInt(
STATE_CAMERA_INDEX, 0);
} else {
mCameraIndex = 0;
mCurveFilterIndex = 0;
mMixerFilterIndex = 0;
mConvolutionFilterIndex = 0;
}
if (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.GINGERBREAD) {
CameraInfo cameraInfo = new CameraInfo();
Camera.getCameraInfo(mCameraIndex, cameraInfo);
mIsCameraFrontFacing =
(cameraInfo.facing ==
CameraInfo.CAMERA_FACING_FRONT);
mNumCameras = Camera.getNumberOfCameras();
} else { // pre-Gingerbread
// Assume there is only 1 camera and it is rear-facing.
mIsCameraFrontFacing = false;
mNumCameras = 1;
}
mCameraView = new NativeCameraView(this, mCameraIndex);
mCameraView.setCvCameraViewListener(this);
setContentView(mCameraView);
}
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the current camera index.
savedInstanceState.putInt(STATE_CAMERA_INDEX, mCameraIndex);
savedInstanceState.putInt(STATE_CURVE_FILTER_INDEX,
mCurveFilterIndex);
savedInstanceState.putInt(STATE_MIXER_FILTER_INDEX,
mMixerFilterIndex);
savedInstanceState.putInt(STATE_CONVOLUTION_FILTER_INDEX,
mConvolutionFilterIndex);
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onPause() {
if (mCameraView != null) {
mCameraView.disableView();
}
super.onPause();
}
@Override
public void onResume() {
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3,
this, mLoaderCallback);
mIsMenuLocked = false;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mCameraView != null) {
mCameraView.disableView();
}
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.activity_camera, menu);
if (mNumCameras < 2) {
// Remove the option to switch cameras, since there is
// only 1.
menu.removeItem(R.id.menu_next_camera);
}
return true;
}
@SuppressLint("NewApi")
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
if (mIsMenuLocked) {
return true;
}
switch (item.getItemId()) {
case R.id.menu_next_curve_filter:
mCurveFilterIndex++;
if (mCurveFilterIndex == mCurveFilters.length) {
mCurveFilterIndex = 0;
}
return true;
case R.id.menu_next_mixer_filter:
mMixerFilterIndex++;
if (mMixerFilterIndex == mMixerFilters.length) {
mMixerFilterIndex = 0;
}
return true;
case R.id.menu_next_convolution_filter:
mConvolutionFilterIndex++;
if (mConvolutionFilterIndex ==
mConvolutionFilters.length) {
mConvolutionFilterIndex = 0;
}
return true;
case R.id.menu_next_camera:
mIsMenuLocked = true;
// With another camera index, recreate the activity.
//另一个相机索引,重新创建活动
mCameraIndex++;
if (mCameraIndex == mNumCameras) {
mCameraIndex = 0;
}
recreate();
return true;
case R.id.menu_take_photo:
mIsMenuLocked = true;
// Next frame, take the photo.
//
mIsPhotoPending = true;
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void takePhoto(final Mat rgba) {
// Determine the path and metadata for the photo.
//确定路径和照片元数据
final long currentTimeMillis = System.currentTimeMillis();
final String appName = getString(R.string.app_name);
final String galleryPath =
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES).toString();
final String albumPath = galleryPath + "/" + appName;
final String photoPath = albumPath + "/" +
currentTimeMillis + ".png";
final ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DATA, photoPath);
values.put(Images.Media.MIME_TYPE,
LabActivity.PHOTO_MIME_TYPE);
values.put(Images.Media.TITLE, appName);
values.put(Images.Media.DESCRIPTION, appName);
values.put(Images.Media.DATE_TAKEN, currentTimeMillis);
// Ensure that the album directory exists.
//确保相片目录存在
File album = new File(albumPath);
if (!album.isDirectory() && !album.mkdirs()) {
Log.e(TAG, "Failed to create album directory at " +
albumPath);
onTakePhotoFailed();
return;
}
// Try to create the photo.
//尝试创建照片
Imgproc.cvtColor(rgba, mBgr, Imgproc.COLOR_RGBA2BGR, 3);
if (!Highgui.imwrite(photoPath, mBgr)) {
Log.e(TAG, "Failed to save photo to " + photoPath);//图片没有保存到
onTakePhotoFailed();
}
Log.d(TAG, "Photo saved successfully to " + photoPath);//图片保存成功
// Try to insert the photo into the MediaStore.
//尝试插入图片到MediaStore
Uri uri;
try {
uri = getContentResolver().insert(
Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (final Exception e) {
Log.e(TAG, "Failed to insert photo into MediaStore");//无法插入图像到MediaStore
e.printStackTrace();
// Since the insertion failed, delete the photo.
//由于插入失败,删除图片
File photo = new File(photoPath);
if (!photo.delete()) {
Log.e(TAG, "Failed to delete non-inserted photo");
}
onTakePhotoFailed();
return;
}
// Open the photo in LabActivity.
//打开照片在LabActivity
final Intent intent = new Intent(this, LabActivity.class);
intent.putExtra(LabActivity.EXTRA_PHOTO_URI, uri);
intent.putExtra(LabActivity.EXTRA_PHOTO_DATA_PATH,
photoPath);
startActivity(intent);
}
private void onTakePhotoFailed() {
mIsMenuLocked = false;
// Show an error message.
// 显示一个错误消息
final String errorMessage =
getString(R.string.photo_error_message);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(CameraActivity.this, errorMessage,
Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onCameraViewStarted(int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void onCameraViewStopped() {
// TODO Auto-generated method stub
}
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
final Mat rgba = inputFrame.rgba();
if (mIsPhotoPending) {
mIsPhotoPending = false;
takePhoto(rgba);
}
if (mIsCameraFrontFacing) {
// Mirror (horizontally flip) the preview.
Core.flip(rgba, rgba, 1);
}
return rgba;
}
}
LabActivity.java
package com.nummist.secondsight;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
public class LabActivity extends Activity {
public static final String PHOTO_MIME_TYPE = "image/png";
public static final String EXTRA_PHOTO_URI =
"com.nummist.secondsight.LabActivity.extra.PHOTO_URI";
public static final String EXTRA_PHOTO_DATA_PATH =
"com.nummist.secondsight.LabActivity.extra.PHOTO_DATA_PATH";
private Uri mUri;
private String mDataPath;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
mUri = intent.getParcelableExtra(EXTRA_PHOTO_URI);
mDataPath = intent.getStringExtra(EXTRA_PHOTO_DATA_PATH);
final ImageView imageView = new ImageView(this);
imageView.setImageURI(mUri);
setContentView(imageView);
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.activity_lab, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_delete:
deletePhoto();
return true;
case R.id.menu_edit:
editPhoto();
return true;
case R.id.menu_share:
sharePhoto();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void deletePhoto() {
final AlertDialog.Builder alert = new AlertDialog.Builder(
LabActivity.this);
alert.setTitle(R.string.photo_delete_prompt_title);
alert.setMessage(R.string.photo_delete_prompt_message);
alert.setCancelable(false);//按返回键不能退出
alert.setPositiveButton(R.string.delete,
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog,
final int which) {
getContentResolver().delete(
Images.Media.EXTERNAL_CONTENT_URI,
MediaStore.MediaColumns.DATA + "=?",
new String[] { mDataPath });
finish();
}
});
alert.setNegativeButton(android.R.string.cancel, null);
alert.show();
}
private void editPhoto() {
final Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setDataAndType(mUri, PHOTO_MIME_TYPE);
startActivity(Intent.createChooser(intent,
getString(R.string.photo_edit_chooser_title)));
}
private void sharePhoto() {
final Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType(PHOTO_MIME_TYPE);
intent.putExtra(Intent.EXTRA_STREAM, mUri);
intent.putExtra(Intent.EXTRA_SUBJECT,
getString(R.string.photo_send_extra_subject));
intent.putExtra(Intent.EXTRA_TEXT,
getString(R.string.photo_send_extra_text));
startActivity(Intent.createChooser(intent,
getString(R.string.photo_send_chooser_title)));
}
}
layout\\gg.xml
menu\\activity_camera.xml
menu\\activi_lab.xml
menu\\activi_lab.xml
配置文件的代码