1. 程式人生 > >opencv學習(二十四)之腐蝕與膨脹

opencv學習(二十四)之腐蝕與膨脹

腐蝕和膨脹是對二維圖片的進行操作的形態學運算,簡單來講形態學操作就是基於形狀的一系列影象處理操作,通過將結構元素作用於輸入影象來產生輸出影象。腐蝕(Erosion)和膨脹(Dilation)是最基本的形態學操作,他們運用廣泛主要有:
. 消除噪聲
. 分割(ioslate)獨立的影象元素以及連線(join)相鄰的元素
. 尋找影象中的明顯的極大值區域或極小值區域
. 求出影象的梯度
給出圖片如下:
這裡寫圖片描述
圖片背景為白色,字母為黑色。下面將根據此圖形對膨脹腐蝕的原理進行說明。
1.膨脹
膨脹(dilate)就是求區域性最大值的操作,從數學的角度來講膨脹或者腐蝕就是將一幅二維影象或影象的一部分(稱之為A)與一個模板也就是核(稱為B)進行卷集運算的過程。
核可以是任何形狀和大小,與之前介紹的模板一樣,核有一個可定義的錨點。
. 膨脹操作是將影象A與任意形狀的核心B(通常為正方形或者圓形)進行卷集
. 核心B中可定義的錨點通稱定義為核心中心點
. 進行膨脹操作時,將核心B在影象A上進行滑動操作,將核心B覆蓋的區域的最大畫素值提取並提到核心B錨點位置的畫素。
. 上述操作將會導致影象中的亮區開始擴充套件,因為白色的畫素值要遠遠大於黑色的畫素值。經膨脹運算後其圖形如下
這裡寫圖片描述


對於膨脹運算其數學表示式如下:

這裡寫圖片描述

opencv提供了dilate函式來實現膨脹操作,其原型如下

C++: void dilate(InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )

引數解釋如下:
. InputArray src: 輸入影象,可以是Mat型別,對於影象通道數量沒有要求,但是影象深度應為CV_8U、CV_16U、CV_16s、CV_32F或CV_64F其中之一。
. OutputArray dst:

輸出影象,與原影象有相同的尺寸和型別。
. InpurArray kernel: 用於膨脹操作的kernel,當引數=Mat()即NULL時,kernel是一個錨點位於中心的3x3模板。可以通過getStructuringElement函式來制定kernel的形狀和尺寸,其函式原型如下:

Mat cv::getStructuringElement   (   int     shape,
        Size    ksize,
        Point   anchor = Point(-1,-1) 
    )   

引數解釋:
. int shape: kernel的形狀,由cv::MorphShapes指定,如下
這裡寫圖片描述


分別是矩形(MORPH_RECT)、交叉形(MORPH_CROSS)、橢圓形(MORPH_ELLIPSE)
. Size ksize: kernel的尺寸
. Point anchor = Point(-1, -1): 錨點位置

一般在呼叫erode以及dilate函式之前需要定義一個Mat型別的變數來獲得getStructuringElement()函式的返回值,對於錨點如果沒有特殊要求使用預設值即可

. Point anchor = Point(-1, -1): 錨點位置
. int iterations=1: 迭代使用膨脹的次數
. int borderType = BORDER_CONSTANT: 用於推斷影象外部畫素的某種邊界模式,其有預設值BORDER_CONSTANT,可以通過cv::BorderTypes查詢其他的方法。
. const Scalar & borderValue = morphologyDefaultBorderValue() : 邊界為常數時的邊界值,有預設值morphologyDefaultBorderValue(),一般不用進行設定,如果有特殊需要,可以檢視 createMorphologyFilter()函式得到詳細資訊。

2.腐蝕
. 腐蝕在形態學操作家族裡是膨脹操作的孿生姐妹,它是提取核心覆蓋下的畫素最小值
. 進行腐蝕操作時,將核心視窗在影象A上進行滑動,將核心B覆蓋的區域最小畫素值提取並代替錨點位置的畫素值
. 腐蝕操作將會導致影象中畫素值較低的元素進行擴充套件,造成黑色部分加粗,如下圖所示:

這裡寫圖片描述

腐蝕操作的數學表示式如下:

這裡寫圖片描述

opencv提供erode來實現腐蝕操作,其原型如下:

void cv::erode  (   InputArray      src,
        OutputArray     dst,
        InputArray      kernel,
        Point   anchor = Point(-1,-1),
        int     iterations = 1,
        int     borderType = BORDER_CONSTANT,
        const Scalar &      borderValue = morphologyDefaultBorderValue() 
    )   

