OpenCV模板匹配调用cv::Mat::create报错(-215:Assertion failed) s>=0如何解决
报错触发原因
这个error: (-215:Assertion failed) s >= 0 in function 'setSize'是OpenCV创建矩阵时的参数合法性校验失败,触发原因有两个:
- 核心直接原因:
result.create(result_cols, result_rows, CV_32FC1)传入的宽高参数为负数。模板匹配的结果矩阵宽高计算公式是大图宽 - 模板宽 + 1、大图高 - 模板高 + 1,如果待搜索的大图宽度/高度小于子图(模板图)的宽度/高度,计算出来的结果就会是负数,触发断言错误。 - 场景差异原因:App包内的图像资源都是提前处理好的,尺寸固定符合匹配要求;而设备拍摄的图像存在两个常见问题导致尺寸不符合要求:
- UIImage的
imageOrientation属性未被正确处理:你调用的CVMat转换方法如果没有处理图像方向,竖拍的图像转换后会出现宽高颠倒的情况,导致实际大图的宽高小于子图。 - 拍摄的图像本身分辨率低于子图的分辨率,直接导致计算出来的结果矩阵宽高为负。
- UIImage的
修复方案
1. 增加前置合法性校验
在创建结果矩阵之前先校验尺寸是否合法,避免触发崩溃:
int result_cols = tempMat1.cols - tempMat2.cols + 1; int result_rows = tempMat1.rows - tempMat2.rows + 1; // 新增校验逻辑 if (result_cols <= 0 || result_rows <= 0) { NSLog(@"待搜索图像尺寸小于子图,无法执行匹配"); return [[UIImage alloc] initWithCVMat:tempMat1]; } result.create( result_cols, result_rows, CV_32FC1);
2. 校正UIImage的方向
在把UIImage转换为Mat之前,先校正图像方向,确保转换后的宽高符合实际预期,你可以新增如下UIImage分类方法校正方向:
@implementation UIImage (OrientationFix) - (UIImage *)fixOrientation { if (self.imageOrientation == UIImageOrientationUp) return self; CGAffineTransform transform = CGAffineTransformIdentity; switch (self.imageOrientation) { case UIImageOrientationDown: case UIImageOrientationDownMirrored: transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height); transform = CGAffineTransformRotate(transform, M_PI); break; case UIImageOrientationLeft: case UIImageOrientationLeftMirrored: transform = CGAffineTransformTranslate(transform, self.size.width, 0); transform = CGAffineTransformRotate(transform, M_PI_2); break; case UIImageOrientationRight: case UIImageOrientationRightMirrored: transform = CGAffineTransformTranslate(transform, 0, self.size.height); transform = CGAffineTransformRotate(transform, -M_PI_2); break; default: break; } switch (self.imageOrientation) { case UIImageOrientationUpMirrored: case UIImageOrientationDownMirrored: transform = CGAffineTransformTranslate(transform, self.size.width, 0); transform = CGAffineTransformScale(transform, -1, 1); break; case UIImageOrientationLeftMirrored: case UIImageOrientationRightMirrored: transform = CGAffineTransformTranslate(transform, self.size.height, 0); transform = CGAffineTransformScale(transform, -1, 1); break; default: break; } CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height, CGImageGetBitsPerComponent(self.CGImage), 0, CGImageGetColorSpace(self.CGImage), CGImageGetBitmapInfo(self.CGImage)); CGContextConcatCTM(ctx, transform); switch (self.imageOrientation) { case UIImageOrientationLeft: case UIImageOrientationLeftMirrored: case UIImageOrientationRight: case UIImageOrientationRightMirrored: CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage); break; default: CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage); break; } CGImageRef cgimg = CGBitmapContextCreateImage(ctx); UIImage *img = [UIImage imageWithCGImage:cgimg]; CGContextRelease(ctx); CGImageRelease(cgimg); return img; } @end
修改转换Mat的代码为:
cv::Mat tempMat1 = [[largerImage fixOrientation] CVMat]; cv::Mat tempMat2 = [[subImage fixOrientation] CVMat];
3. 可选优化:统一转换为灰度图
放开代码中注释的转灰度逻辑,避免因为包内图和拍摄图通道数不一致(比如拍摄图是4通道RGBA,子图是3通道RGB)导致的其他匹配错误:
cv::cvtColor(tempMat1, tempMat1, cv::COLOR_RGB2GRAY); cv::cvtColor(tempMat2, tempMat2, cv::COLOR_RGB2GRAY);
内容的提问来源于stack exchange,提问作者Anand
相关产品推荐
相关产品推荐

