EXEC_BAD_ACCESS 在 IOS 上使用 OpenCV `cv::aruco::detectMarkers()`
EXEC_BAD_ACCESS w/ OpenCV `cv::aruco::detectMarkers()` on IOS
- opencv:4.1.0(带 'contrib' 扩展)
- swift: 5
- IOS: 12.2
我正在尝试 运行 在来自 iphone 相机的每一帧上使用 opencv 的方法 cv::aruco::detectMarkers
。这有效,但大约一分钟后它因错误而崩溃:Thread 8: EXC_BAD_ACCESS (code=1, address=0x10dea0000)
我已经包含了我认为是应用程序最相关的两个部分,UIViewController
和 Objective-C
包装器,并且我在每一行中标记了异常的两行抛出评论。
在我看来这不是并发问题,因为这应该 运行 在主线程上同步。
这是thread backtrace
的结果
* thread #8, queue = 'com.apple.root.default-qos', stop reason = EXC_BAD_ACCESS (code=1, address=0x10dea0000)
* frame #0: 0x000000010505c700 Camera`cv::pointSetBoundingRect(cv::Mat const&) + 432
frame #1: 0x000000010505c8c0 Camera`cvBoundingRect + 236
frame #2: 0x0000000104fdf168 Camera`cvFindNextContour + 4348
frame #3: 0x0000000104fe00fc Camera`cvFindContours_Impl(void*, CvMemStorage*, CvSeq**, int, int, int, CvPoint, int) + 1008
frame #4: 0x0000000104fe118c Camera`cv::findContours(cv::_InputArray const&, cv::_OutputArray const&, cv::_OutputArray const&, int, int, cv::Point_<int>) + 972
frame #5: 0x0000000104fe1bb0 Camera`cv::findContours(cv::_InputArray const&, cv::_OutputArray const&, int, int, cv::Point_<int>) + 96
frame #6: 0x000000010507df68 Camera`cv::aruco::DetectInitialCandidatesParallel::operator()(cv::Range const&) const + 2056
frame #7: 0x0000000104f8e068 Camera`(anonymous namespace)::ParallelLoopBodyWrapper::operator()(cv::Range const&) const + 248
frame #8: 0x0000000104f8df5c Camera`(anonymous namespace)::block_function(void*, unsigned long) + 32
frame #9: 0x0000000105318824 libdispatch.dylib`_dispatch_client_callout2 + 20
这就是我设置 AVCaptureVideoDataOutputSampleBufferDelegate
的方式,它接收每一帧作为 CMSampleBuffer
,将其转换为 UIImage 并将该 UIImage 发送到 opencv 以进行 Aruco 标记检测。
extension ViewController : AVCaptureVideoDataOutputSampleBufferDelegate {
func captureOutput(
_ output: AVCaptureOutput,
didOutput sampleBuffer: CMSampleBuffer,
from connection: AVCaptureConnection) {
let image : UIImage = self.sample_buffer_to_uiimage(sampleBuffer: sampleBuffer)
// call out to opencv wrapper, which eventually blows up
let annotated_image : UIImage = OpenCVWrapper.drawMarkers(image)
self.imageView.image = annotated_image
}
func sample_buffer_to_uiimage(sampleBuffer:CMSampleBuffer) -> UIImage
{
let imageBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
let cimage : CIImage = CIImage(cvPixelBuffer: imageBuffer)
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(cimage, from: cimage.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage)
return image
}
}
这就是我设置 objective-c opencv 包装器方法的方式
+(UIImage *) drawMarkers:(UIImage *)image {
cv::Mat colorImageRGBA;
cv::Mat colorImage;
cv::Mat grayImage;
UIImageToMat(image, colorImageRGBA);
cvtColor(colorImageRGBA, grayImage, cv::COLOR_BGR2GRAY);
cvtColor(colorImageRGBA, colorImage, cv::COLOR_RGBA2RGB);
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
std::vector<int> markerIds;
std::vector<std::vector<cv::Point2f>> markerCorners;
// this is the line that blows up
cv::aruco::detectMarkers(grayImage, dictionary, markerCorners, markerIds);
if (markerIds.size() > 0) {
cv::aruco::drawDetectedMarkers(colorImage, markerCorners, markerIds);
}
return MatToUIImage(colorImage);
}
我报告了一个问题,可以在这里找到:https://github.com/opencv/opencv/issues/15078
详细信息已在问题中报告,但恢复到 OpenCV 4.0.0 将解决您的问题。可能是在合并请求期间出了点问题,3.4.6 的代码库已合并到 4.1.0。
因为,cv::pointSetBoundingRect
在OpenCV 3.4.6和4.1.0中有完全相同的代码,但在4.0.0中进行了重构。
在 4.1.0 中使用旧代码库可能会破坏 NEON/SSE 优化。
不幸的是,深入调试源代码并找到确切的问题并不容易。
干杯
- opencv:4.1.0(带 'contrib' 扩展)
- swift: 5
- IOS: 12.2
我正在尝试 运行 在来自 iphone 相机的每一帧上使用 opencv 的方法 cv::aruco::detectMarkers
。这有效,但大约一分钟后它因错误而崩溃:Thread 8: EXC_BAD_ACCESS (code=1, address=0x10dea0000)
我已经包含了我认为是应用程序最相关的两个部分,UIViewController
和 Objective-C
包装器,并且我在每一行中标记了异常的两行抛出评论。
在我看来这不是并发问题,因为这应该 运行 在主线程上同步。
这是thread backtrace
* thread #8, queue = 'com.apple.root.default-qos', stop reason = EXC_BAD_ACCESS (code=1, address=0x10dea0000)
* frame #0: 0x000000010505c700 Camera`cv::pointSetBoundingRect(cv::Mat const&) + 432
frame #1: 0x000000010505c8c0 Camera`cvBoundingRect + 236
frame #2: 0x0000000104fdf168 Camera`cvFindNextContour + 4348
frame #3: 0x0000000104fe00fc Camera`cvFindContours_Impl(void*, CvMemStorage*, CvSeq**, int, int, int, CvPoint, int) + 1008
frame #4: 0x0000000104fe118c Camera`cv::findContours(cv::_InputArray const&, cv::_OutputArray const&, cv::_OutputArray const&, int, int, cv::Point_<int>) + 972
frame #5: 0x0000000104fe1bb0 Camera`cv::findContours(cv::_InputArray const&, cv::_OutputArray const&, int, int, cv::Point_<int>) + 96
frame #6: 0x000000010507df68 Camera`cv::aruco::DetectInitialCandidatesParallel::operator()(cv::Range const&) const + 2056
frame #7: 0x0000000104f8e068 Camera`(anonymous namespace)::ParallelLoopBodyWrapper::operator()(cv::Range const&) const + 248
frame #8: 0x0000000104f8df5c Camera`(anonymous namespace)::block_function(void*, unsigned long) + 32
frame #9: 0x0000000105318824 libdispatch.dylib`_dispatch_client_callout2 + 20
这就是我设置 AVCaptureVideoDataOutputSampleBufferDelegate
的方式,它接收每一帧作为 CMSampleBuffer
,将其转换为 UIImage 并将该 UIImage 发送到 opencv 以进行 Aruco 标记检测。
extension ViewController : AVCaptureVideoDataOutputSampleBufferDelegate {
func captureOutput(
_ output: AVCaptureOutput,
didOutput sampleBuffer: CMSampleBuffer,
from connection: AVCaptureConnection) {
let image : UIImage = self.sample_buffer_to_uiimage(sampleBuffer: sampleBuffer)
// call out to opencv wrapper, which eventually blows up
let annotated_image : UIImage = OpenCVWrapper.drawMarkers(image)
self.imageView.image = annotated_image
}
func sample_buffer_to_uiimage(sampleBuffer:CMSampleBuffer) -> UIImage
{
let imageBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
let cimage : CIImage = CIImage(cvPixelBuffer: imageBuffer)
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(cimage, from: cimage.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage)
return image
}
}
这就是我设置 objective-c opencv 包装器方法的方式
+(UIImage *) drawMarkers:(UIImage *)image {
cv::Mat colorImageRGBA;
cv::Mat colorImage;
cv::Mat grayImage;
UIImageToMat(image, colorImageRGBA);
cvtColor(colorImageRGBA, grayImage, cv::COLOR_BGR2GRAY);
cvtColor(colorImageRGBA, colorImage, cv::COLOR_RGBA2RGB);
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
std::vector<int> markerIds;
std::vector<std::vector<cv::Point2f>> markerCorners;
// this is the line that blows up
cv::aruco::detectMarkers(grayImage, dictionary, markerCorners, markerIds);
if (markerIds.size() > 0) {
cv::aruco::drawDetectedMarkers(colorImage, markerCorners, markerIds);
}
return MatToUIImage(colorImage);
}
我报告了一个问题,可以在这里找到:https://github.com/opencv/opencv/issues/15078
详细信息已在问题中报告,但恢复到 OpenCV 4.0.0 将解决您的问题。可能是在合并请求期间出了点问题,3.4.6 的代码库已合并到 4.1.0。
因为,cv::pointSetBoundingRect
在OpenCV 3.4.6和4.1.0中有完全相同的代码,但在4.0.0中进行了重构。
在 4.1.0 中使用旧代码库可能会破坏 NEON/SSE 优化。
不幸的是,深入调试源代码并找到确切的问题并不容易。
干杯