Android OpenCV(五十三):Shi-Tomasi角点检测

Shi-Tomasi角点检测

在Harris角点检测中,Harris角点评价系数R表示为:
R = d e t ( M ) − k ( t r a c e ( M ) ) 2 R=det(M)-k(trace(M))^2 R=det(M)k(trace(M))2

d e t ( M ) = λ 1 λ 2 det(M)=λ_1λ_2 det(M)=λ1λ2

t r a c e ( M ) = λ 1 + λ 2 trace(M)=λ_1+λ_2 trace(M)=λ1+λ2

其 中 d e t ( M ) = λ 1 λ 2 是 矩 阵 的 行 列 式 , t r a c e ( M ) = λ 1 + λ 2 是 矩 阵 的 迹 其中det(M)=λ_1λ_2是矩阵的行列式,trace(M)=λ_1+λ_2是矩阵的迹 det(M)=λ1λ2trace(M)=λ1+λ2

λ1 和 λ2 是矩阵M的特征值, k是一个经验常数,在范围 (0.04, 0.06) 之间。由于 Harris 角点检测算法的稳定性和 k 值有关,而 k 是个经验值,不好设定最佳值,且角点的稳定性与矩阵 M 的较小特征值有关,于是直接用较小的那个特征值作为评价系数。所以在Shi-Tomasi算法中,评价系数R表示为:
R = m i n ( λ 1 , λ 2 ) R=min(λ_1,λ_2) R=min(λ1,λ2)

如果某个像素点R值大于阈值,则像素点是为角点。把它绘制到 λ1 ~ λ2 空间中,就会得到下图:

Shi-Tomasi Corner Space

API

public static void goodFeaturesToTrack(Mat image, MatOfPoint corners, int maxCorners, double qualityLevel, double minDistance, Mat mask, int blockSize, boolean useHarrisDetector, double k)
  • 参数一:image,输入源图像。必须是单通道8U或者32F类型。
  • 参数二:corners,检测到的角点输出量。
  • 参数三:maxCorners,返回角点数目最大值。如果实际检测到的角点大于返回数目最大值,则返回最强的maxCorners个角点。若此参数设置为0,则无此限制。
  • 参数四:qualityLevel,表示图像角点的最低可接受水平。比如最强角点评价系数为1500,并且此参数为0.01,那么所有评价系数低于15的将都会被排除在外,不是角点,即15就是检测角点的阈值。
  • 参数五:minDistance,角点之间的最小欧几里得距离。
  • 参数六:mask,掩码矩阵,表示检测角点的区域。如果参数不为空,则必须是和源图像大小相同的单通道8U图像。
  • 参数七:blockSize,计算梯度协方差矩阵的尺寸。
  • 参数八:useHarrisDetector,是否使用Harris角点检测。默认为false,使用Shi-Tomasi算法。
  • 参数九:k,Harris角点检测过程中的权重系数。

操作

/**
 * Shi-Tomas角点检测
 * author: yidong
 * 2021/1/7
 */
class ShiTomasiActivity : AppCompatActivity() {

    private val gray by lazy {
        getBgrFromResId(R.drawable.lena).toGray()
    }
    private val rgb by lazy {
        getBgrFromResId(R.drawable.lena).toRgb()
    }
    private val mBinding: ActivityShiTomasBinding by lazy {
        ActivityShiTomasBinding.inflate(layoutInflater)
    }

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

    private fun doShiTomas() {
        val corners = MatOfPoint()
        val maxCorners = 100;
        val qualityLevel = 0.1
        val minDistance = 0.04
        
        Imgproc.goodFeaturesToTrack(
            gray,
            corners,
            maxCorners,
            qualityLevel,
            minDistance,
            Mat(),
            3,
            false
        )
        val points = corners.toList()
        val result = rgb.clone()
        GlobalScope.launch(Dispatchers.Main) {
            for (point in points) {
                Imgproc.circle(result, point, 10, Scalar(0.0, 255.0, 0.0), 2, Imgproc.LINE_8)
            }
            mBinding.ivResult.showMat(result)
        }
    }

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

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

    override fun onDestroy() {
        super.onDestroy()
        gray.release()
        rgb.release()
    }
}

效果

在这里插入图片描述

源码

https://github.com/onlyloveyd/LearningAndroidOpenCV

关注我

关注左侧公众号【OpenCV or Android】
回复【计算机视觉】【Android】【Flutter】【OpenCV】白嫖学习资料。

onlyloveyd CSDN认证博客专家 Android Kotlin OpenCV
个人公众号【OpenCV or Android】,热爱Android、Kotlin、Flutter和OpenCV。毕业于华中科技大学计算机专业,曾就职于华为武汉研究所。目前在三线小城市生活,专注技术与研发。
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 博客之星2020 设计师:CY__0809 返回首页