? 使用數(shù)學(xué)形態(tài)學(xué)的基本運算,由計算機(jī)對圖像進(jìn)行分析,以達(dá)到所需結(jié)果的一種技術(shù)。
形態(tài)學(xué),morphology, 形態(tài)學(xué)最初是生物學(xué)中研究動物和植物結(jié)構(gòu)的一個分支,被引入圖像處理領(lǐng)域后,圖像形態(tài)學(xué)就指以形態(tài)為基礎(chǔ)對圖像進(jìn)行分析的一種方法或技術(shù)。
圖像形態(tài)學(xué)操作的基本思想 :
? 是用具有一定形態(tài)的結(jié)構(gòu)元素去度量和提取圖像中的對應(yīng)形狀以達(dá)到對圖像分析和識別的目的。
關(guān)鍵點:
? 圖像形態(tài)學(xué)操作主要是對二值圖像進(jìn)行操作的,來連接相鄰的元素或分離成獨立的元素。其次是灰度圖像,但處理彩色圖像幾乎沒有意義!
圖像形態(tài)學(xué)操作主要有:
? 膨脹、腐蝕、開運算、閉運算、梯度運算、禮帽運算、黑帽運算,擊中與擊不中變換 等等。其中膨脹和腐蝕是基本操作,后面的操作都是在膨脹和腐蝕的基礎(chǔ)上延申而來的。
圖像形態(tài)學(xué)操作有哪些應(yīng)用領(lǐng)域?
? 由于對圖像進(jìn)行形態(tài)學(xué)操作后,可以實現(xiàn)比如消除噪聲、提取邊界、填充區(qū)域、提取連通分量、凸殼、細(xì)化、粗化等; 還可以分割出獨立的圖像元素,或者圖像中相鄰的元素;求取圖像中明顯的極大值區(qū)域和極小值區(qū)域;求取圖像梯度等等, 所以在視覺檢測、圖像理解、文字識別、醫(yī)學(xué)圖像處理、圖像壓縮編碼等領(lǐng)域有非常重要的應(yīng)用。
? 在進(jìn)行各種形態(tài)學(xué)操作之前,先介紹一個至關(guān)重要的函數(shù):morphologyEx函數(shù),其利用基本的膨脹和腐蝕技術(shù),來執(zhí)行更加高級的形態(tài)學(xué)變換,如開閉運算、形態(tài)學(xué)梯度、“頂帽”、“黑帽”等等。
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() );
參數(shù)1:InputArray src? 輸入圖像,圖像數(shù)據(jù)類型必須為CV_8U, CV_16U, CV_16S, CV_32F or CV_64F中的一種。
參數(shù)2:OutputArray dst? 輸出圖像,數(shù)據(jù)類型與大小和輸入圖像一樣。
參數(shù)3:int op? 形態(tài)學(xué)處理的類型:
MORPH_ERODE = 0:腐蝕處理
MORPH_DILATE = 1:膨脹處理
MORPH_OPEN = 2:開運算處理
MORPH_CLOSE = 3:閉運算處理
MORPH_GRADIENT = 4:形態(tài)學(xué)梯度
MORPH_TOPHAT = 5:頂帽變換
MORPH_BLACKHAT = 6:黑帽變換
MORPH_HITMISS = 7 :擊中-擊不中變換
參數(shù)4:InputArray kernel? 結(jié)構(gòu)元矩陣
參數(shù)5:Point anchor = Point(-1,-1)? 結(jié)構(gòu)元中心點, 默認(rèn)值Point(-1,-1), 表示正中心
參數(shù)6:int iterations = 1? 腐蝕膨脹處理的次數(shù),默認(rèn)值為1;
如果是開運算閉運算,次數(shù)表示先腐蝕或者膨脹幾次,再膨脹腐蝕幾次,而不是開運算閉運算幾次:
如開運算且次數(shù)為2:erode ->erode ->dilate ->dilate
參數(shù)7:int borderType = BORDER_CONSTANT? 圖像邊框插值類型,默認(rèn)類型為固定值填充
BORDER_CONSTANT = 0:固定值 i 填充:iiiiii | abcdefgh | iiiiiii
BORDER_REPLICATE = 1:兩端復(fù)制:aaaaaa | abcdefgh | hhhhhhh
BORDER_REFLECT = 2:鏡像復(fù)制:fedcba | abcdefgh | hgfedcb
BORDER_WRAP = 3:去除一端的值然后復(fù)制: cdefgh | abcdefgh | abcdefg
BORDER_REFLECT_101 = 4:去除一端的值然后鏡像復(fù)制: gfedcb|abcdefgh|gfedcba
BORDER_TRANSPARENT = 5:推導(dǎo)賦值 uvwxyz | abcdefgh | ijklmno
BORDER_REFLECT101 = BORDER_REFLECT_101: same as BORDER_REFLECT_101
BORDER_DEFAULT = BORDER_REFLECT_101: same as BORDER_REFLECT_101
BORDER_ISOLATED = 16:< do not look outside of ROI
參數(shù)8:const Scalar& borderValue = morphologyDefaultBorderValue()? 文檔中說明:param borderValue Border value in case of a constant border. The default value has a special meaning.
? morphologyEx函數(shù)配合上自己定義的結(jié)構(gòu)元矩陣kernel,就可以完成各種形態(tài)學(xué)操作。
以下是原始圖、Sobel算子得到的梯度圖以及大津法OTSU閾值分割之后的圖片:
其中大津法作用之后的二值圖作為形態(tài)學(xué)操作的輸入。
一、圖像腐蝕? 顧名思義,是將物體的邊緣加以腐蝕。具體的操作是拿一個寬m高n的矩形作為kernel,對圖像中的每一個像素進(jìn)行掃描,掃描后的圖像的每個像素點和原圖的位置對應(yīng),同時和掃描時kernel的中心點對應(yīng)。用kernel遍歷原圖的所有像素,每遍歷一次就將對應(yīng)位置的像素點更改為kernel中的最小值。這樣原圖所有像素遍歷一輪后,原圖中突出的像素點就會被置為最小值,人類視覺看起來就是圖像被腐蝕了。
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, image, MORPH_ERODE, element);
imshow("【腐蝕效果圖】", image);
二、圖像膨脹? 膨脹和腐蝕是一對兒相反的操作,膨脹能對圖像的邊界進(jìn)行擴(kuò)展,就是將圖像的輪廓加以膨脹。
操作方法與腐蝕操作一樣,也是拿一個kernel,對圖像的每個像素做遍歷處理。不同之處在于生成的像素值不是所有像素中最小的值,而是大的值。這樣操作的結(jié)果會將圖像外圍的突出點連接并向外延伸。
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, image, MORPH_DILATE, element); //結(jié)果保存到自身
imshow("【膨脹效果圖】", image);
可見 指紋內(nèi)部暗點消失,邊界部分有細(xì)微的擴(kuò)張。
三、圖像開運算、閉運算、梯度運算、頂帽運算、底帽運算? 膨脹和腐蝕是圖像形態(tài)學(xué)處理的基礎(chǔ),將膨脹和腐蝕通過不同方式結(jié)合起來就可以得到圖像開運算、閉運算、梯度運算、頂帽運算、底帽運算等運算。
①開運算
開運算(opening operation),其實就是先腐蝕后膨脹過得過程,可以用來消除小物體,在纖細(xì)點出分離物體,平滑較大物體的邊界同時并不明顯改變其面積。
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, image, MORPH_OPEN, element);
imshow("【開運算效果圖】", image);
②閉運算
? 先膨脹后腐蝕的過程稱為閉運算(closing operation),?閉運算能夠排除小黑洞(黑色區(qū)域)。
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, image, MORPH_CLOSE, element);
imshow("【閉運算效果圖】", image);
③形態(tài)學(xué)梯度
? 形態(tài)學(xué)梯度(morphological gradient)為膨脹圖與腐蝕圖之差,對二值圖像進(jìn)行這一操作可以將團(tuán)塊(blob)的邊緣突出來。
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, image, MORPH_GRADIENT, element);
imshow("【形態(tài)學(xué)梯度效果圖】", image);
④頂帽運算
??頂帽運算(top hat) 又常常被譯為“禮帽”運算,為原圖像與“開運算”的結(jié)果圖之差。因為開運算帶來的結(jié)果是放大了裂縫或者局部低亮度的區(qū)域,因此,從原圖中減去開運算后的圖,得到的效果圖突出了比原型輪廓周圍的區(qū)域更明亮的區(qū)域。且這一操作和選擇的核的大小有關(guān)。頂帽運算往往用來分離比鄰近點亮一些的斑塊。當(dāng)一幅圖像具有大幅的背景的時候,而微小物品比較有規(guī)律的時候,可以用頂帽運算進(jìn)行背景提取。
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, image, MORPH_TOPHAT, element);
imshow("【頂帽運算效果圖】",image);
⑤底帽運算
??黑帽(Black Hat)運算為”閉運算“的結(jié)果圖與原圖像之差,黑帽運算后的效果圖突出了比原圖輪廓周圍的區(qū)域更暗的區(qū)域,且這一操作和選擇的核的大小相關(guān)。所以,黑帽運算用來分離比鄰近點暗一些的斑塊。
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, image, MORPH_BLACKHAT, element);
imshow("【黑帽運算效果圖】", image);
四、代碼匯總
1.頭文件,把各種操作封裝到一個類中。
#includeusing namespace cv;
class Shape_process{
public:
void Dilation(Mat image);
void Opening(Mat image);
void Closing(Mat image);
void Gradient(Mat image);
void TopHat(Mat image);
void BlackHat(Mat image);
void ErodeEX(Mat image);
Mat Sobel(Mat img);
Mat OTSU(Mat img, int arr[]);
};
2.cpp文件,對類中方法進(jìn)行定義。
#include#includeusing namespace std;
void Shape_process::Dilation(Mat image){
namedWindow("【膨脹原始圖】");
namedWindow("【膨脹效果圖】");
imshow("【膨脹原始圖】", image);
Mat module = Mat::zeros(Size(image.cols, image.rows), image.type());
//定義核
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, module, MORPH_DILATE, element);
imshow("【膨脹效果圖】", module);
waitKey(0);
}
void Shape_process::Opening(Mat image){
namedWindow("【開運算原始圖】");
namedWindow("【開運算效果圖】");
imshow("【開運算原始圖】", image);
Mat module = Mat::zeros(Size(image.cols, image.rows), image.type());
//定義核
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, module, MORPH_OPEN, element);
imshow("【開運算效果圖】", module);
waitKey(0);
}
void Shape_process::Closing(Mat image){
namedWindow("【閉運算原始圖】");
namedWindow("【閉運算效果圖】");
imshow("【閉運算原始圖】", image);
Mat module = Mat::zeros(Size(image.cols, image.rows), image.type());
//定義核
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, module, MORPH_CLOSE, element);
imshow("【閉運算效果圖】", module);
waitKey(0);
}
void Shape_process::Gradient(Mat image){
namedWindow("【形態(tài)學(xué)梯度原始圖】");
namedWindow("【形態(tài)學(xué)梯度效果圖】");
imshow("【形態(tài)學(xué)梯度原始圖】", image);
Mat module = Mat::zeros(Size(image.cols, image.rows), image.type());
//定義核
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, module, MORPH_GRADIENT, element);
imshow("【形態(tài)學(xué)梯度效果圖】", module);
waitKey(0);
}
void Shape_process::TopHat(Mat image){
namedWindow("【頂帽運算原始圖】");
namedWindow("【頂帽運算效果圖】");
imshow("【頂帽運算原始圖】", image);
Mat module = Mat::zeros(Size(image.cols, image.rows), image.type());
//定義核
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, module, MORPH_TOPHAT, element);
imshow("【頂帽運算效果圖】", module);
waitKey(0);
}
void Shape_process::BlackHat(Mat image){
namedWindow("【黑帽運算原始圖】");
namedWindow("【黑帽運算效果圖】");
imshow("【黑帽運算原始圖】", image);
Mat module = Mat::zeros(Size(image.cols, image.rows), image.type());
//定義核
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, module, MORPH_BLACKHAT, element);
imshow("【黑帽運算效果圖】", module);
waitKey(0);
}
void Shape_process::ErodeEX(Mat image){
namedWindow("【腐蝕原始圖】");
namedWindow("【腐蝕效果圖】");
imshow("【腐蝕原始圖】", image);
Mat module = Mat::zeros(Size(image.cols, image.rows), image.type());
//定義核
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
//進(jìn)行形態(tài)學(xué)操作
morphologyEx(image, module, MORPH_ERODE, element);
imshow("【腐蝕效果圖】", module);
waitKey(0);
}
Mat Shape_process::Sobel(Mat img) { // 基于Prewitt算子的閾值分割
Mat Sobel_Ojld = Mat::zeros(Size(img.cols, img.rows), img.type()); //用于計算歐幾里得距離的空白圖像
for (int row = 1; row< img.rows - 1; row++) {
for (int col = 1; col< img.cols - 1; col++) {
Sobel_Ojld.at(row, col) = saturate_cast(sqrt(pow(img.at(row - 1, col + 1) - img.at(row - 1, col - 1) + 2 * img.at(row, col + 1) - 2 * img.at(row, col - 1) + img.at(row + 1, col + 1) - img.at(row + 1, col - 1), 2) + pow(img.at(row + 1, col - 1) - img.at(row - 1, col - 1) + 2 * img.at(row + 1, col) - 2 * img.at(row - 1, col) + img.at(row + 1, col + 1) - img.at(row - 1, col + 1), 2)));
}
}
imshow("Sobel圖像(歐幾里得距離)", Sobel_Ojld);
int pixel_num[256] = { 0 }; //數(shù)組記得初始化為0,即未統(tǒng)計數(shù)量之前各個像素的個數(shù)都是0
for (int row = 0; row< img.rows; row++) {
for (int col = 0; col< img.cols; col++) {
pixel_num[Sobel_Ojld.at(row, col)] += 1; //遍歷到的像素值作為索引,次數(shù)+1
}
}
imshow("歐幾里得閾值分割", Sobel_Ojld);
Mat m1 = OTSU(Sobel_Ojld, pixel_num); // OTSU閾值分割
return m1;
}
Mat Shape_process::OTSU(Mat img, int arr[]) { // 需要輸入待處理的圖像 和 直方圖像素個數(shù)數(shù)組
int N = img.rows * img.cols; // 統(tǒng)計輸入圖像的像素個數(shù)N
double pro[256] = { 0 }; // 定義概率數(shù)組
for (int i = 0; i< 256; i++) {
pro[i] = arr[i] / N; // 得到每個像素值的概率
}
double delta = 0, w0 = 0, w1 = 0, u0 = 0, u1 = 0, v = 0; // 變量初始化為0
int T = 0, thresh = 0;
while (T<= 255) {
for (int i = 0; i<= T; i++) {
w0 += pro[i]; // C0的概率
}
w1 = 1 - w0; // C1的概率
for (int i = 0; i<= 255; i++) {
if (i<= T) {
u0 += pro[i] * i; // C0的平均值
}
else {
u1 += pro[i] * i; // C1的平均值
}
v = w0 * w1 * pow(u1 - u0, 2);
if (v >delta) {
delta = v;
thresh = T;
}
T += 1;
}
}
//由最佳像素閾值進(jìn)行二值分割
Mat OTSU = Mat::zeros(Size(img.cols, img.rows), img.type());
for (int row = 0; row< img.rows; row++) {
for (int col = 0; col< img.cols; col++) {
if (img.at(row, col) >thresh) {
OTSU.at(row, col) = 255;
}
}
}
return OTSU;
}
3.cpp文件,進(jìn)行各種形態(tài)學(xué)操作。
#include#includeusing namespace cv;
int main() {
Mat Gray = imread("C:\\Users\\LLLiePP\\Desktop\\zhiwen.png", IMREAD_GRAYSCALE);
if (Gray.empty())return -1; //判斷圖片是否引入出錯
Shape_process test;
Mat otsu = test.Sobel(Gray);
test.Dilation(otsu);
test.Opening(otsu);
test.Closing(otsu);
test.Gradient(otsu);
test.TopHat(otsu);
test.BlackHat(otsu);
test.ErodeEX(otsu);
return 0;
};
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
本文名稱:C++圖像的形態(tài)學(xué)操作-創(chuàng)新互聯(lián)
文章地址:http://aaarwkj.com/article28/cccccp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、搜索引擎優(yōu)化、商城網(wǎng)站、營銷型網(wǎng)站建設(shè)、網(wǎng)站改版、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容