前言
本文講述影像處理的形態學操作
一、數學形態學影像處理基本概念

1.1、數學形態學簡介
數學形態學(Mathematical morphology) 是一門建立在格論和拓撲學基礎之上的影像分析學科,是數學形態學影像處理的基本理論,其基本的運算包括: 二值腐蝕和膨脹、二值開閉運算、骨架抽取、極限腐蝕、擊中擊不中變換、形態學梯度、Top-hat變換、顆粒分析、流域變換、灰值腐蝕和膨脹、灰值開閉運算、灰值形態學梯度等,
1.2、數學形態學組成
數學形態學是由一組形態學的代數運算子組成的,它的基本運算有4個: 膨脹(或擴張)、腐蝕(或侵蝕)、開啟和閉合,它們在二值影像和灰度影像中各有特點,基于這些基本運算還可推導和組合成各種數學形態學實用演算法,用它們可以進行影像形狀和結構的分析及處理,包括影像分割、特征抽取、邊緣檢測、 影像濾波、影像增強和恢復等,數學形態學方法利用一個稱作結構元素的“探針”收集影像的資訊,當探針在影像中不斷移動時, 便可考察影像各個部分之間的相互關系,從而了解影像的結構特征,數學形態學基于探測的思想,與人的FOA(Focus Of Attention)的視覺特點有類似之處,作為探針的結構元素,可直接攜帶知識(形態、大小、甚至加入灰度和色度資訊)來探測、研究影像的結構特點,
1.3、數學形態學應用
數學形態學的基本思想及方法適用于與影像處理有關的各個方面,如基于擊中/擊不中變換的目標識別,基于流域概念的影像分割,基于腐蝕和開運算的骨架抽取及影像編碼壓縮,基于測地距離的影像重建,基于形態學濾波器的顆粒分析等,
數學形態學是一門建立在嚴格數學理論基礎上的學科,其基本思想和方法對影像處理的理論和技術產生了重大影響,事實上,數學形態學已經構成一種新的影像處理方法和理論,成為計算機數字影像處理及分形理論的一個重要研究領域,并且已經應用在多門學科的數字影像分析和處理的程序中,這門學科在計算機文字識別, 計算機顯微影像分析(如定量金相分析,顆粒分析), 醫學影像處理(例如細胞檢測、心臟的運動程序研究、脊椎骨癌影像自動數量描述),影像編碼壓縮,工業檢測(如食品檢驗和印刷電路自動檢測),材料科學, 機器人視覺,汽車運動情況監測等方面都取得了非常成功的應用,另外,數學形態學在指紋檢測、經濟地理、合成音樂和斷層X光照像等領域也有良好的應用前景,形態學方法已成為影像應用領域工程技術人員的必備工具,
二、二值影像
2.1、含義
二值影像是指每個像素點均為黑色或者白色的影像,二值影像一般用來描述字符影像,其優點是占用空間少;缺點是當表示人物,風景的影像時,二值影像只能展示其邊緣資訊,影像內部的紋理特征表現不明顯,這時候要使用紋理特征更為豐富的灰度影像,
2.2、二值影像樣例

