腐蝕和膨脹是圖像的形態學處理中最基本的操作,之後遇見的開操作和閉操作都是腐蝕和膨脹操作的結合運算。腐蝕和膨脹的應用非常廣泛,而且效果還很好:
結構元素是形態學操作中最重要的概念,
如上圖,B為結構元素。
腐蝕操作描述為:掃描圖像的每一個像素,用結構元素與其覆蓋的二值圖像做“與”操作:如果都為1,結果圖像的該像素為1,否則為0。
膨脹操作描述為:掃描圖像的每一個像素,用結構元素與其覆蓋的二值圖像做“與”操作:如果都為0,結果圖像的該像素為0,否則為1。
以上都是關於二值圖像的形態學操作,對於灰度圖像:
腐蝕操作
其中,g(x,y)為腐蝕後的灰度圖像,f(x,y)為原灰度圖像,B為結構元素。腐蝕運算是由結構元素確定的鄰域塊中選取圖像值與結構元素值的差的最小值。
膨脹操作
其中,g(x,y)為腐蝕後的灰度圖像,f(x,y)為原灰度圖像,B為結構元素。 膨脹運算是由結構元素確定的鄰域塊中選取圖像值與結構元素值的和的最大值。
在灰度圖的形態學操作中,一般選擇“平攤”的結構元素,即結構元素B的值為0,則上面對灰度圖的形態學操作可簡化如下:
好了,這就是基本的形態學操作——腐蝕和膨脹,下面是使用OpenCV對圖像進行腐蝕和膨脹的程序,還是秉承我們一貫的原則:擱下理論,先直觀地感覺圖像處理算法的效果,實際項目需要時再深入挖掘!
/*
* FileName : eroding_and_dilating.cpp
* Author : xiahouzuoxin @163.com
* Version : v1.0
* Date : Fri 19 Sep 2014 07:42:12 PM CST
* Brief :
*
* Copyright (C) MICL,USTB
*/
#include "cv.h"
#include "highgui.h"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;
#define TYPE_MORPH_RECT (0)
#define TYPE_MORPH_CROSS (1)
#define TYPE_MORPH_ELLIPSE (2)
#define MAX_ELE_TYPE (2)
#define MAX_ELE_SIZE (20)
Mat src, erode_dst, dilate_dst;
const char *erode_wn = "eroding demo";
const char *dilate_wn = "dilating demo";
int erode_ele_type;
int dilate_ele_type;
int erode_ele_size;
int dilate_ele_size;
static void Erosion(int, void *);
static void Dilation(int, void *);
/*
* @brief
* @inputs
* @outputs
* @retval
*/
int main(int argc, char *argv[])
{
if (argc < 2) {
cout<<"Usage: ./eroding_and_dilating [file name]"<<endl;
return -1;
}
src = imread(argv[1]);
if (!src.data) {
cout<<"Read image failure."<<endl;
return -1;
}
// Windows
namedWindow(erode_wn, WINDOW_AUTOSIZE);
namedWindow(dilate_wn, WINDOW_AUTOSIZE);
// Track Bar for Erosion
createTrackbar("Element Type\n0:Rect\n1:Cross\n2:Ellipse", erode_wn,
&erode_ele_type, MAX_ELE_TYPE, Erosion); // callback @Erosion
createTrackbar("Element Size: 2n+1", erode_wn,
&erode_ele_size, MAX_ELE_SIZE, Erosion);
// Track Bar for Dilation
createTrackbar("Element Type\n0:Rect\n1:Cross\n2:Ellipse", dilate_wn,
&dilate_ele_type, MAX_ELE_TYPE, Dilation); // callback @Erosion
createTrackbar("Element Size: 2n+1", dilate_wn,
&dilate_ele_size, MAX_ELE_SIZE, Dilation);
// Default start
Erosion(0, 0);
Dilation(0, 0);
waitKey(0);
return 0;
}
/*
* @brief 腐蝕操作的回調函數
* @inputs
* @outputs
* @retval
*/
static void Erosion(int, void *)
{
int erode_type;
switch (erode_ele_type) {
case TYPE_MORPH_RECT:
erode_type = MORPH_RECT;
break;
case TYPE_MORPH_CROSS:
erode_type = MORPH_CROSS;
break;
case TYPE_MORPH_ELLIPSE:
erode_type = MORPH_ELLIPSE;
break;
default:
erode_type = MORPH_RECT;
break;
}
Mat ele = getStructuringElement(erode_type, Size(2*erode_ele_size+1, 2*erode_ele_size+1),
Point(erode_ele_size, erode_ele_size));
erode(src, erode_dst, ele);
imshow(erode_wn, erode_dst);
}
/*
* @brief 膨脹操作的回調函數
* @inputs
* @outputs
* @retval
*/
static void Dilation(int, void *)
{
int dilate_type;
switch (dilate_ele_type) {
case TYPE_MORPH_RECT:
dilate_type = MORPH_RECT;
break;
case TYPE_MORPH_CROSS:
dilate_type = MORPH_CROSS;
break;
case TYPE_MORPH_ELLIPSE:
dilate_type = MORPH_ELLIPSE;
break;
default:
dilate_type = MORPH_RECT;
break;
}
Mat ele = getStructuringElement(dilate_type, Size(2*dilate_ele_size+1, 2*dilate_ele_size+1),
Point(dilate_ele_size, dilate_ele_size));
dilate(src, dilate_dst, ele);
imshow(dilate_wn, dilate_dst);
}
膨脹和腐蝕操作的函數分別是erode
和dilate
,傳遞給他們的參數也都依次是原圖像、形態學操作後的圖像、結構元素ele。本程序中給出了3種結構元素類型,分別是
#define TYPE_MORPH_RECT (0) // 矩形
#define TYPE_MORPH_CROSS (1) // 十字交叉型
#define TYPE_MORPH_ELLIPSE (2) // 橢圓型
再通過OpenCV提供的getStructuringElement
函數創建Mat類型的結構元素。
getStructuringElement
的參數依次是結構元素類型(OpenCV中提供了宏定義MORPH_RECT、MORPH_CROSS和MORPH_ELLIPSE表示)、結構元素大小。
這裡我們首次接觸了createTrackbar
函數(聲明在highgui.hpp
中),該函數的功能是給窗口添加滑動條。其原型是:
CV_EXPORTS int createTrackbar( const string& trackbarname, const string& winname,
int* value, int count,
TrackbarCallback onChange=0,
void* userdata=0);
trackbarname
為滑動條的名稱,將會顯示在滑動條的前面,參見結果中的圖片顯示; winname
為窗口名; value
為滑動條關聯的變量,如上面程序中第一個滑動條關聯到erode_ele_type
,表示——當滑動條滑動變化時,erode_ele_type的值發生響應���變化; count
表示滑動條能滑動到的最大值; TrackbarCallback onChange
其實是這個函數的關鍵,是滑動條變化時調用的回調函數。當滑動條滑動時,value值發生變化,系統立刻調用onChange
函數,執行相關的操作,回調函數的定義形式是固定的:
void onChange(int, void *)
程序中的回調函數Erosion
和Dilation
函數的定義都遵循該形式:
static void Erosion(int, void *);
static void Dilation(int, void *);
對“黑白小豬”進行膨脹操作的變化(隨著結構元素大小的變化)如下圖:
對“黑白小豬”進行腐蝕操作的變化(隨著結構元素大小的變化)如下圖:
膨脹與腐蝕在圖像處理中具有廣泛的用途,比如提取車牌過程中,可以通過膨脹運算確定車牌的區域。如下圖為通過sobel算子提取邊緣後的車牌,
為去掉邊界,確定車牌在圖中的位置,可以通過膨脹操作,結果如下:
上圖中的紅線區域就是膨脹後能用於確定車牌的連通區域,再通過對連通區域的搜索及“車牌的矩形特性”即可確定含有車牌數字在圖片中的位置。
--------------------------------------分割線 --------------------------------------
Ubuntu Linux下安裝OpenCV2.4.1所需包 http://www.linuxidc.com/Linux/2012-08/68184.htm
Ubuntu 12.04 安裝 OpenCV2.4.2 http://www.linuxidc.com/Linux/2012-09/70158.htm
CentOS下OpenCV無法讀取視頻文件 http://www.linuxidc.com/Linux/2011-07/39295.htm
Ubuntu 12.04下安裝OpenCV 2.4.5總結 http://www.linuxidc.com/Linux/2013-06/86704.htm
Ubuntu 10.04中安裝OpenCv2.1九步曲 http://www.linuxidc.com/Linux/2010-09/28678.htm
基於QT和OpenCV的人臉識別系統 http://www.linuxidc.com/Linux/2011-11/47806.htm
--------------------------------------分割線 --------------------------------------
OpenCV的詳細介紹:請點這裡
OpenCV的下載地址:請點這裡