B95a4df622aff5ec0488153380c17619
Learning OpenCV with iOS: 形态学--膨胀与腐蚀

一、前言

上一篇 我们讲解了OpenCV图像模糊中的非线性滤波。本篇向大家介绍下形态学操作。按惯例,先来看下效果图。

王者膨胀

王者膨胀

二、形态学

形态学(morphology)通常表示生物学的一个分支,该分支主要研究动植物的形态和结构。而图像处理中的形态学,指的是数学形态学。
数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:膨胀与腐蚀、开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰值腐蚀和膨胀、灰值开闭运算、灰值形态学梯度等。 简单来讲,形态学操作就是基于形状的一系列图像处理操作。
OpenCV为形态学操作提供了快捷、方便的函数。最基本的形态学操作有二种,分别是:膨胀与腐蚀。

三、膨胀

概念

膨胀操作就是将图像(下图灰黑色部分)与(下图白色的9宫格)进行卷积。核可以是任何的形状和大小,它拥有一个单独定义出来的参考点,我们称其为锚点(如图中9宫格的红色格)。这个核就是第二篇所讲的卷积算子。而膨胀操作与第二篇所讲的增加对比度操作的不同在于,膨胀操作求的是局部最大值,也就是9宫格中的最大值赋值给红色格子对应的点。

卷积

卷积

公式

dst(x, y) = max src(x+x', y+y')

概念和公式太难懂,我们一图胜千言。

膨胀操作的效果就是让“王者荣耀”变瘦了。也许你会有疑问,不是膨胀吗?膨胀不是变胖吗?记住,膨胀操作是求局部最大值,而对于图像而言,像素值(0~255)值越大,越靠近白色。因为“王者荣耀”字的颜色是黑色的,所以膨胀后,被周围的白色侵蚀,所以变瘦了。

OpenCV 提供了便捷的膨胀操作API

@param kernel  InputArray类型的kernel,膨胀操作的核。若elemenat=Mat(),表示的是使用参考点位于中心3x3的核。kernel可以使用getStructuringElement来构建
@param anchor 锚点位置默认值为 (-1, -1) ,表示为中心点
@param iterations 迭代使用函数的次数,默认值为1.
 */
CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel,
                          Point anchor = Point(-1,-1), int iterations = 1,
                          int borderType = BORDER_CONSTANT,
                          const Scalar& borderValue = morphologyDefaultBorderValue() );
/** 
@param shape 结构元素的形状,可取值MORPH_RECT、MORPH_CROSS、MORPH_ELLIPSE
@param ksize 结构元素的大小
 */
CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));

王者膨胀

王者膨胀

王者膨胀

+ (UIImage *)dilate:(UIImage *)image sizeX:(int)sizeX sizeY:(int)sizeY {
    Mat src;
    UIImageToMat(image, src);

    Mat dst;
    Mat kernel = getStructuringElement(MORPH_RECT, cv::Size(sizeX, sizeY));
    dilate(src, dst, kernel);

    UIImage* result = MatToUIImage(dst);

    return result;
}

class DilateViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var resultImageView: UIImageView!

    private var sizeX: Int32 = 3
    private var sizeY: Int32 = 3

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func onSliderValueChanged(_ sender: UISlider) {
        sizeX = Int32(sender.value)
        transform()
    }

    @IBAction func onSlider2ValueChanged(_ sender: UISlider) {
        sizeY = Int32(sender.value)
        transform()
    }

    private func transform() {
        if sizeX == 0 && sizeY == 0 {
            resultImageView.image = imageView.image
        } else {
            if sizeX%2 == 0 {
                sizeX = sizeX + 1
            }
            if sizeY%2 == 0 {
                sizeY = sizeY + 1
            }
            let image = OpenCV.dilate(imageView.image, sizeX: sizeX, sizeY: sizeY)
            resultImageView.image = image
        }
    }
}

思考

top Created with Sketch.