2.3、影像二值化處理邏輯
影像的二值化處理是將影像上的點的灰度值為0或255,也就是將整個影像呈現出明顯的黑白效果,即將256個亮度等級的灰度影像通過適當的閾值選取而獲得仍然可以反映影像整體和區域特征的二值化影像,在數字影像處理中,要進行二值影像的處理與分析,首先要把灰度影像二值化,得到二值化影像,這樣子有利于在對影像做進一步處理時,影像的集合性質只與像素值為0或255的點的位置有關,不再涉及像素的多級值,使處理變得簡單,而且資料的處理和壓縮量小,為了得到理想的二值影像,一般采用封閉、連通的邊界定義不交疊的區域,所有灰度大于或等于閾值的像素被判定為屬于特定物體,其灰度值為255表示,否則這些像素點被排除在物體區域以外,灰度值為0,表示背景或者例外的物體區域,
2.4、opencv二值化處理函式
2.4.1、threshold()函式
簡介:對每個陣列元素應用一個固定級別的閾值,手動指定一個閾值,以此閾值來進行二值化處理
函式定義:
double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type );
/*
src輸入陣列(多通道,8位或32位浮點),即影像,
dst輸出陣列的大小和型別與src的通道數相同,
thresh引數閾值,
maxval用于#THRESH_BINARY和#THRESH_BINARY_INV thresholding的最大值型別,
type如果使用大津法或三角形法,則回傳計算出的閾值,
*/
2.4.2、adaptiveThreshold()函式
簡介:對陣列應用自適應閾值,通過設定最后兩個引數來調整效果
函式定義:
void adaptiveThreshold( InputArray src, OutputArray dst, double maxValue,
int adaptiveMethod, int thresholdType, int blockSize, double C );
/*
src源8位單通道影像,
dst目標映像與src大小和型別相同的param
maxValue指定給滿足條件的像素的非零值
adaptiveMethod自適應閾值演算法的使用#BORDER_REPLICATE |#BORDER_ISOLATED用于處理邊界,
thresholdType Thresholding type必須是#THRESH_BINARY或#THRESH_BINARY_INV,
blockSize用于計算閾值的像素鄰域的大小像素:3、5、7等等,
引數C常數從平均值或加權平均值中減去,正常情況下為正,但也可能為零或負,
*/
三、Opencv影像基本二值運算
3.1、腐蝕操作:erode()函式
簡介:使用指定的結構元素來腐蝕源影像,該結構元素決定取最小值的像素鄰域的形狀
定義:
void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );
/*
src:為輸入影像物件通道數可以是任意的,但深度應該是CV_8U、CV_16U、CV_16S、CV_32F或CV_64F,
dst:輸出與src大小和型別相同的影像,
kernel:用于擴展的內核結構元素;如果elemenat=Mat(),則為3 x 3矩形使用結構元素,
anchor:可以使用#getStructuringElement創建內核anchor元素中錨點的位置;默認值(-1,-1)表示錨點位于元素中心,
iterations:迭代次數應用腐蝕,
borderType:像素外推方法,不支持邊框環繞,
borderValue:如果是常量border,則為border值
*/
3.2、膨脹操作:dilate()函式
簡介:使用指定的結構元素來擴展源影像,該結構元素確定取最大值的像素鄰域的形狀
定義:
void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,const Scalar& borderValue = morphologyDefaultBorderValue() );
/*
src:為輸入影像物件通道數可以是任意的,但深度應該是CV_8U、CV_16U、CV_16S、CV_32F或CV_64F,
dst:輸出與src大小和型別相同的影像,
kernel:用于擴展的內核結構元素;如果elemenat=Mat(),則為3 x 3矩形使用結構元素,
anchor:可以使用#getStructuringElement創建內核anchor元素中錨點的位置;默認值(-1,-1)表示錨點位于元素中心,
iterations 迭代應用擴展的次數,
borderType:像素外推方法,不支持邊框環繞,
borderValue:如果是常量border,則為border值
*/
3.3、morphologyEx()函式
簡介:morphologyEx可以使用侵蝕和擴張來執行高級形態轉換基本操作,任何操作都可以在原地完成,在多通道影像的情況下,每個通道獨立處理,
定義:
void morphologyEx( InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor = Point(-1,-1),
int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );
/*
src:源影像,通道的數量可以是任意的,深度應該是CV_8U、CV_16U、CV_16S、CV_32F或CV_64F,
dst:目標映像的大小和型別與源映像相同,
Type:形態學運算的型別,請參見#MorphTypes
kernel:內核結構元素,可以使用#getStructuringElement創建它,
anchor :錨定與內核的錨定位置,負值表示錨點位于內核中心,
iterations :迭代應用腐蝕和膨脹的次數,
borderType:像素外推方法,請參見#BorderTypes,#不支持邊框自動換行,
borderValue:如果是常量Border,則為Border值,默認值具有特殊的意思,
迭代次數是應用侵蝕或膨脹操作的次數,
例如,具有兩次迭代的打開操作(#MORPH_OPEN)等價于apply
*/
3.3.1、開操作:MORPH_OPEN
先腐蝕后膨脹的操作,
作用:消除細小物體,在纖細處分離物體和平滑較大物體邊界,
3.3.2、閉操作:MORPH_CLOSE
先膨脹后腐蝕的操作,
作用:填充物體內細小空洞,連接鄰近物體和平滑邊界,
3.3.3、梯度運算:MORPH_GRADIENT
對二值影像進行這一操作可以將團塊的邊緣突出來,
作用:形態學梯度來保留物體的邊緣輪廓
3.3.4、頂帽操作:MORPH_TOPHAT
從原圖中減去開運算后的圖,得到的效果圖突出了比原型輪廓周圍的區域更明亮的區域
作用:分離比鄰近點亮一些的斑塊
3.3.5、黑帽操作:MORPH_BLACKHAT
突出了比原圖輪廓周圍的區域更暗的區域
作用:分離比鄰近點暗一些的斑塊
3.4、 getStructuringElement()函式
簡介:回傳用于形態學操作的指定大小和形狀的結構元素
作用:我們一般利用這個函式來配合前面各個函式定義中的引數kernel來使用,構造一個符合的結構元素
定義:
Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));
/*
shape:元素可以是#MorphShapes之一的形狀
ksize:結構元素的大小,
anchor:錨定元素內的錨定位置,默認值\f$(-1,-1)\f$表示錨在中間,只有十字形元素的形狀取決于錨點位置,在其他情況下,錨定只會調節結果的大小操作轉移,
*/
3.5、createTrackbar()函式
簡介:函式createTrackbar創建具有指定名稱的軌跡欄(滑塊或范圍控制元件)和范圍,將變數值指定為與軌跡欄同步的位置,并指定要在軌跡欄位置更改時呼叫的回呼函式onChange,創建的軌跡欄是顯示在指定的視窗中,
定義:
int createTrackbar(const String& trackbarname, const String& winname, int* value,
int count,TrackbarCallback onChange = 0,void* userdata = 0);
/*
trackbarname:創建的軌跡欄的名稱,
winname:將用作所創建軌跡欄父級的視窗的名稱,
value:指向整數變數的可選指標,該整數變數的值反映滑塊,創建時,滑塊位置由該變數定義,
count:滑塊的最大位置,最小位置總是0,
onChange:指向每次滑塊改變位置時要呼叫的函式的指標,這個函式的原型應該是void Foo(int,void\*);其中第一個引數是trackbar位置,第二個引數是用戶資料(見下一個引數),如果回呼是空指標,不呼叫回呼,但只更新值,
userdata:按原樣傳遞給回呼的用戶資料,它可以用來處理軌跡欄不使用全域變數的事件,
*/
3.6、形態學操作型別列舉:
enum MorphTypes{
MORPH_ERODE = 0, //!< see #erode
MORPH_DILATE = 1, //!< see #dilate
MORPH_OPEN = 2, //!< an opening operation
MORPH_CLOSE = 3, //!< a closing operation
MORPH_GRADIENT = 4, //!< a morphological gradient
MORPH_TOPHAT = 5, //!< "top hat"
MORPH_BLACKHAT = 6, //!< "black hat"
MORPH_HITMISS = 7 //!< "hit or miss"
};
四、代碼演示:
4.1、腐蝕與膨脹
代碼塊
//腐蝕與膨脹
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Mat src, dst;
int element_size = 2;
int max_size = 20;
void CallBack_Demo(int, void*) {
int s = element_size * 2 + 1;
Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
dilate(src, dst, structureElement, Point(-1, -1));//膨脹
//erode(src, dst, structureElement);//腐蝕
imshow("output_image", dst);
}
int main() {
src = imread("D:\\Myfile\\素材照片\\opencv素材照片\\4.jpg");
if (!src.data) {
cout << "could not load image..." << endl;
return 0;
}
namedWindow("input_image", WINDOW_AUTOSIZE);
imshow("input_image", src);
namedWindow("output_image", WINDOW_AUTOSIZE);
createTrackbar("Element Size :", "output_image", &element_size, max_size, CallBack_Demo);
CallBack_Demo(0, 0);
imshow("output_image", dst);
waitKey(0);
return 0;
}
運行結果:

