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)=srcopen(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_8UCV_16UCV_16SCV_32FCV_64F

  • 参数二:dst,形态学操作后的输出图像,与输入图像src具有相同的尺寸和数据类型

  • 参数三:op,形态学操作类型的标志

    标志位作用
    MORPH_ERODE0图像腐蚀
    MORPH_DILATE1图形膨胀
    MORPH_OPEN2开操作
    MORPH_CLOSE3闭操作
    MORPH_GRADIENT4形态学梯度
    MORPH_TOPHAT5顶帽操作
    MORPH_BLACKHAT6黑帽操作
    MORPH_HITMISS7击中击不中运算
  • 参数四: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】【数字图像处理】获取对应学习资料。
留言可帮觅学习资料。

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