我正在使用OpenCV开发增强现实Android应用程序。
现在,当我运行我的应用程序时,它会运行几秒钟,然后在没有警告且在logcat中没有错误消息的情况下突然关闭。我认为这与RAM内存耗尽有关,但我很难搞清楚导致这种情况的原因。此外,当我检查ddms时,我的应用程序将突然关闭,所有进程(不仅是我的应用程序)开始消失。有时我会在logcat中收到这样的错误消息:
cannot map BpMemoryHeap (binder=0x767e84c0), size=2883584, fd=53 (Out of memory)
这就是我的OnPreviewFrame的设置方式:
添加一些回调缓冲区:
float bytesPerPix = ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8.0f;
int frame_byteSize = (int) ((size.width * size.height) * bytesPerPix);
for(int i = 0; i< AppConfig.AMOUNT_PREVIEW_BUFFERS ; i++) {
camera.addCallbackBuffer(new byte[frame_byteSize]);
}
在相机上设置PreviewCallback:
cameraRenderer.getCamera().setPreviewCallbackWithBuffer(virtualLayerRenderer);
这是我在OnPreviewFrame方法中调用的updateCameraPose函数:
public void updateCameraPose(byte[] frameData, Camera camera) {
Size size = camera.getParameters().getPreviewSize();
Mat frameImg = new Mat();
Mat mYuv = new Mat( size.height + size.height/2, size.width, CvType.CV_8UC1 );
mYuv.put( 0, 0, frameData );
camera.addCallbackBuffer(frameData);
Imgproc.cvtColor( mYuv, frameImg, Imgproc.COLOR_YUV2GRAY_NV21, 1);
FindCameraPose task = new FindCameraPose();
task.execute(frameImg, cameraPose);
}
这个函数调用asynctask并执行它,这是我的asynctask的代码:
private class FindCameraPose extends AsyncTask<Mat, Void, Mat> {
@Override
protected Mat doInBackground(Mat... params) {
String t = cameraIntDistPath;
getCameraPose(
params[0].getNativeObjAddr(),
t,
params[1].getNativeObjAddr());
return params[1];
}
@Override
protected void onPostExecute(Mat result) {
super.onPostExecute(result);
if(result != null && !result.empty())
Log.d(TAG, "Camera Pose: "+result.dump());
}
private native boolean getCameraPose(long frameImagePtr, String cameraIntDistPath, long cameraPosePtr);
}
asynctask然后调用获取相机姿势的本机方法,这是此本机方法的代码:
JNIEXPORT jboolean JNICALL Java_be_wouterfranken_arboardgame_rendering_tracking_CameraPose_00024FindCameraPose_getCameraPose
(JNIEnv * env, jobject jobject, jlong frameImagePtr, jstring cameraIntDistPath, jlong cameraPosePtr)
{
Mat *camPose = (Mat *) cameraPosePtr;
Mat *frameImage = (Mat *) frameImagePtr;
__android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Mats setup ...");
const char * path = env->GetStringUTFChars(cameraIntDistPath, NULL);
__android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Path string setup started ... %s",path);
Mat intrinsics;
Mat distortion;
__android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Search for cameraPose started...");
Utilities::loadCameraCalibration(path, intrinsics, distortion);
env->ReleaseStringUTFChars(cameraIntDistPath, path);
__android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Camera calibration done");
bool patternFound = pd.findPattern(*frameImage, pti);
__android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Patterns found? %d",patternFound);
if(patternFound) {
pti.computePose(p, intrinsics, distortion);
*camPose = pti.pose3d;
__android_log_print(ANDROID_LOG_DEBUG,APPNAME, "Pose computed");
}
return patternFound;
}
有什么想法吗?
更新
好的,所以我将内存泄漏缩小到本机堆中的泄漏,这是来自opencv_java库。特别是当我关闭检测关键点的调用时,泄漏似乎消失了。我希望这不是OpenCV中的错误,但现在看起来就是这样。此外,即使我尝试使用另一个探测器(SIFT / SURF / ORB / BRISK),这并不重要,仍然是内存泄漏。
有什么想法可以与此相关吗?
答案 0 :(得分:1)
您是否尝试将“android:largeHeap =”true“参数放在 AndroidManifest.xml 中 Application 标记内?< / p>
这样的事情:
<application android:label="@string/app_name" android:largeHeap="true">
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
答案 1 :(得分:1)
好的,我刚回答了我自己的问题。
在我的计算完成之前,我把回调缓冲区送回了相机,并在每一帧上都这样。这使得相机几乎可以在每一帧上运行getCameraPose方法(这当然很多)。这几乎每一帧都称为跟踪代码,因此添加了比可以解决的更多的工作,这解释了堆中大量使用的内存。
从现在开始,我确保在完全处理相框后,我才会将缓冲区送回相机。