为啥 OpenCV 的 MSER 的 Python 实现和 Java 实现会产生不同的输出?

Posted

技术标签:

【中文标题】为啥 OpenCV 的 MSER 的 Python 实现和 Java 实现会产生不同的输出?【英文标题】:Why does Python implementation and Java implementation of OpenCV's MSER create different output?为什么 OpenCV 的 MSER 的 Python 实现和 Java 实现会产生不同的输出? 【发布时间】:2015-08-09 22:24:28 【问题描述】:

我一直在尝试同时使用 OpenCV 的 MSER 算法的 Python 实现(opencv 2.4.11)和 Java 实现(opencv 2.4.10)。有趣的是,我注意到 MSER 的检测在 Python 和 Java 中返回不同类型的输出。在 Python 中,detect 返回一个点列表列表,其中每个点列表代表一个检测到的 blob。在 Java 中,返回一个 Mat,其中每一行是一个点,其相关直径表示检测到的斑点。我想重现 Java 中的 Python 行为,其中 blob 由一组点定义,而不是一个点。有谁知道怎么回事?

Python:

frame = cv2.imread('test.jpg')
mser = cv2.MSER(**dict((k, kw[k]) for k in MSER_KEYS))  
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  
regions = mser.detect(gray, None)
print("REGIONS ARE: " + str(regions))

where the dict given to cv2.MSER is
'_delta':7, '_min_area': 2000, '_max_area': 20000, '_max_variation': .25, '_min_diversity': .2, '_max_evolution': 200, '_area_threshold': 1.01, '_min_margin': .003, '_edge_blur_size': 5

Python 输出:

REGIONS ARE: [array([[197,  58],
   [197,  59],
   [197,  60],
   ..., 
   [143,  75],
   [167,  86],
   [172,  98]], dtype=int32), array([[114,   2],
   [114,   1],
   [114,   0],
   ..., 
   [144,  56],
   [ 84,  55],
   [ 83,  55]], dtype=int32)]

Java:

Mat mat = new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_16S, new Scalar(4));
Mat gray = new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_16S, new Scalar(4));
Imgproc.cvtColor(mat, gray, Imgproc.COLOR_RGB2GRAY, 4);

FeatureDetector fd = FeatureDetector.create(FeatureDetector.MSER);
MatOfKeyPoint regions = new MatOfKeyPoint();
fd.detect(gray, regions);
System.out.println("REGIONS ARE: " + regions);

Java 输出:

REGIONS ARE: Mat [ 10*1*CV_32FC(7), isCont=true, isSubmat=false, nativeObj=0x6702c688, dataAddr=0x59add760 ]

where each row of the Mat looks like
KeyPoint [pt=365.3387451171875, 363.75640869140625, size=10.680443, angle=-1.0, response=0.0, octave=0, class_id=-1]

编辑:

answers.opencv.org 论坛上的一个模组提供了更多信息 (http://answers.opencv.org/question/63733/why-does-python-implementation-and-java-implementation-of-mser-create-different-output/):

不幸的是,看起来 java 版本仅限于 features2d.FeatureDetector 接口,它只允许您访问 KeyPoints(而不是实际的区域)

berak(2015 年 6 月 10 日)

@berak:所以如果我从文档中正确理解,java 版本和 python/C++ 版本都有 features2d.FeatureDetector 接口,但是 python/C++ 版本有额外的 MSER 类来查找区域,而不仅仅是键积分? 在这种情况下,人们会怎么做?是否可以将 C++ MSER 类添加到 OpenCV 管理器,在此处编辑 javaFeatureDetector 之类的内容,并为它创建一个 java 包装器?感谢您的建议。

sloreti(2015 年 6 月 11 日)

是的,您可以在 c++ 或 python 中获取矩形,但不能从 java 中获取。这是设计中的一个缺陷。 javaFeatureDetector 仍在使用中,但要获得矩形,我猜你必须编写自己的 jni 接口。 (并将您自己的 .so 与您的 apk 一起分发)

berak(2015 年 6 月 12 日)

【问题讨论】:

您能否附上您在answers.opencsv.org收到的答复? 根据我的经验,它并不稳定。您是否尝试过这个:相同的图像,但旋转(90 或 180 度),然后使用完全相同的参数应用算法。预计提取的区域将是相同的吗?但它们不一样(区域的数量及其形状)。我在 Python 中进行了测试,您可以看到它在 Python 和 Java 中是如何工作的。 问题解决了吗? @sloreti 【参考方案1】:

您正在对 MSER 实现使用两个不同的接口。

Python cv2.MSER 给你一个包装好的cv::MSER,它把它的operator() 作为detect 暴露给Python:

//! the operator that extracts the MSERs from the image or the specific part of it
CV_WRAP_AS(detect) void operator()( const Mat& image, CV_OUT vector<vector<Point> >& msers,
                                    const Mat& mask=Mat() ) const;

这为您提供了您正在寻找的轮廓界面的漂亮列表。

相比之下,Java 使用 javaFeatureDetector 包装器,它调用由 MSER::detectImpl 支持的 FeatureDetector::detect,并使用标准的 FeatureDetector 接口:关键点列表。

如果您想在 Java 中(在 OpenCV 2.4 中)访问 operator(),您必须将其包装在 JNI 中。

【讨论】:

以上是关于为啥 OpenCV 的 MSER 的 Python 实现和 Java 实现会产生不同的输出?的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV实战——使用MSER提取特征区域

OpenCV 例程 300篇247. 特征检测之最大稳定极值区域(MSER)

OpenCV 例程 300篇247. 特征检测之最大稳定极值区域(MSER)

opencv mser算法框出图片文字区域

有没有人在 OpenCV 中使用 MSER 来检测区域?

Python and OpenCV - 为啥用 OpenCV 处理的裁剪图像仍然可以影响原始图像?