简介
形态学(morphology
)一词通常表示生物学的一个分支,它是研究动植物的形态和结构的学科。而我们图像处理中指的形态学,往往表示的是数学形态学。数学形态学(Mathematical morphology
) 的语言是集合论
。同样,形态学为大量的图像处理问题提供了一种一致的有力方法。数字形态学中的集合表示图像中的不同对象。例如,在二值图像中,所有的黑色像素的集合是图像完整的形态学描述。形态学的基本操作有图像腐蚀
、图像膨胀
、开操作
、闭操作
、击中不击中
等。主要应用于边界提取
、区域填充
、连通分量的提取
、凸壳
、细化
、粗化
等方面。
定义
开操作
使用结构元素B对A进行开操作。其实就是B对A腐蚀以后,再用B对腐蚀结果进行膨胀。
闭操作
使用结构元素B对A进行闭操作。其实就是B对A膨胀以后,再用B对膨胀结果进行腐蚀。
形态学梯度
形态学梯度能够描述目标的边界,根据图像腐蚀和膨胀与原图之间的关系计算得到,形态学梯度可以分为基本梯度、内部梯度和外部梯度。基本梯度是原图像膨胀后图像和腐蚀后图像间的差值图像,内部梯度图像是原图像和腐蚀后图像间的差值图像,外部梯度是膨胀后图像和原图像间的差值图像
。
顶帽
图像顶帽运算是原图像与开运算结果之间的差值
,往往用来分离比邻近点亮一些的斑块,因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域。
黑帽
图像黑帽运算是与图像顶帽运算相对应的形态学操作,与顶帽运算相反,黑帽运算是原图像与闭运算结果之间的差值
,往往用来分离比邻近点暗一些的斑块。
击中不击中
击中击不中变换是比图像腐蚀要求更加苛刻的一种形态学操作,图像腐蚀只需要图像能够将结构元素中所有非0元素包含即可,但是击中击不中变换要求原图像中需要存在与结构元素一模一样的结构,即结构元素中非0元素也需要同时被考虑。
API
代码语言:javascript复制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_ERODE0图像腐蚀MORPH_DILATE1图形膨胀MORPH_OPEN2开操作MORPH_CLOSE3闭操作MORPH_GRADIENT4形态学梯度MORPH_TOPHAT5顶帽操作MORPH_BLACKHAT6黑帽操作MORPH_HITMISS7击中击不中运算
- 参数四:kernel,用于形态学操作的结构元素,可以自己定义,也可以用
getStructuringElement()
函数生成 - 参数五:anchor,中心点在结构元素中的位置,默认参数为结构元素的几何中心点
- 参数六:iterations,操作次数,默认值为1
- 参数七:borderType,像素外推法选择标志
- 参数八:borderValue,使用边界不变外推法时的边界值
操作
代码语言:javascript复制/**
* 形态学
* 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()
}
}
效果
形态学操作