Android OpenCV(三十):​图像膨胀

图像腐蚀、膨胀属于形态学的操作,就是基于形状的一系列图像处理操作。数字形态学的基本思想是:用具有一定形态的结构元素去量度和提取图像中的对应形状,以达到图像分析和识别的目的。图像腐蚀、膨胀是基于高亮部分(白色)操作的,膨胀是对高亮部分进行膨胀,类似“领域扩张”,腐蚀是高亮部分被腐蚀,类似“领域蚕食”。膨胀腐蚀的应用主要体现在消除噪声、分割独立元素或者连接相邻元素、寻找图像中明显极大值、极小值区域以及求图像的梯度。

图像膨胀

图像膨胀的作用是将目标图像扩大,运算效果取决于结构元素大小内容以及逻辑运算性质。图像膨胀操作可以用来填补目标区域中某些空洞以及消除包含在目标区域中的小颗粒噪声。

膨胀的算法

  • 用结构元素,扫描图像的每一个元素;
  • 用结构元素与其覆盖的二值图像做操作;
  • 如果有一个为1,结果图像的该元素为1。否则为0。
  • 结果:使二值图像扩大一圈

[dst(x,y)=max(x,y):element(x,y)0src(x+x,y+y)] [\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')]

膨胀的定义

对集合AB,使用BA进行膨胀,用
AB A\bigoplus B

表示,并使用
(B)z (B)_z
表示B平移z后得到的结果,若平移后的结果和A的交集不为空,则我们记录下z点,所有满足上述条件的z点组成的集合就是A被B膨胀后的结果。表示为:
AB=z(B)zA A\bigoplus B = | z | (B)_z \bigcap A\neq \varnothing|

膨胀示意图

膨胀示意图

API

public static void dilate(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue) 
  • 参数一:src,输入的待膨胀图像,图像的通道数可以是任意的,但是图像的数据类型必须是CV_8UCV_16UCV_16SCV_32FCV_64F

  • 参数二:dst,膨胀后的输出图像,与输入图像src具有相同的尺寸和数据类型

  • 参数三:kernel,用于膨胀操作的结构元素,可以自己定义,也可以用getStructuringElement()函数生成

  • 参数四:anchor,中心点在结构元素中的位置,默认参数为结构元素的几何中心点

  • 参数五:iterations,膨胀的次数,默认值为1

  • 参数六:borderType,像素外推法选择标志

  • 参数七:borderValue,使用边界不变外推法时的边界值

public static Mat getStructuringElement(int shape, Size ksize, Point anchor) 
  • 参数一:shape,结构元素的种类

    // C++: enum MorphShapes_c
    public static final int
            CV_SHAPE_RECT = 0,  
            CV_SHAPE_CROSS = 1, 
            CV_SHAPE_ELLIPSE = 2, 
            CV_SHAPE_CUSTOM = 100;
    
  • 参数二:ksize,结构元素的尺寸大小

  • 参数三:anchor,中心点的位置,默认参数为结构元素的几何中心点

关于结构体形状

  • CV_SHAPE_RECT:矩形结构元素

[Eij=1] [E_{ij}=1]

  • CV_SHAPE_CROSS:十字形结构元素

[Eij={1if i=anchor.y orj=anchor.x0otherwise] [E_{ij} = \begin{cases} 1 & \texttt{if } {i=\texttt{anchor.y } {or } {j=\texttt{anchor.x}}} \\0 & \texttt{otherwise} \end{cases}]

  • CV_SHAPE_ELLIPSE:椭圆结构体元素。矩形内椭圆。
    5X5矩形结构体
    5X5十字形结构体
    5X5椭圆结构体

操作

/**
 * 图像膨胀
 *
 * @author yidong
 * @date 2020/6/24
 */
class DilateActivity : AppCompatActivity() {

    private lateinit var mBinding: ActivityDilateBinding
    private lateinit var mBinary: Mat
    private var mFlag = Imgproc.CV_SHAPE_RECT
        set(value) {
            field = value
            doDilate(value, mSize.toDouble())
        }
    private var mSize = 3
        set(value) {
            field = value
            doDilate(mFlag, value.toDouble())
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_dilate)
        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?) {

            }
        })

        val bgr = Utils.loadResource(this, R.drawable.opencv)
        mBinary = Mat()
        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_dilate, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        mFlag = when (item.itemId) {
            R.id.dilate_cross -> {
                Imgproc.CV_SHAPE_CROSS
            }
            R.id.dilate_ellipse -> {
                Imgproc.CV_SHAPE_ELLIPSE
            }
            else -> Imgproc.CV_SHAPE_RECT
        }
        return true
    }

    private fun doDilate(flag: Int, width: Double) {
        title = "Flag = $flag,Size = ${width}X${width}"
        val kernel = Imgproc.getStructuringElement(flag, Size(width, width))
        val result = Mat()
        Imgproc.dilate(mBinary, result, kernel)
        GlobalScope.launch(Dispatchers.Main) {
            mBinding.ivResult.showMat(result)
            result.release()
        }
    }
    
    override fun onDestroy() {
        mBinary.release()
        super.onDestroy()
    }
}

效果

膨胀效果

源码

https://github.com/onlyloveyd/LearningAndroidOpenCV

扫码关注,持续更新

回复【计算机视觉】【Android】【Flutter】【数字图像处理】获取对应学习资料。
留言可帮觅学习资料。

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

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值