This is the 28th day of my participation in Gwen Challenge

preface

In the last article in the Android OpenCV series, we learned about violent matching for ORB feature points. As a review, the violent matching method will look for matching descriptors in training descriptors for each descriptor in query descriptors, and the algorithm complexity is O(N2N ^2n2) level. With the increase of the number of feature points, the running speed will be significantly affected. So, today we introduce another matching method — Fast Library for Approximate Nearest Neighbors (FLANN). It is a collection of algorithms that have been optimized for the nearest neighbor search of large data sets and high-dimensional features. It performs better than BFMatcher in the face of large data sets.

API

FLANN verifier

public static FlannBasedMatcher create(a)
Copy the code

DescriptorMatcher generic filter

public static DescriptorMatcher create(String descriptorMatcherType)
Copy the code
  • Parameter 1: descriptorMatcherType, describes the child matcher type. The following five matching types are supported:
    • BruteForce
    • BruteForce-L1
    • BruteForce-Hamming
    • BruteForce-Hamming(2)
    • FlannBased
public static DescriptorMatcher create(int matcherType) 
Copy the code

Parameter 1: matcherType describes the type of the child matcher. The following matching types are supported:

public static final int
        FLANNBASED = 1,
        BRUTEFORCE = 2,
        BRUTEFORCE_L1 = 3,
        BRUTEFORCE_HAMMING = 4,
        BRUTEFORCE_HAMMINGLUT = 5,
        BRUTEFORCE_SL2 = 6;
Copy the code

Therefore, for FLANN matchers, construction can be completed in the following three ways:

val matcher = FlannBasedMatcher.create() / / method

val matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED) / / method 2

val matcher = DescriptorMatcher.create("FlannBased") / / method 3
Copy the code

operation

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(a) {
        mBinding.isLoading = true
    }

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

    private fun doORBFlannMatch(a) {
        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.2 f
        )
        orbDetector.detect(source, keyPoints)
        orbDetector.compute(source, keyPoints, descriptor)
        Log.e(App.TAG, "count = ${keyPoints.size()}")}override fun onDestroy(a) {
        firstBgr.release()
        secondBgr.release()
        firstGray.release()
        secondGray.release()
        super.onDestroy()
    }
}
Copy the code

The effect

The source code

Github.com/onlyloveyd/…