前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android OpenCV(五十七):ORB特征点FLANN匹配

Android OpenCV(五十七):ORB特征点FLANN匹配

作者头像
Vaccae
发布2021-11-05 10:46:25
1.9K0
发布2021-11-05 10:46:25
举报
文章被收录于专栏:微卡智享微卡智享

前言

Android OpenCV 系列的上一篇文章中,我们学习了 ORB 特征点的暴力匹配方式。复习一下,暴力匹配法会针对查询描述子中的每个描述符在训练描述子中寻找匹配描述子,算法复杂度是 O(

n^2

) 级别的,随着特征点数量的增加,运行速度会受到明显的影响。所以,我们今天介绍另外一种匹配方法—— (近似)最近邻快速搜索库(Fast Library for Approximate Nearest Neighbors,FLANN)。它是一个对大数据集和高维特征进行最近邻搜索的算法的集合,而且这些算法都已经被优化过了。在面对大数据集时它的效果要好于BFMatcher。

API

FlannBasedMatcher

FLANN匹配器

代码语言:javascript
复制
public static FlannBasedMatcher create()

DescriptorMatcher通用匹配器

代码语言:javascript
复制
public static DescriptorMatcher create(String descriptorMatcherType)
  • 参数一:descriptorMatcherType,描述子匹配器类型。支持下列五种匹配类型:
    • BruteForce
    • BruteForce-L1
    • BruteForce-Hamming
    • BruteForce-Hamming(2)
    • FlannBased
代码语言:javascript
复制
public static DescriptorMatcher create(int matcherType) 

参数一:matcherType,描述子匹配器类型。支持下列几种匹配类型:

代码语言:javascript
复制
public static final int
        FLANNBASED = 1,
        BRUTEFORCE = 2,
        BRUTEFORCE_L1 = 3,
        BRUTEFORCE_HAMMING = 4,
        BRUTEFORCE_HAMMINGLUT = 5,
        BRUTEFORCE_SL2 = 6;

所以,针对 FLANN 匹配器,如下三种方式均可以完成构建:

代码语言:javascript
复制
val matcher = FlannBasedMatcher.create() // 方法一

val matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED) // 方法二

val matcher = DescriptorMatcher.create("FlannBased") // 方法三

操作

代码语言:javascript
复制
class ORBFLANNMatchActivity : AppCompatActivity() {

    private val firstBgr by lazy {
        Utils.loadResource(this, R.drawable.lena)
    }
    private val firstGray by lazy { firstBgr.toGray() }

    private val secondBgr by lazy {
        Utils.loadResource(this, R.drawable.lena_250)
    }
    private val secondGray by lazy { secondBgr.toGray() }

    private val mBinding: ActivityOrbFlannBinding by lazy {
        ActivityOrbFlannBinding.inflate(layoutInflater)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(mBinding.root)
        wrapCoroutine({ showLoading() }, { doORBFlannMatch() }, { hideLoading() })
    }

    private fun showLoading() {
        mBinding.isLoading = true
    }

    private fun hideLoading() {
        mBinding.isLoading = false
    }

    private fun doORBFlannMatch() {
        val firstKeyPoints = MatOfKeyPoint()
        val secondKeyPoints = MatOfKeyPoint()

        val firstDescriptor = Mat()
        val secondDescriptor = Mat()

        orbFeatures(firstGray, firstKeyPoints, firstDescriptor)
        orbFeatures(secondGray, secondKeyPoints, secondDescriptor)
        if (firstDescriptor.type() != CvType.CV_32F && secondDescriptor.type() != CvType.CV_32F) {
            firstDescriptor.convertTo(firstDescriptor, CvType.CV_32F)
            secondDescriptor.convertTo(secondDescriptor, CvType.CV_32F)
        }

        val matches = MatOfDMatch()
        val matcher = FlannBasedMatcher.create()
//        val matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED)
//        val matcher = DescriptorMatcher.create("FlannBased")
        matcher.match(firstDescriptor, secondDescriptor, matches)
        Log.e(App.TAG, " matchers size = ${matches.size()}")

        val list = matches.toList()
        list.sortBy { it.distance }
        Log.e(App.TAG, "Min = ${list.first().distance}")
        val min = list.first().distance
        val max = list.last().distance

        val goodMatchers = list.filter {
            it.distance < max.times(0.4)
        }

        Log.e(App.TAG, " good matchers size = ${goodMatchers.size}")

        val result = Mat()
        val matOfDMatch = MatOfDMatch()
        matOfDMatch.fromList(goodMatchers)
        drawMatches(firstGray, firstKeyPoints, secondGray, secondKeyPoints, matOfDMatch, result)
        GlobalScope.launch(Dispatchers.Main) {
            mBinding.ivResult.showMat(result)
        }
    }

    private fun orbFeatures(source: Mat, keyPoints: MatOfKeyPoint, descriptor: Mat) {
        val orbDetector = ORB.create(
            1000,
            1.2f
        )
        orbDetector.detect(source, keyPoints)
        orbDetector.compute(source, keyPoints, descriptor)
        Log.e(App.TAG, "count = ${keyPoints.size()}")
    }

    override fun onDestroy() {
        firstBgr.release()
        secondBgr.release()
        firstGray.release()
        secondGray.release()
        super.onDestroy()
    }
}

效果

FLANN匹配结果

源码

https://github.com/onlyloveyd/LearningAndroidOpenCV

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微卡智享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • API
    • FLANN匹配器
      • DescriptorMatcher通用匹配器
      • 操作
      • 效果
      • 源码
      相关产品与服务
      大数据
      全栈大数据产品,面向海量数据场景,帮助您 “智理无数,心中有数”!
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档