Android(安卓)OpenCV(三十一):图像形态学
简介
形态学(morphology
)一词通常表示生物学的一个分支,它是研究动植物的形态和结构的学科。而我们图像处理中指的形态学,往往表示的是数学形态学。数学形态学(Mathematical morphology
) 的语言是集合论
。同样,形态学为大量的图像处理问题提供了一种一致的有力方法。数字形态学中的集合表示图像中的不同对象。例如,在二值图像中,所有的黑色像素的集合是图像完整的形态学描述。形态学的基本操作有图像腐蚀
、图像膨胀
、开操作
、闭操作
、击中不击中
等。主要应用于边界提取
、区域填充
、连通分量的提取
、凸壳
、细化
、粗化
等方面。
定义
开操作
使用结构元素B对A进行开操作。其实就是B对A腐蚀以后,在用B对腐蚀结果进行膨胀。
dst = o p e n ( src , element ) = d i l a t e ( e r o d e ( src , element ) ) \texttt{dst} = \mathrm{open} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \mathrm{erode} ( \texttt{src} , \texttt{element} )) dst=open(src,element)=dilate(erode(src,element))
闭操作
使用结构元素B对A进行闭操作。其实就是B对A膨胀以后,在用B对膨胀结果进行腐蚀。
dst = c l o s e ( src , element ) = e r o d e ( d i l a t e ( src , element ) ) \texttt{dst} = \mathrm{close} ( \texttt{src} , \texttt{element} )= \mathrm{erode} ( \mathrm{dilate} ( \texttt{src} , \texttt{element} )) dst=close(src,element)=erode(dilate(src,element))
形态学梯度
形态学梯度能够描述目标的边界,根据图像腐蚀和膨胀与原图之间的关系计算得到,形态学梯度可以分为基本梯度、内部梯度和外部梯度。基本梯度是原图像膨胀后图像和腐蚀后图像间的差值图像,内部梯度图像是原图像和腐蚀后图像间的差值图像,外部梯度是膨胀后图像和原图像间的差值图像
。
dst = m o r p h _ g r a d ( src , element ) = d i l a t e ( src , element ) − e r o d e ( src , element ) \texttt{dst} = \mathrm{morph\_grad} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \texttt{src} , \texttt{element} )- \mathrm{erode} ( \texttt{src} , \texttt{element} ) dst=morph_grad(src,element)=dilate(src,element)−erode(src,element)
顶帽
图像顶帽运算是原图像与开运算结果之间的差值
,往往用来分离比邻近点亮一些的斑块,因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域。
dst = t o p h a t ( src , element ) = src − o p e n ( src , element ) \texttt{dst} = \mathrm{tophat} ( \texttt{src} , \texttt{element} )= \texttt{src} - \mathrm{open} ( \texttt{src} , \texttt{element} ) dst=tophat(src,element)=src−open(src,element)
黑帽
图像黑帽运算是与图像顶帽运算相对应的形态学操作,与顶帽运算相反,黑帽运算是原图像与闭运算结果之间的差值
,往往用来分离比邻近点暗一些的斑块。
dst = b l a c k h a t ( src , element ) = c l o s e ( src , element ) − src \texttt{dst} = \mathrm{blackhat} ( \texttt{src} , \texttt{element} )= \mathrm{close} ( \texttt{src} , \texttt{element} )- \texttt{src} dst=blackhat(src,element)=close(src,element)−src
击中不击中
击中击不中变换是比图像腐蚀要求更加苛刻的一种形态学操作,图像腐蚀只需要图像能够将结构元素中所有非0元素包含即可,但是击中击不中变换要求原图像中需要存在与结构元素一模一样的结构,即结构元素中非0元素也需要同时被考虑。
API
public static void morphologyEx(Mat src, Mat dst, int op, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue)
-
参数一:src,输入的待形态学操作图像,图像的通道数可以是任意的,但是图像的数据类型必须是
CV_8U
,CV_16U
,CV_16S
,CV_32F
或CV_64F
-
参数二:dst,形态学操作后的输出图像,与输入图像src具有相同的尺寸和数据类型
-
参数三:op,形态学操作类型的标志
标志位 值 作用 MORPH_ERODE 0 图像腐蚀 MORPH_DILATE 1 图形膨胀 MORPH_OPEN 2 开操作 MORPH_CLOSE 3 闭操作 MORPH_GRADIENT 4 形态学梯度 MORPH_TOPHAT 5 顶帽操作 MORPH_BLACKHAT 6 黑帽操作 MORPH_HITMISS 7 击中击不中运算 -
参数四:kernel,用于形态学操作的结构元素,可以自己定义,也可以用
getStructuringElement()
函数生成 -
参数五:anchor,中心点在结构元素中的位置,默认参数为结构元素的几何中心点
-
参数六:iterations,操作次数,默认值为1
-
参数七:borderType,像素外推法选择标志
-
参数八:borderValue,使用边界不变外推法时的边界值
操作
/** * 形态学 * author: yidong * 2020/7/5 */class MorphologyExActivity : AppCompatActivity() { private lateinit var mBinding: ActivityMorphologyExBinding private lateinit var mBinary: Mat private var mFlag = Imgproc.MORPH_OPEN set(value) { field = value doMorphology(value, mSize.toDouble()) } private var mSize = 3 set(value) { field = value doMorphology(mFlag, value.toDouble()) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = DataBindingUtil.setContentView(this, R.layout.activity_morphology_ex) mBinding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { mSize = progress mBinding.tvSize.text = progress.toString() } override fun onStartTrackingTouch(seekBar: SeekBar?) { } override fun onStopTrackingTouch(seekBar: SeekBar?) { } }) mBinary = Mat() val bgr = Utils.loadResource(this, R.drawable.number) val gray = Mat() Imgproc.cvtColor(bgr, gray, Imgproc.COLOR_BGR2GRAY) Imgproc.threshold(gray, mBinary, 125.0, 255.0, Imgproc.THRESH_BINARY_INV) mBinding.ivLena.showMat(mBinary) bgr.release() gray.release() } override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.menu_morphology_ex, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { title = item.title mFlag = when (item.itemId) { R.id.morphology_close -> { Imgproc.MORPH_CLOSE } R.id.morphology_gradient -> { Imgproc.MORPH_GRADIENT } R.id.morphology_top_hat -> { Imgproc.MORPH_TOPHAT } R.id.morphology_black_hat -> { Imgproc.MORPH_BLACKHAT } R.id.morphology_hit_miss -> { Imgproc.MORPH_HITMISS } else -> Imgproc.MORPH_OPEN } return true } private fun doMorphology(flag: Int, width: Double) { val kernel = Imgproc.getStructuringElement(Imgproc.CV_SHAPE_RECT, Size(width, width)) val dst = Mat() Imgproc.morphologyEx(mBinary, dst, flag, kernel) mBinding.ivResult.showMat(dst) dst.release() }}
效果
源码
https://github.com/onlyloveyd/LearningAndroidOpenCV
扫码关注,持续更新
回复【计算机视觉】【Android】【Flutter】【数字图像处理】获取对应学习资料。
留言可帮觅学习资料。
更多相关文章
- Android学习笔记进阶14之像素操作
- Android开发-通过通俗易懂的Demo让你理解Android中MVC架构和MVP
- 【android】个人推崇的数据库升级方式
- Android中使用SDcard进行文件的读取
- Android(安卓)UI秘笈:谨记该做什么不该做什么 - [图形界面]
- Android设计模式系列--模板方法模式
- Android实现一个简单的SQLite数据库的增删改查
- Android(安卓)AndroidProgressLayout:加载页面遮挡耗时操作任务页
- 【Android(安卓)开发】:UI控件之 ImageView 实现图片旋转和缩放功