Android:在服务中使用OpenCV视频捕获
我使用的服务是在Android设备启动时启动的。这是因为我不需要一个可见的活动。到目前为止效果很好。但现在我正试图打开相机(在MyService.onStart中)并进行一些基本的图像处理。我知道默认的Android camera类需要一个用于视频预览的曲面。这就是为什么我想使用OpenCV的视频捕获 但我得到了这个错误: 未找到本机的实现 Lorg/opencv/highgui/VideoCapture;。n(I)J 我想知道这是否是因为我没有使用主活动的OpenCV示例中使用的以下行。问题是,如何将其集成到我的服务中,以及何时初始化VideoCapture成员Android:在服务中使用OpenCV视频捕获,android,opencv,android-camera,video-processing,Android,Opencv,Android Camera,Video Processing,我使用的服务是在Android设备启动时启动的。这是因为我不需要一个可见的活动。到目前为止效果很好。但现在我正试图打开相机(在MyService.onStart中)并进行一些基本的图像处理。我知道默认的Android camera类需要一个用于视频预览的曲面。这就是为什么我想使用OpenCV的视频捕获 但我得到了这个错误: 未找到本机的实现 Lorg/opencv/highgui/VideoCapture;。n(I)J 我想知道这是否是因为我没有使用主活动的OpenCV示例中使用的以下行。问题是
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_5, this, mLoaderCallback);
这是到目前为止我的代码。大部分OpenCV代码取自OpenCV的NativeCameraView和CameraBridgeViewBase
package com.example.boot;
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
import org.opencv.highgui.VideoCapture;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public final class MyService extends Service
{
private static final String TAG = "MyService";
private boolean mStopThread;
private Thread mThread;
private VideoCapture mCamera;
private int mFrameWidth;
private int mFrameHeight;
private int mCameraIndex = -1;
private Bitmap mCacheBitmap;
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void onDestroy() {
this.disconnectCamera();
Toast.makeText(this, "service stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
}
@Override
public void onStart(Intent intent, int startid)
{
Log.d(TAG, "service.onStart: begin");
try
{
if (!connectCamera(640, 480))
Log.e(TAG, "Could not connect camera");
else
Log.d(TAG, "Camera successfully connected");
}
catch(Exception e)
{
Log.e(TAG, "MyServer.connectCamera throws an exception: " + e.getMessage());
}
Toast.makeText(this, "service started", Toast.LENGTH_LONG).show();
Log.d(TAG, "service.onStart: end");
}
private boolean connectCamera(int width, int height) {
/* First step - initialize camera connection */
if (!initializeCamera(width, height))
return false;
/* now we can start update thread */
mThread = new Thread(new CameraWorker());
mThread.start();
return true;
}
private boolean initializeCamera(int width, int height) {
synchronized (this) {
if (mCameraIndex == -1)
mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID);
else
mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID + mCameraIndex);
if (mCamera == null)
return false;
if (mCamera.isOpened() == false)
return false;
//java.util.List<Size> sizes = mCamera.getSupportedPreviewSizes();
/* Select the size that fits surface considering maximum size allowed */
Size frameSize = new Size(width, height);
mFrameWidth = (int)frameSize.width;
mFrameHeight = (int)frameSize.height;
AllocateCache();
mCamera.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, frameSize.width);
mCamera.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, frameSize.height);
}
Log.i(TAG, "Selected camera frame size = (" + mFrameWidth + ", " + mFrameHeight + ")");
return true;
}
protected void AllocateCache()
{
mCacheBitmap = Bitmap.createBitmap(mFrameWidth, mFrameHeight, Bitmap.Config.ARGB_8888);
}
private void releaseCamera() {
synchronized (this) {
if (mCamera != null) {
mCamera.release();
}
}
}
private void disconnectCamera() {
/* 1. We need to stop thread which updating the frames
* 2. Stop camera and release it
*/
try {
mStopThread = true;
mThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mThread = null;
mStopThread = false;
}
/* Now release camera */
releaseCamera();
}
protected void deliverAndDrawFrame(NativeCameraFrame frame)
{
Mat modified = frame.rgba();
boolean bmpValid = true;
if (modified != null) {
try {
Utils.matToBitmap(modified, mCacheBitmap);
} catch(Exception e) {
Log.e(TAG, "Mat type: " + modified);
Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
bmpValid = false;
}
}
}
private class NativeCameraFrame
{
public Mat rgba() {
mCapture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
return mRgba;
}
public Mat gray() {
mCapture.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);
return mGray;
}
public NativeCameraFrame(VideoCapture capture) {
mCapture = capture;
mGray = new Mat();
mRgba = new Mat();
}
private VideoCapture mCapture;
private Mat mRgba;
private Mat mGray;
};
private class CameraWorker implements Runnable
{
public void run()
{
do
{
if (!mCamera.grab()) {
Log.e(TAG, "Camera frame grab failed");
break;
}
deliverAndDrawFrame(new NativeCameraFrame(mCamera));
} while (!mStopThread);
}
}
}
package com.example.boot;
导入org.opencv.android.Utils;
导入org.opencv.core.Mat;
导入org.opencv.core.Size;
导入org.opencv.highgui.highgui;
导入org.opencv.highgui.VideoCapture;
导入android.app.Service;
导入android.content.Intent;
导入android.graphics.Bitmap;
导入android.os.IBinder;
导入android.util.Log;
导入android.widget.Toast;
公共最终类MyService扩展服务
{
私有静态最终字符串TAG=“MyService”;
私有布尔mStopThread;
私有线程mThread;
私有视频捕获mCamera;
私有帧宽度;
私家车高度;
private int mCameraIndex=-1;
私有位图;
@凌驾
公共IBinder onBind(意向){
返回null;
}
公共空间{
这个。断开摄像头();
Toast.makeText(此“服务已停止”,Toast.LENGTH_LONG).show();
Log.d(标签“onDestroy”);
}
@凌驾
公共无效启动(Intent Intent,int startid)
{
Log.d(标记“service.onStart:begin”);
尝试
{
如果(!连接摄像头(640480))
Log.e(标签“无法连接摄像头”);
其他的
Log.d(标签“摄像机成功连接”);
}
捕获(例外e)
{
Log.e(标记“MyServer.connectCamera”引发异常:“+e.getMessage()”;
}
Toast.makeText(此“服务已启动”,Toast.LENGTH_LONG).show();
Log.d(标记“service.onStart:end”);
}
专用摄像机(整数宽度、整数高度){
/*第一步-初始化摄像头连接*/
如果(!initializeCamera(宽度、高度))
返回false;
/*现在我们可以开始更新线程了*/
mThread=新线程(new CameraWorker());
mThread.start();
返回true;
}
私有布尔初始值设定项CAMERA(整数宽度、整数高度){
已同步(此){
如果(mCameraIndex==-1)
mCamera=新的视频捕获(Highgui.CV\u CAP\u ANDROID);
其他的
mCamera=新视频捕获(Highgui.CV_CAP_ANDROID+mCameraIndex);
if(mCamera==null)
返回false;
if(mCamera.isOpened()==false)
返回false;
//java.util.List size=mCamera.getSupportedPreviewSizes();
/*考虑到允许的最大尺寸,选择适合曲面的尺寸*/
尺寸frameSize=新尺寸(宽度、高度);
mFrameWidth=(int)frameSize.width;
mFrameHeight=(int)frameSize.height;
AllocateCache();
mCamera.set(Highgui.CV\u CAP\u PROP\u FRAME\u WIDTH,frameSize.WIDTH);
mCamera.set(Highgui.CV\u CAP\u PROP\u FRAME\u HEIGHT,frameSize.HEIGHT);
}
Log.i(标记,“所选相机帧大小=(“+mFrameWidth+”,“+mFrameHeight+”));
返回true;
}
受保护的void AllocateCache()
{
mCacheBitmap=Bitmap.createBitmap(mFrameWidth、mFrameHeight、Bitmap.Config.ARGB_8888);
}
私有无效释放摄影机(){
已同步(此){
if(mCamera!=null){
mCamera.release();
}
}
}
私有void disconnectCamera(){
/*1.我们需要停止更新帧的线程
*2.停止摄像头并将其释放
*/
试一试{
mStopThread=true;
mThread.join();
}捕捉(中断异常e){
e、 printStackTrace();
}最后{
mThread=null;
mStopThread=false;
}
/*现在释放摄像机*/
松开摄像头();
}
受保护的空位释放器DrawFrame(NativeCameraFrame)
{
Mat modified=frame.rgba();
布尔值bmpValid=true;
如果(已修改!=null){
试一试{
Utils.matToBitmap(修改,mcachebimap);
}捕获(例外e){
Log.e(标签,“垫类型:”+修改);
Log.e(标记,“位图类型:”+mCacheBitmap.getWidth()+“*”+mCacheBitmap.getHeight());
Log.e(标记“Utils.matToBitmap()引发异常:”+e.getMessage());
bmpValid=false;
}
}
}
私有类NativeCameraFrame
{
公共Mat rgba(){
检索(mRgba,Highgui.CV\u CAP\u ANDROID\u COLOR\u FRAME\u RGBA);
返回mRgba;
}
公众席(灰色){
检索(mGray,Highgui.CV\u CAP\u ANDROID\u GREY\u FRAME);
返回mGray;
}
公共NativeCameraFrame(视频捕获){
mCapture=捕获;
mGray=新材料();
mRgba=新材料();
}
私人视频捕捉;
私人Mat mRgba;
私人马拉松;
};
私有类CameraWorker实现Runnable
{
公开募捐
{
做
{
如果(!mCamera.grab()){
Log.e(标签,“摄像头框架g