Android基于OpenCV实现Harris角点检测
作者:易冬 发布时间:2023-07-16 12:19:47
目录
什么是角点?
为什么要检测角点?
Harris角点检测
API
操作
效果
源码
什么是角点?
角点就是极值点,即在某方面属性特别突出的点。当然,你可以自己定义角点的属性(设置特定熵值进行角点检测)。角点可以是两条线的交叉处,也可以是位于相邻的两个主要方向不同的事物上的点。角点通常被定义为两条边的交点,或者说,角点的局部邻域应该具有两个不同区域的不同方向的边界。常见的角点有:
灰度梯度的最大值对应的像素点;
两条直线或者曲线的交点;
一阶梯度的导数最大值和梯度方向变化率最大的像素点;
一阶导数最大,二阶导数为零的像素点(指示物体边缘变化不连续的方向)。
为什么要检测角点?
角点是图像很重要的特征,对图像图形的理解和分析有很重要的作用。角点在保留图像图形重要特征的同时,可以有效地减少信息的数据量,使其信息的含量很高,有效地提高了计算的速度,有利于图像的可靠匹配,使得实时处理成为可能。角点在三维场景重建、运动估计、目标跟踪、目标识别、图像配准与匹配等计算机视觉领域起着非常重要的作用。
Harris角点检测
人眼对角点的识别通常是在一个局部的小区域或小窗口完成的。如果在各个方向上移动这个特征的小窗口,窗口内区域的灰度发生了较大的变化,那么就认为在窗口内遇到了角点。如果这个特定的窗口在图像各个方向上移动时,窗口内图像的灰度没有发生变化,那么窗口内就不存在角点;如果窗口在某一个方向移动时,窗口内图像的灰度发生了较大的变化,而在另一些方向上没有发生变化,那么,窗口内的图像可能就是一条直线的线段。
Harris角点检测原理用公式演算如下:
其中w(x,y)表示滑动窗口权重函数,可以是常数也可以是高斯函数。E(u,v)表示滑动窗口向各个方向移动时像素值衡量系数的变化。
这里λ1,λ2是矩阵M的2个特征值,k是一个指定值,这是一个经验参数,需要实验确定它的合适大小,通常它的值在0.04和0.06之间,它的存在只是调节函数的形状而已。R取决于M的特征值,对于角点|R|很大,平坦的区域|R|很小,边缘的R为负值;
API
public static void cornerHarris(Mat src, Mat dst, int blockSize, int ksize, double k, int borderType)
参数一:src,输入源图像。必须是单通道8U或者32F类型。
参数二:dst,输出评价系数R的矩阵。尺寸与src相同,类型为单通道32F。
参数三:blockSize,邻域大小。
参数四:ksize,Sobel算子的半径。
参数五:k,计算Harris评价系数R的权重系统。
参数六:borderType,像素外推算法标志位。
方法的输出dst为评价系数R的矩阵,由于评价系数有正有负且范围较广,计算结束后通常需要进行归一化处理。然后通过经验阈值比较判断像素点是否为Harris角点。阈值越大,提取的Harris角点越少,阈值越小,提取的Harris角点越多。
操作
/**
* Harris角点检测
* author: yidong
* 2020/12/30
*/
class HarrisActivity : AppCompatActivity() {
private val mBinding: ActivityHarrisBinding by lazy {
ActivityHarrisBinding.inflate(layoutInflater)
}
private val gray by lazy {
this.getBgrFromResId(R.drawable.lena).toGray()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
mBinding.ivLena.showMat(gray)
wrapCoroutine({ showLoading() }, { doCornerHarris() }, { hideLoading() })
}
private fun doCornerHarris() {
val dst = Mat()
val dstNorm = Mat()
val dstNormal8U = Mat()
Imgproc.cornerHarris(gray, dst, 2, 3, 0.04)
Core.normalize(dst, dstNorm, 0.0, 255.0, Core.NORM_MINMAX)
Core.convertScaleAbs(dstNorm, dstNormal8U)
Imgproc.threshold(dstNormal8U, dstNormal8U, 120.0, 255.0, Imgproc.THRESH_BINARY)
GlobalScope.launch(Dispatchers.Main) {
mBinding.ivResult.showMat(dstNormal8U)
}
}
private fun showLoading() {
mBinding.isLoading = true
}
private fun hideLoading() {
mBinding.isLoading = false
}
override fun onDestroy() {
super.onDestroy()
gray.release()
}
}
效果
如下图,图中白点即为评价系数大于120的角点检测结果。代码中的参数可自行调整测试。
源码
github.com/onlyloveyd/…
来源:https://juejin.cn/post/6976746764082610206


猜你喜欢
- 本文实例为大家分享了视频播放器的两种方式,供大家参考,具体内容如下1)、SurfaceView在布局文件中<?xml version=
- 协程与并发Kotlin协程是基于线程执行的。经过一层封装以后,Kotlin协程面对并发,处理方式与Java不同。在java的世界里,并发往往
- 本文实例为大家分享了AndroidStudio简单实现BMI计算的具体代码,供大家参考,具体内容如下xml代码```xml<TextV
- import android.provider.Settings.Secure;private String android_id = Se
- 本文实例为大家分享了Unity实现打砖块游戏的具体代码,供大家参考,具体内容如下效果演示1.创建墙1.1我们用预制体来统一管理墙方便以后对墙
- 本文实例为大家分享了java实现PDF转图片的具体代码,供大家参考,具体内容如下1.首先利用maven引入所需jar包<depende
- Java连接SQLServer 2008数据库的步骤:1.到微软官方下载jdbc 并解压,得到sqljdbc.jar和sqljdbc4.ja
- 本文实例讲述了Android基于TextView实现的跑马灯效果。分享给大家供大家参考,具体如下:package sweet.venst.a
- 创建普通Maven工程导入所需依赖坐标:<dependencies> <!-- https://
- 我的接口是这样的:TestCase测试Impl类的方法没有问题,但是Swgger和前端调用接口就会报404错误:在网上查了很多资料,都说是地
- 现如今打开一个 App,比如头条、微博,都会有长列表,随着我们不断地滑动,视窗内的内容也会不断地更新。今天就用 Flutter 实现一下这种
- CountDownLatch简介CountDownLatch顾名思义,count + down + latch = 计数 + 减 + 门闩(
- 1 MapStruct配置MapStuct的使用非常简单,把对应的jar包引入即可。<properties> &n
- HandlerThread 顾名思义就是一种可以使用 Handler 的 Thread。日常开发中我们经常会通过创建一个 Thread 去执
- 文章描述可能我标题描述不太准确,所以还是要稍微解释下:横线样式就是将TextBox以一条底横线的形式展示在页面,占位提示就是Web的Plac
- 主要通过System.Resources.ResourceManager类中GetString和GetObject两个方法。两个方法的返回值
- JavaConfig,是在 Spring 3.0 开始从一个独立的项目并入到 Spring 中的。JavaConfig 可以看成一个用于完成
- 1、线程数使用开发规约阿里巴巴开发手册中关于线程和线程池的使用有如下三条强制规约【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时
- android中执行java命令的方法大家都晓得吗,下面一段内容给大家带来了具体解析。android的程序基于java开发,当我们接上调试器
- 高斯模糊是什么?高斯模糊(英语:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NE