高級形態學變換:
開運算:
先腐蝕,再膨脹,可清除一些小東西(亮的),放大局部低亮度的區域
閉運算:
先膨脹,再腐蝕,可清除小黑點
形態學梯度:
膨脹圖與腐蝕圖之差,提取物體邊緣
頂帽:
原圖像-開運算圖,突出原圖像中比周圍亮的區域
黑帽:
閉運算圖-原圖像,突出原圖像中比周圍暗的區域
腐蝕用於分割(isolate)獨立的圖像元素,
膨脹用於連接(join)相鄰的元素
腐蝕、膨脹可用於去噪(低尺寸結構元素的腐蝕操作很容易去掉分散的椒鹽噪聲點),圖像輪廓提取、圖像分割、尋找圖像中的明顯的極大值區域或極小值區域等
腐蝕和膨脹是最基本的形態學算子
結構元素
就相當於我們在濾波中所涉及到的模板,也就是說它是一個給定像素的矩陣,這個矩陣可以是任意形狀的,
一般情況下都是正方形,圓形或者菱形的但是在結構元素中有一個中心點(也叫做anchor point)。
和模板中心一樣,處理后的結果賦值給和這個中心點對齊的像素點。處理的過程也是基本相同。
結構元素和卷積模板的區別在於,膨脹是以集合運算為基礎的,卷積是以算數運算為基礎的。
(OpenCV里面的腐蝕膨脹都是針對白色目標區域的)
膨脹:用結構元素的中心點對准當前正在遍歷的這個像素,
然后取當前結構元素所覆蓋下的原圖對應區域內的所有像素的最大值,用這個最大值替換當前像素值,給圖像中的對象邊界添加像素,使二值圖像擴大一圈
1. 用結構元素,掃描圖像的每一個像素
2. 用結構元素與其覆蓋的二值圖像做“與”操作
3. 如果都為0,結果圖像的該像素為0。否則為1
也就是在結構元素覆蓋范圍下,只要有一個像素符和結構元素像素相同,那么中心點對應點就為1,否則為0
腐蝕:用結構元素的中心點對准當前正在遍歷的這個像素,
然后取當前結構元素所覆蓋下的原圖對應區域內的所有像素的最小值,用這個最小值替換當前像素值,刪除對象邊界的某些像素,使二值圖像減小一圈
1. 用結構元素,掃描圖像的每一個像素
2. 用結構元素與其覆蓋的二值圖像做“與”操作
3. 如果都為1,結果圖像的該像素為1。否則為0
也就是查找被處理圖像中能不能找到和結構元素相同的矩陣。如果存在那么中心點所對應的點就為1,否則為0
腐蝕:刪除對象邊界的某些像素
膨脹:給圖像中的對象邊界添加像素
1 //! erodes the image (applies the local minimum operator)
2 CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel, 3 Point anchor=Point(-1,-1), int iterations=1, 4 int borderType=BORDER_CONSTANT, 5 const Scalar& borderValue=morphologyDefaultBorderValue() );
src
原圖像
dst
結果輸出圖像
kernel
結構元素
anchor
結構元素的原點
iterations
迭代次數
//! dilates the image (applies the local maximum operator)
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() );
src
原圖像
dst
結果輸出圖像
kernel
結構元素
anchor
結構元素的原點
iterations
迭代次數
//! shape of the structuring element
enum { MORPH_RECT=0, MORPH_CROSS=1, MORPH_ELLIPSE=2 };
常用的結構元素的形狀:
矩形(包括線形)、橢圓(包括圓形)及十字形。
MORPH_RECT
MORPH_ELLIPSE
MORPH_CROSS
1 //! returns structuring element of the specified shape and size
2 CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1));
獲取結構元素(內核矩陣),包括結構元素的大小及形狀:
shape
內核的形狀: MORPH_RECT、MORPH_ELLIPSE、MORPH_CROSS
ksize
內核的尺寸
anchor
錨點的位置, Point(-1,-1)錨點位於中心
例如:
//結構元素(內核矩陣)的尺寸
int g_nStructElementSize = 2;
//自定義核
1 Mat element = getStructuringElement(MORPH_RECT, //核為矩形
2 Size(2*g_nStructElementSize+1, 2*g_nStructElementSize+1), //5X5 核矩陣
3 Point(g_nStructElementSize, g_nStructElementSize )); // 中心(2,2)
十字形的element形狀唯一依賴於錨點的位置。其他情況下,錨點只是影響了形態學運算結果的偏移。
1 //! applies an advanced morphological operation to the image
2 CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst, 3 int op, InputArray kernel, 4 Point anchor=Point(-1,-1), int iterations=1, 5 int borderType=BORDER_CONSTANT, 6 const Scalar& borderValue=morphologyDefaultBorderValue() );
morphologyEx函數利用基本的膨脹和腐蝕技術,來執行更加高級形態學變換
src
輸入圖像,圖像位深應該為以下五種之一:CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。
dst
輸出圖像,需和源圖片保持一樣的尺寸和類型。
op
表示形態學運算的類型:
MORPH_OPEN – 開運算(Opening operation) MORPH_CLOSE – 閉運算(Closing operation) MORPH_GRADIENT - 形態學梯度(Morphological gradient) MORPH_TOPHAT - 頂帽(Top hat) MORPH_BLACKHAT - 黑帽(Black hat)
kernel
形態學運算的內核。為NULL,使用參考點位於中心3x3的核。一般使用函數getStructuringElement配合這個參數的使用,
kernel參數填保存getStructuringElement返回值的Mat類型變量。
anchor
錨的位置,其有默認值(-1,-1),表示錨位於中心。
iterations
迭代使用函數的次數,默認值為1。
borderType
用於推斷圖像外部像素的某種邊界模式。注意它有默認值BORDER_CONSTANT。
borderValue
當邊界為常數時的邊界值,有默認值morphologyDefaultBorderValue(),
一般我們不用去管他。需要用到它時,可以看官方文檔中的createMorphologyFilter()函數得到更詳細的解釋。
JNI:
morphology.cpp
1 #include <string>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <jni.h>
5 #include <android/log.h>
6 #include <iostream>
7 #include <fstream>
8 #include <opencv2/core/core.hpp>
9 #include <opencv2/imgproc/imgproc.hpp>
10 #include <opencv2/objdetect/objdetect.hpp>
11 #include "opencv2/features2d/features2d.hpp"
12 #include "opencv2/calib3d/calib3d.hpp"
13 #include "opencv2/imgproc/types_c.h"
14 #include "opencv2/imgproc/imgproc_c.h"
15 #include "opencv2/video/tracking.hpp"
16 #include "opencv2/video/video.hpp"
17 #include <opencv2/ml/ml.hpp>
18
19 using namespace std; 20 using namespace cv; 21
22 #define LOG_TAG "FeatureTest"
23 #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
24
25 #ifdef __cplusplus 26 extern "C" { 27 #endif
28
29 #define BYTE unsigned char
30
31 void EqualizeGray(IplImage* pImg) //直方圖均衡化
32 { 33 IplImage* pGray=cvCreateImage(cvSize(pImg->width,pImg->height),IPL_DEPTH_8U,1); 34 cvCvtColor(pImg,pGray,CV_BGR2GRAY); 35 pGray->origin=pImg->origin; 36 //cvShowImage("Gray Image",pGray);
37
38 IplImage* pEqualizedImg=cvCreateImage(cvSize(pImg->width,pImg->height),IPL_DEPTH_8U,1); 39 cvEqualizeHist(pGray, pEqualizedImg); 40 //cvShowImage("Equalize Image",pEqualizedImg);
41 cvReleaseImage(&pGray); 42 } 43
44 void cvFindContours2(Mat pImg) //顏色識別 輪廓檢測 IplImage* pImg
45 { 46 Mat pGray; 47 cvtColor(pImg, pGray, CV_BGR2GRAY); // 1、灰度圖
48
49 blur(pGray, pGray, Size(5,5)); //2、 均值濾波 50
51 //Finde vertical edges. Car plates have high density of vertical lines
52 Mat img_sobel; 53 Sobel(pGray, img_sobel, CV_8U, 1, 1, 3, 1, 0, BORDER_DEFAULT);// 3、sobel 邊緣提取 xorder=1,yorder=0,kernelsize=3
54
55 Mat img_threshold; 56 threshold(img_sobel, img_threshold, 0, 255, CV_THRESH_OTSU); // 4、二值化 img_sobel CV_THRESH_BINARY 57
58 //Morphplogic operation close:remove blank spaces and connect all regions that have a high number of edges
59 Mat element = getStructuringElement(MORPH_RECT, Size(17, 3) ); // 5、高級形態學變化,閉操作
60 morphologyEx(img_threshold, img_threshold, CV_MOP_CLOSE, element); 61
62 //Find 輪廓 of possibles plates
63 vector< vector< Point> > contours; // a vector of contours
64 findContours(img_threshold, contours, 65 CV_RETR_EXTERNAL, // 提取外部輪廓
66 CV_CHAIN_APPROX_NONE); // all pixels of each contours
67
68 LOGD(" contours.size() = %d !", contours.size()); 69 drawContours(pImg, contours, -1, Scalar(0,0,255), 2); 70
71 } 72
73 JNIEXPORT jlong JNICALL Java_com_example_morphology_MainActivity_doMorphology(JNIEnv *env, jclass clz, jlong imageGray, jint type_num) 74 { 75 Mat pImg = Mat(*(Mat*)imageGray); 76 Mat pGray; 77 cvtColor(pImg, pGray, CV_BGR2GRAY); // 1、灰度圖 78 //equalizeHist(pGray, pGray); // 2、直方圖均衡化 CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst );
79
80 blur(pGray, pGray, Size(5,5)); //2、 均值濾波 81
82 //Mat img_sobel; 83 //Sobel(pGray, img_sobel, CV_8U, 1, 1, 3, 1, 0, BORDER_DEFAULT);// 3、sobel 邊緣提取 xorder=1,yorder=1,kernelsize=3
84
85 Mat img_threshold; 86 threshold(pGray, img_threshold, 0, 255, CV_THRESH_OTSU); // 4、二值化 img_sobel CV_THRESH_BINARY_INV CV_THRESH_OTSU
87
88 Mat element = getStructuringElement(MORPH_RECT, Size(17, 3) ); // 5、高級形態學變化,閉操作
89 /*
90 enum { MORPH_ERODE=CV_MOP_ERODE, MORPH_DILATE=CV_MOP_DILATE, 91 MORPH_OPEN=CV_MOP_OPEN, 92 MORPH_CLOSE=CV_MOP_CLOSE, 93 MORPH_GRADIENT=CV_MOP_GRADIENT, 94 MORPH_TOPHAT=CV_MOP_TOPHAT, 95 MORPH_BLACKHAT=CV_MOP_BLACKHAT }; 96 */
97 if(type_num==0){ 98 morphologyEx(img_threshold, img_threshold, CV_MOP_OPEN, element); //先腐蝕,再膨脹,可清除一些小亮點,放大局部低亮度的區域
99 }else if(type_num==1){ 100 morphologyEx(img_threshold, img_threshold, CV_MOP_CLOSE, element); //先膨脹,再腐蝕,可清除小黑點
101 }else if(type_num==2){ 102 morphologyEx(img_threshold, img_threshold, CV_MOP_GRADIENT, element); //膨脹圖與腐蝕圖之差,提取物體邊緣
103 }else if(type_num==3){ 104 morphologyEx(img_threshold, img_threshold, CV_MOP_TOPHAT, element);//原圖像-開運算圖,突出原圖像中比周圍亮的區域
105 }else if(type_num==4){ 106 morphologyEx(img_threshold, img_threshold, CV_MOP_BLACKHAT, element);//閉運算圖-原圖像,突出原圖像中比周圍暗的區域
107 } 108 //type_num
109
110 Mat *hist = new Mat(img_threshold); 111 return (jlong) hist; 112 } 113
114 JNIEXPORT jlong JNICALL Java_com_example_morphology_MainActivity_doErode(JNIEnv *env, jclass clz, jlong imageGray) 115 { 116 Mat pImg = Mat(*(Mat*)imageGray); 117 Mat pGray; 118 cvtColor(pImg, pGray, CV_BGR2GRAY); // 1、灰度圖 119 //equalizeHist(pGray, pGray); // 2、直方圖均衡化 CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst );
120
121 blur(pGray, pGray, Size(5,5)); //2、 均值濾波 122
123 //Mat img_sobel; 124 //Sobel(pGray, img_sobel, CV_8U, 1, 1, 3, 1, 0, BORDER_DEFAULT);// 3、sobel 邊緣提取 xorder=1,yorder=1,kernelsize=3
125
126 Mat img_threshold; 127 threshold(pGray, img_threshold, 0, 255, CV_THRESH_OTSU); // 4、二值化 img_sobel CV_THRESH_BINARY_INV CV_THRESH_OTSU 128
129 //Mat element = getStructuringElement(MORPH_RECT, Size(17, 3) ); // 5、高級形態學變化,閉操作 130 //cv::Mat element(5,5,CV_8U,cv::Scalar(1)); 131 //Mat eroded; 132 //erode(pGray, eroded, element); 133
134 // Erode the image
135 cv::Mat eroded; 136 cv::erode(img_threshold,eroded,cv::Mat()); 137
138 Mat *hist = new Mat(eroded); 139 return (jlong) hist; 140 } 141
142 JNIEXPORT jlong JNICALL Java_com_example_morphology_MainActivity_doDilate(JNIEnv *env, jclass clz, jlong imageGray) 143 { 144 Mat pImg = Mat(*(Mat*)imageGray); 145 Mat pGray; 146 cvtColor(pImg, pGray, CV_BGR2GRAY); // 1、灰度圖 147 //equalizeHist(pGray, pGray); // 2、直方圖均衡化 CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst );
148
149 blur(pGray, pGray, Size(5,5)); //2、 均值濾波 150
151 //Mat img_sobel; 152 //Sobel(pGray, img_sobel, CV_8U, 1, 1, 3, 1, 0, BORDER_DEFAULT);// 3、sobel 邊緣提取 xorder=1,yorder=1,kernelsize=3
153
154 Mat img_threshold; 155 threshold(pGray, img_threshold, 0, 255, CV_THRESH_OTSU); // 4、二值化 img_sobel CV_THRESH_BINARY_INV CV_THRESH_OTSU 156
157 //Mat element = getStructuringElement(MORPH_RECT, Size(17, 3) ); // 5、高級形態學變化,閉操作 158 //Mat element;//(5, 5, CV_8U, Scalar(1)); 159 //element.create(5, 5, CV_8U, Scalar(0,0,255)); 160 //cv::Mat element(5,5,CV_8U,cv::Scalar(1)); 161 //cv::Mat dilate; 162 //dilate(pGray, dilate, element);
163
164 cv::Mat dilate; 165 cv::dilate(img_threshold,dilate,cv::Mat()); 166
167 Mat *hist = new Mat(dilate); 168 return (jlong) hist; 169 } 170
171 #ifdef __cplusplus 172 } 173 #endif
open:
close:
top:
gradient:
black:
erode:
dilate: