从 Objective C++ 调用 OpenCv inRange 函数时的行为不同
Posted
技术标签:
【中文标题】从 Objective C++ 调用 OpenCv inRange 函数时的行为不同【英文标题】:OpenCv inRange function behaves differently when called from Objective C++ 【发布时间】:2018-02-18 21:50:18 【问题描述】:我在这里使用了这个问题的优秀答案:
How to detect bullet holes on the target using python
我已经验证它在 Python 2 和 3.6 中都可以工作,但我想在一个用 Objective C(++) 编写的 ios 应用程序中使用这个概念。这是我翻译它的尝试。最终,我需要它来处理相机拍摄的图像,所以我不想使用 imread,但我已经检查过这没有什么区别。
UIImage *nsi = [UIImage imageNamed:@"CANDX.jpg"];
cv::Mat original;
UIImageToMat(nsi, original);
cv::Mat thresholded;
cv::inRange(original, cv::Scalar(40,40,40), cv::Scalar(160,160,160), thresholded);
cv::Mat kernel = cv::Mat::ones(10, 10, CV_64FC1);
cv::Mat opening;
cv::morphologyEx(thresholded, opening, cv::MORPH_OPEN, kernel);
vector<vector<cv::Point>> contours;
cv::findContours(opening, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
使用与 Python 版本相同的值对 inRange 的调用会给出一个完全黑色的图像。实际上,不可能为不会导致此结果的下限和上限选择值。我尝试将图像转换为 HSV 并使用 HSV 值作为下限和上限。这有点不同,因为我可以获得一些模糊可识别的结果,但与我应该得到的有用结果完全不同。
如果我从答案中替换“阈值”图像并注释掉 inRange 调用,morphology
和 findContours
调用工作正常。
我在设置 inRange 调用时做错了吗?
【问题讨论】:
您所指的原始问题不存在——您是否获得了正确的链接? 感谢@DanMašek,不知道我是如何错误地粘贴它的!现已编辑。original
cv::Mat 的元素(和通道数)的数据类型是什么?
感谢@DanMašek,我认为元素的数据类型是CV_8UC4,查看github.com/opencv/opencv/blob/master/modules/imgcodecs/src/… 中的UIImageToMat 的来源。通道数在我的代码中报告为 4。
完美!非常感谢。如果你想把它写成答案,我所要做的就是在 inRange 调用之前输入cvtColor(original, original, cv::COLOR_BGRA2BGR);
。
【参考方案1】:
正如您在 cmets 中提到的,original
的数据类型是 CV_8UC4
——即它是一个 4 通道图像。但是,在您致电 cv::inRange
时,您只提供了 3 个频道的范围。
cv::Scalar
表示一个 4 元素向量。当您仅使用 3 个值调用 constructor 时,第 4 个元素使用默认值 0。
因此,您对inRange
的调用实际上等同于:
cv::inRange(original, cv::Scalar(40,40,40,0), cv::Scalar(160,160,160,0), thresholded);
您只寻找 Alpha 通道设置为 0(完全透明)的像素。由于图像来自相机,因此不太可能有任何透明像素 - Alpha 通道可能只有全部 255。
有两种方法可以解决这个问题:
删除不需要的 Alpha 通道。一种方法是使用cv::cvtColor
,例如
cv::cvtColor(original, original, cv::COLOR_BGRA2BGR);
为所有通道指定所需的范围,例如
cv::inRange(original, cv::Scalar(40,40,40,0), cv::Scalar(160,160,160,255), thresholded);
【讨论】:
以上是关于从 Objective C++ 调用 OpenCv inRange 函数时的行为不同的主要内容,如果未能解决你的问题,请参考以下文章
使用另一个 C++ 类作为参数从 Objective-C(++) 调用 C++ 方法
从 Android 中的本机 c++ 文件调用本机 opencv