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/…