iOS中OpenCV BackgroundSubtractor.getBackgroundImage因帧类型无效崩溃
Objective-C中OpenCV BackgroundSubtractorMOG2获取背景图崩溃解决
问题场景
在iOS应用通过Objective-C封装OpenCV时,BackgroundSubtractorMOG2的apply方法能正常生成前景掩码,但调用getBackgroundImage时应用崩溃,错误提示帧格式无效。即使手动创建CV_8UC1或CV_8UC3类型的Mat,依然崩溃。
崩溃代码
cv::Ptr<BackgroundSubtractor> backSub = createBackgroundSubtractorMOG2(); for (int i = 0; i < arr.count; i++) { // arr - UIImage数组 Mat mask; Mat frame = [OpenCVWrapper _matFrom:arr[i]]; // UIImage转OpenCV Mat backSub->apply(frame, mask); // 正常运行,掩码有效 } Mat background; backSub->getBackgroundImage(background); // 此处崩溃
错误信息
libc++abi: terminating with uncaught exception of type cv::Exception: OpenCV(4.3.0) /Volumes/build-storage/build/master_iOS-mac/opencv/modules/video/src/bgfg_gaussmix2.cpp:929: error: (-215:Assertion failed) frameType == CV_8UC1 || frameType == CV_8UC3 || frameType == CV_32FC1 || frameType == CV_32FC3 in function 'getBackgroundImage' dyld4 config: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/Developer/usr/lib/libBacktraceRecording.dylib:/Developer/usr/lib/libMainThreadChecker.dylib:/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib
对比:Python版本正常运行
background = backSub.getBackgroundImage()
问题原因
C++版本的getBackgroundImage(Mat& bg)重载要求传入的Mat必须和之前apply处理的帧尺寸、通道数、数据类型完全匹配。手动创建的Mat或默认初始化的空Mat,无法满足这个隐式要求,导致断言失败。而Python版本会自动完成返回Mat的初始化,无需手动传入参数。
解决方法
方法1:复用最后一帧的参数初始化背景Mat
循环处理完所有帧后,用最后一帧的尺寸和类型创建background,确保格式完全匹配:
cv::Ptr<BackgroundSubtractor> backSub = createBackgroundSubtractorMOG2(); Mat lastFrame; for (int i = 0; i < arr.count; i++) { Mat mask; Mat frame = [OpenCVWrapper _matFrom:arr[i]]; backSub->apply(frame, mask); lastFrame = frame.clone(); // 保存最后一帧的格式信息 } // 用最后一帧的尺寸和类型初始化background Mat background(lastFrame.size(), lastFrame.type()); backSub->getBackgroundImage(background);
方法2:检查并转换帧格式
确认_matFrom转换后的Mat是MOG2支持的格式(CV_8UC1或CV_8UC3),如果是RGBA(CV_8UC4),先转成RGB:
Mat frame = [OpenCVWrapper _matFrom:arr[i]]; if (frame.channels() == 4) { cvtColor(frame, frame, COLOR_RGBA2RGB); // RGBA转RGB } backSub->apply(frame, mask);
方法3:使用无参重载(推荐)
OpenCV C++接口提供了无参的getBackgroundImage()重载,直接返回背景Mat,和Python逻辑一致:
cv::Ptr<BackgroundSubtractor> backSub = createBackgroundSubtractorMOG2(); for (int i = 0; i < arr.count; i++) { Mat mask; Mat frame = [OpenCVWrapper _matFrom:arr[i]]; backSub->apply(frame, mask); } // 直接调用无参重载,自动返回正确格式的背景图 Mat background = backSub->getBackgroundImage();
内容的提问来源于stack exchange,提问作者DreamTeam Mobile
相关产品推荐
相关产品推荐