引數解釋:
. InputArray src: 輸入影象可以是Mat型別,可以是任意通道影象,影象深度只能是CV_8U、CV_16U、CV_16S、CV_32F或CV_64F其中的一個。
. OutputArray dst: 輸出影象,與輸入影象尺寸型別一致。
. Input Array kernel: 用於腐蝕操作的kernel,當引數=Mat()即NULL時,kernel是一個錨點位於中心的3x3模板。可以通過getStructuringElement函式來制定kernel的形狀和尺寸,具體用法請參考對膨脹的表述
. Point anchor = Point(-1, -1): 錨點位置
. int iterations = 1: 迭代腐蝕操作次數,有預設值1
. int borderType = BORDER_CONSTANT: 用於推斷影象外部畫素的某種邊界模式,其有預設值BORDER_CONSTANT,可以通過cv::BorderTypes查詢其他的方法。
. const Scalar & borderValue = morphologyDefaultBorderValue(): 邊界為常數時的邊界值,有預設值morphologyDefaultBorderValue(),一般不用進行設定,如果有特殊需要,可以檢視 createMorphologyFilter()函式得到詳細資訊。

示例程式:

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

//定義全域性變數
Mat g_srcImage;
Mat g_dilateImage;
Mat g_erodeImage;

//定義兩個軌跡條屬性
const int typeMaxValue = 2;         //膨脹腐蝕採用圖形的型別
const int kernelSizeMaxVale = 21;   //採用kernel的尺寸最大值

int dilateTypeValue = 0;            //預設膨脹操作模板影象型別
int dilateSizeValue = 5;            //預設模板影象尺寸
int erodeTypeValue = 0;
int erodeSizeValue = 5;

//定義兩個回撥函式
void dilateFun(int, void*);         //膨脹回撥函式
void erodeFun(int, void*);          //腐蝕回撥函式

int main()
{
    g_srcImage = imread("cat.jpg");

    //判斷影象是否開啟成功
    if(g_srcImage.empty())
    {
        cout << "影象載入失敗!" << endl;
        return -1;
    }
    else
        cout << "影象載入成功!" << endl << endl;
    namedWindow("原影象", WINDOW_AUTOSIZE);
    imshow("原影象",g_srcImage);

    //定義膨脹操作視窗屬性及軌跡條性質
    namedWindow("影象膨脹", WINDOW_AUTOSIZE);
    namedWindow("影象腐蝕", WINDOW_AUTOSIZE);

    char typeName[20];
    sprintf(typeName, "模板型別 %d", typeMaxValue);

    char sizeName[20];
    sprintf(sizeName, "模板尺寸 %d", kernelSizeMaxVale);

    //建立膨脹軌跡條
    createTrackbar(typeName, "影象膨脹", &dilateTypeValue, typeMaxValue, dilateFun);
    createTrackbar(sizeName, "影象膨脹", &dilateSizeValue, kernelSizeMaxVale, dilateFun);
    dilateFun(dilateTypeValue, 0);
    dilateFun(dilateSizeValue, 0);

    //建立腐蝕軌跡條
    createTrackbar(typeName, "影象腐蝕", &erodeTypeValue, typeMaxValue, erodeFun);
    createTrackbar(sizeName, "影象腐蝕", &erodeSizeValue, kernelSizeMaxVale, erodeFun);
    erodeFun(erodeTypeValue, 0);
    erodeFun(erodeSizeValue, 0);

    waitKey(0);

    return 0;
}

//膨脹回撥函式
void dilateFun(int, void*)
{
    //確定模板影象型別
    int dilate_type;
    if(dilateTypeValue == 0)
        dilate_type = MORPH_RECT;
    else if (dilateTypeValue == 1)
        dilate_type = MORPH_CROSS;
    else
        dilate_type = MORPH_ELLIPSE;

    Mat element = getStructuringElement(dilate_type, Size(2*dilateSizeValue + 1, 2*dilateSizeValue + 1));
    dilate(g_srcImage, g_dilateImage, element);     //膨脹操作
    imshow("影象膨脹", g_dilateImage);

}

//腐蝕回撥函式
void erodeFun(int, void*)
{
    //確定模板影象型別
    int erode_type;
    if(erodeTypeValue == 0)
        erode_type = MORPH_RECT;
    else if (erodeTypeValue == 1)
        erode_type = MORPH_CROSS;
    else
        erode_type = MORPH_ELLIPSE;

    Mat element = getStructuringElement(erode_type, Size(2*erodeSizeValue + 1, 2*erodeSizeValue + 1));
    erode(g_srcImage, g_erodeImage, element);     //腐蝕操作
    imshow("影象腐蝕", g_erodeImage);
}

執行結果如下:
這裡寫圖片描述