4.2、開、閉、梯度、頂帽、黑帽等操作
代碼塊:
//形態學操作
#include <opencv2/opencv.hpp>
#include <iostream>
#include "facedetectcnn.h"
using namespace std;
using namespace cv;
int main() {
Mat src, dst;
src = imread("D:\\Myfile\\素材照片\\opencv素材照片\\11.jpg");
if (!src.data) {
cout << "could not load image..." << endl;
return 0;
}
namedWindow("input_image", WINDOW_AUTOSIZE);
imshow("input_image", src);
//Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));//結構元素
//morphologyEx(src, dst, MORPH_OPEN, kernel);//開操作,先腐蝕后膨脹
//morphologyEx(src, dst, MORPH_CLOSE, kernel);//閉操作,先膨脹后腐蝕
//梯度:膨脹減去腐蝕,基本梯度(內部梯度,方向梯度)
//morphologyEx(src, dst, MORPH_GRADIENT, kernel);
//頂帽 原影像和開操作影像
//morphologyEx(src, dst, MORPH_TOPHAT, kernel);
//黑帽 原影像和閉操作影像
//morphologyEx(src, dst, MORPH_BLACKHAT, kernel);
//提取水平和垂直線
cvtColor(src, dst, COLOR_BGR2GRAY);
Mat Bin_dst;
adaptiveThreshold(dst, Bin_dst, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);//二值化影像
Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1));
Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.rows / 16), Point(-1, -1));
Mat kernels = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
//Mat temp;
//erode(Bin_dst, temp, kernels);
//dilate(temp, dst, kernels);
morphologyEx(Bin_dst, dst, MORPH_OPEN, hline);
bitwise_not(dst, dst);
blur(dst, dst, Size(3, 3), Point(-1, -1));
namedWindow("output_image", WINDOW_AUTOSIZE);
imshow("output_image", dst);
waitKey(0);
return 0;
}
運行結果:

總結
本文講述數學形態學操作:腐蝕、膨脹、開、閉、梯度、頂帽、黑帽
參考來源
如有疑問,請留言!
如有錯誤,敬請指正!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/263808.html
標籤:其他
上一篇:Ruby 28 歲生日快樂!
下一篇:神仙思維導圖:XMind的介紹
