Opencv-C++ メモ (5): opencv-morphology

1. 形態学的操作と構造

モルフォロジー演算は、数学的形態学の集合論手法に基づいて二値画像に対して
開発された画像処理手法です。数学的形態学は岩石学における岩石構造の定量的記述に端を発し、近年ではデジタル画像処理やマシンビジョンの分野で広く利用され、独自のデジタル画像解析手法と理論を形成しています。

構造要素は単純にピクセルの組み合わせとして定義でき、原点 (アンカー ポイントとも呼ばれる) は対応するピクセル上に定義されます。形態学的フィルタの適用プロセスは、この構造要素を使用して画像内の各ピクセルの演算プロセスを検出することです。ある画素を構造要素のアンカーポイントとして設定した後、構造要素と画像との重なり部分に設定された画素が特定のモルフォロジー演算の適用対象となる。構造要素は原理的にはどのような形状でも構いませんが、通常は中心点を原点とした正方形、円、ひし形などの単純な形状です。

膨張と腐食の違い: 膨張は交差がある限りトリガーされますが、腐食はリセット ポイントと前景ピクセルの領域が完全に重なる場合に保持される必要があります。
ここに画像の説明を挿入

2. 腐食拡大操作

エロージョンの定義で
は、3×3 カーネルを使用してバイナリ イメージをスキャンします。カーネルと前景のピクセルが完全に重複する領域がある場合にのみ、バイナリ イメージ内の対応するコンボリューション カーネルの中心のピクセルが保持されます。その他の場合は、中心位置のピクセルは 0 に設定されます。

     拓展:卷积核可以为任意形状,且重置点可以选用卷积核中的任意位置

ここに画像の説明を挿入
ここに画像の説明を挿入

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() 
                    )	

つまり、B による X の侵食によって生成されるバイナリ イメージ E は、次の条件を満たす点 (x, y) の集合です。 B の原点を点 (x, y) に変換すると、B は次のようになります。 X真ん中に完全に含まれています。

もう 1 つの理解は、現在のピクセルを、定義されたピクセル セット内の最小ピクセル値に置き換えることです。入力バイナリ画像には黒 (0) と白 (255) のピクセルしか含まれていないため、構造要素で覆われた画像領域に黒のピクセルがある場合、アンカー ポイントが配置されているピクセル (x, y) が次のピクセルに置き換えられます。黒 0、それ以外の場合は白 255 に置き換えます。また、オブジェクトの境界には通常黒いピクセルがあるため、侵食は境界を縮小することと同じです。

腐食: 腐食は、境界点を除去し、境界を内側に縮小するプロセスです。小さくて意味のないオブジェクトを削除するために使用できます

// Read input image  
    cv::Mat image= cv::imread("binary.bmp");  
    if (!image.data)  
        return 0;   
// Display the image  
    cv::namedWindow("Image");  
    cv::imshow("Image",image);  
// Erode the image  
    cv::Mat eroded;  
    cv::erode(image,eroded,cv::Mat());//cv::Mat()为空矩阵,此时采用默认3*3正方形结构元素  
// Display the eroded image  
    cv::namedWindow("Eroded Image");  
    cv::imshow("Eroded Image",eroded);  
// Erode the image with a larger s.e.定义更大的结构元素  
    cv::Mat element(7,7,CV_8U,cv::Scalar(1));  
 // Display the eroded image by large s.e.  
    cv::erode(image,eroded,element);  
    cv::namedWindow("Eroded Image (7x7)");  
    cv::imshow("Eroded Image (7x7)",eroded);  
// Erode the image 3 times.腐蚀3次  
    cv::erode(image,eroded,cv::Mat(),cv::Point(-1,-1),3);//cv::Point(-1,-1)表示原点是矩阵的中心点  
// Display the eroded image  
    cv::namedWindow("Eroded Image (3 times)");  
    cv::imshow("Eroded Image (3 times)",eroded);  
    cv::waitKey(0);  

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

3. 拡張

拡張の定義で
は、3×3 カーネルを使用してバイナリ画像をスキャンします。カーネルが画像の前景ピクセル (値 1 を持つピクセル) と交差するとき、画像内の対応するコンボリューション カーネルの中心のピクセル値が、バイナリ イメージは 1 に設定されます。

    拓展:卷积核可以为任意形状(除1×1),且重置点可以选用卷积核中的任意位置,有‘交集‘就对重置点位置像素置1。

ここに画像の説明を挿入空所

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

ここに画像の説明を挿入

X に対する B の膨張によって生成されるバイナリ イメージ D は、次の条件を満たす点 (x, y) のセットです。B の原点が点 (x, y) に変換される場合、X との交点は非になります。 -空。

もう 1 つの理解は、拡張は侵食の逆操作であり、現在のピクセル (原点が (x, y) に位置する) を定義されたピクセル セット内の最大ピクセル値に置き換えることです。入力二値画像には黒(0)と白(255)のピクセルしか含まれていないため、画像内に構造要素で覆われた白(オブジェクト)がある場合、構造要素の原点の位置(x、y)の値が要素は白の 255 に置き換えられます。

膨張の役割: つまり、膨張とは、オブジェクトと接触しているすべての背景点をオブジェクトにマージし、境界を外側に拡張するプロセスです。オブジェクトの穴を埋めるために使用できます

// Dilate the image  
    cv::Mat dilated;  
    cv::dilate(image,dilated,cv::Mat());  
// Display the dialted image  
    cv::namedWindow("Dilated Image");  
    cv::imshow("Dilated Image",dilated); 

ここに画像の説明を挿入

4. カスタム構造要素

通常のルール構造要素の使用に加えて、構造要素をカスタマイズすることもできます。以下では、Mat タイプのコンストラクターを使用して、3×3 の十字型の構造要素を作成します。

// 创建自定义结构元素  
unsigned char m[9] = {
    
      
        0,1,0,  
        1,1,1,  
        0,1,0     
    };  
cv::Mat element1(3,3,CV_8U,m); //创建自定义矩阵element1  
//显示该结构元素  
int nr = element1.rows;  
int nl = element1.cols;  
for(int j = 0;j<nr;j++)  
{
    
      
    char *data = element1.ptr<char>(j);  
    for(int i = 0; i<nl; i++)  
    {
    
      
        int value = data[i];  
        cout<<value<<" ";  
}  
    cout<<endl;  
}  
 // Display the eroded image by large s.e.  
    cv::erode(image,eroded,element1);  
    cv::namedWindow("Eroded Image (user define)");  
    cv::imshow("Eroded Image (user define)",eroded);  

ここに画像の説明を挿入

Mat_template クラスを使用して、5×5 サイズの十字、ひし形、正方形、および X 形の構造要素をカスタマイズします。

   cv::Mat_<uchar> cross(5,5);  
    cv::Mat_<uchar> diamond(5,5);  
    cv::Mat_<uchar> x(5,5);  
    cv::Mat_<uchar> square(5,5);  
  
     // Creating the cross-shaped structuring element  
    cross <<  
          0, 0, 1, 0, 0,  
          0, 0, 1, 0, 0,  
          1, 1, 1, 1, 1,  
          0, 0, 1, 0, 0,  
          0, 0, 1, 0, 0;  
            
     // Creating the diamond-shaped structuring element  
     diamond <<  
          0, 0, 1, 0, 0,  
          0, 1, 1, 1, 0,  
          1, 1, 1, 1, 1,  
          0, 1, 1, 1, 0,  
          0, 0, 1, 0, 0;  
            
      // Creating the x-shaped structuring element  
      x <<  
          1, 0, 0, 0, 1,  
          0, 1, 0, 1, 0,  
          0, 0, 1, 0, 0,  
          0, 1, 0, 1, 0,  
          1, 0, 0, 0, 1;  
  
      // Creating the square-shaped structuring element  
      square <<  
          1, 1, 1, 1, 1,  
          1, 1, 1, 1, 1,  
          1, 1, 1, 1, 1,  
          1, 1, 1, 1, 1,  
          1, 1, 1, 1, 1;  
<span style="white-space:pre">    </span> //display x-shaped structuring element  
     cout<<endl<<"x-shaped structuring element"<<endl<<endl;  
     int xnr = x.rows;  
     int xnl = x.cols;  
     for(int j = 0;j<nr;j++)  
     {
    
      
        char *data = x.ptr<char>(j);  
        for(int i = 0; i<nl; i++)  
        {
    
      
            int value = data[i];  
            cout<<value<<" ";  
        }  
        cout<<endl;  
     }  

5. 開閉操作

void cv::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() 
                            )
                            对于输入参数op(形态学运算类型)有以下几种参数可以设置:

MORPH_ERODE(腐蚀)
MORPH_DILATE(膨胀)
MORPH_OPEN(开运算)
MORPH_CLOSE(闭运算)
MORPH_GRADIENT(形态学梯度,即膨胀图减腐蚀图)
MORPH_TOPHAT(顶帽运算)
MORPH_BLACKHAT(底帽运算)
MORPH_HITMISS(击中与击不中)

void QuickDemo::open_close(Mat& image)
{ マット グレー; cvtColor(画像、グレー、COLOR_BGR2GRAY); マットバイナリ。しきい値(グレー、バイナリ、0、255、THRESH_BINARY_INV | THRESH_OTSU); namedWindow(“THRESH_OTSU”, WINDOW_FREERATIO); imshow(“THRESH_OTSU”, バイナリ);





Mat dst1, dst2;
//定义核
int kernel_size = 5;
Mat kernel = getStructuringElement(MORPH_RECT, Size(kernel_size, kernel_size), Point(-1, -1));
//开
morphologyEx(binary, dst1, MORPH_OPEN, kernel, Point(-1, -1), 1, 0);
namedWindow("MORPH_OPEN", WINDOW_FREERATIO);
imshow("MORPH_OPEN", dst1);

//闭、
morphologyEx(binary, dst2, MORPH_CLOSE, kernel, Point(-1, -1), 1, 0);
namedWindow("MORPH_CLOSE", WINDOW_FREERATIO);
imshow("MORPH_CLOSE", dst2);

}

ここに画像の説明を挿入

オープン操作

腐食第一膨張
ここに画像の説明を挿入
ここに画像の説明を挿入

オープン操作機能:
背景の小さなオブジェクトを削除したり、オブジェクトを薄い点で分離したり、大きなオブジェクトの領域を大きく変えることなく境界を滑らかにしたりするために使用されます。構造要素を収容するには小さすぎるオブジェクトはすべて削除されます。

void erode_dilate(Mat& image)
{
    
    
	Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);
	Mat binary;
	threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
	namedWindow("THRESH_OTSU", WINDOW_FREERATIO);
	imshow("THRESH_OTSU", binary);
 
	Mat dst1, dst2;
	//定义核
	int kernel_size = 5;
	Mat kernel = getStructuringElement(MORPH_RECT, Size(kernel_size, kernel_size), Point(-1, -1));
	//腐蚀
	erode(binary, dst1, kernel);
	namedWindow("erode", WINDOW_FREERATIO);
	imshow("erode", dst1);
 
	//膨胀
	dilate(binary, dst2, kernel);
	namedWindow("dilate", WINDOW_FREERATIO);
	imshow("dilate", dst2);
}

ここに画像の説明を挿入

cv::Mat element5(5,5,CV_8U,cv::Scalar(1));//5*5正方形,8位uchar型,全1结构元素  
cv::Mat opened;  
cv::morphologyEx(image, opened,cv::MORPH_OPEN,element5);  
// Display the opened image  
cv::namedWindow("Opened Image");  
cv::imshow("Opened Image",opened);  
cv::waitKey(0); 

ここに画像の説明を挿入

閉じる操作

膨張とその後の腐食
ここに画像の説明を挿入
ここに画像の説明を挿入

cv::Mat element5(5,5,CV_8U,cv::Scalar(1));//5*5正方形,8位uchar型,全1结构元素  
cv::Mat closed;  
cv::morphologyEx(image, closed,cv::MORPH_CLOSE,element5);//高级形态学运算函数  
// Display the opened image  
cv::namedWindow("Closed Image");  
cv::imshow("Closed Image",closed);  
cv::waitKey(0); 

ここに画像の説明を挿入

6. 形態学的勾配

注: エッジ抽出アプリケーションでは、グラデーション エッジの後、より良いエッジ イメージを取得するために 2 値化されます。
基本的なグラデーション: 膨張グラフ - エロージョン グラフ

内部グラデーション: オリジナル画像 - エロージョン画像

外側の勾配: 膨張画像 - 元の画像
役割:
基本的な勾配 (画像の膨張と収縮操作の違い)
内側の勾配 (入力画像と収縮の差)
外側の勾配 (膨張と入力画像の差)
ここで、opencv は基本的な勾配を直接実現することしかできません。 API: morphologyEx を使用する場合は、MORPH_GRADIENT メソッドを呼び出すだけです。
内部グラデーションと外部グラデーション用の直接的な API はなく、通常は既存の API を介して間接的に実装されます。

void QuickDemo::shape_gradient(Mat& image)
{
    
    
	Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);
 
	Mat g1, g2, g3;
	Mat dst1, dst2;
	int kernel_size = 7;
	Mat kernel = getStructuringElement(MORPH_RECT, Size(kernel_size, kernel_size), Point(-1, -1));
	
	//基本梯度
	morphologyEx(gray, g1, MORPH_GRADIENT, kernel, Point(-1, -1), 1, 0);
 
	//膨胀
	morphologyEx(gray, dst1, MORPH_DILATE, kernel, Point(-1, -1), 1, 0);
 
	//腐蚀
	morphologyEx(gray, dst2, MORPH_ERODE, kernel, Point(-1, -1), 1, 0);
 
	//外梯度
	subtract(dst1, gray, g2);
	//内梯度
	subtract(gray, dst2, g3);
 
	namedWindow("基本梯度", WINDOW_FREERATIO);
	imshow("基本梯度", g1);
 
	namedWindow("外梯度", WINDOW_FREERATIO);
	imshow("外梯度", g2);
 
	namedWindow("内梯度", WINDOW_FREERATIO);
	imshow("内梯度", g3);
 
	//最后再进行二值化,获取更好的边缘图像,选用基本梯度示例
	Mat binary;
	threshold(g1, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
	namedWindow("二值化", WINDOW_FREERATIO);
	imshow("二值化", binary);
}

ここに画像の説明を挿入

7. その他の形態 - シルクハット、ブラックハット、行き当たりばったり

シルクハット: 元の画像 - オープニング操作後の画像
1️⃣: オープニング操作によって削除された領域を取得します (オープニング操作の効果を確認します)
2️⃣: 不均一な照明の影響を修正します (暗い背景上の明るいオブジェクトの場合、光の差を除去します)

ブラック ハット: クローズ操作後の画像 - 元の画像
1️⃣: クローズ操作はノイズ除去のプロセスであるため、ブラック ハット操作では基本的にノイズが保持されます。
2️⃣: 不均一な照明の影響を修正します (明るい (白) 背景上の暗いオブジェクトの場合)
注: トップ ハットとブラック ハットの操作は、画像の細部を取得するために使用されます。

ヒットアンドミス: 特定のテンプレートでは、入力画像にテンプレートとまったく同じブロックがある場合にのみ、入力画像のヒット領域が保存されます。
ヒットアンドミス変換は、特定の形状がどこにあるかを検出するために使用される形態学の基本的なツールです。その原理は侵食を使用することです。画像 A 上で B 形状のターゲットを見つけたい場合、しなければならないことは次のとおりです。

まず、B より大きい構造要素 B1 を作成します。B1 を使用してイメージ A を腐食し、イメージは A_B1 であると仮定します。次に、B から B1 を減算して構造要素 B2 (B2-
B) を取得します。B2 を使用してイメージ化します。 A_B2 の補数に対して腐食が実行され、画像が A_B2 であると仮定され、
A_B1 と A_B2 が交差し、得られる結果は B の位置です。

ここに画像の説明を挿入


void QuickDemo::other_method(Mat& image)
{
    
    
	Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);
	Mat binary;
	threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
	namedWindow("二值化", WINDOW_FREERATIO);
	imshow("二值化", binary);
 
	Mat dst1, dst2, dst3;
	int kernel_size = 5;
	Mat kernel_1 = getStructuringElement(MORPH_RECT, Size(kernel_size, kernel_size), Point(-1, -1));
 
	//顶帽
	morphologyEx(binary, dst1, MORPH_TOPHAT, kernel_1, Point(-1, -1), 1, 0);
	namedWindow("顶帽", WINDOW_FREERATIO);
	imshow("顶帽", dst1);
	//黑帽
	morphologyEx(binary, dst2, MORPH_BLACKHAT, kernel_1, Point(-1, -1), 1, 0);
	namedWindow("黑帽", WINDOW_FREERATIO);
	imshow("黑帽", dst2);
 
	//击中击不中
	Mat kernel_2 = getStructuringElement(MORPH_CROSS, Size(kernel_size, kernel_size), Point(-1, -1));
	morphologyEx(binary, dst3, MORPH_HITMISS, kernel_2, Point(-1, -1), 1, 0);
	namedWindow("击中击不中", WINDOW_FREERATIO);
	imshow("击中击不中", dst3);
}

ここに画像の説明を挿入

Mat src = imread("D:/opencv练习图片/击中与击不中.png");
    imshow("原图", src);
    // 二值图像
    Mat gray, binary, hitImg;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    //高斯滤波
    Mat gauss;
    GaussianBlur(gray, gauss, Size(5, 5), 0, 0);
    //二值化
    threshold(gauss, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
    imshow("binary", binary);
    // 定义结构元素
    Mat se = getStructuringElement(MORPH_CROSS, Size(11, 11), Point(-1, -1));
    // 击中击不中
    morphologyEx(binary, hitImg, MORPH_HITMISS, se);
    imshow("击中击不中", hitImg);
    //膨胀一下
    Mat openImg;
    Mat kern2 = getStructuringElement(MORPH_RECT, Size(3, 3));
    morphologyEx(hitImg, openImg, MORPH_OPEN, kern2, Point(-1, -1), 2);
    imshow("dilate", openImg);
    //寻找轮廓
    vector<vector<Point>>contours;
    vector<Vec4i>hie;
    findContours(openImg, contours, hie, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
    for (size_t i = 0; i < contours.size(); i++)
    {
    
    
        double area = contourArea(contours[i]);
        if (area < 20.0)continue;
        Rect rect = boundingRect(contours[i]);
        rectangle(src, rect, Scalar(0, 0, 255), 1, 8);
 
    }
    // 显示
    imshow("结果", src);

ここに画像の説明を挿入

8. カーネル機能

cv2.getStructuringElement() を使用して、さまざまな構造のカーネルを生成します

インポートCV2

長方形のカーネル

kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 10)
get_show(kernel1)
ここに画像の説明を挿入

十字核

kernel2 = cv2.getStructuringElement(cv2.MORPH_CROSS, (10, 10))
ここに画像の説明を挿入

楕円核

kernel3 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1000, 1000))
ここに画像の説明を挿入

参考:https://blog.csdn.net/qq_33287871/article/details/112761328?ops_request_misc=&request_id=&biz_id=102&utm_term=opencv%E5%BD%A2%E6%80%81%E5%AD%A6%E5%A4%84%E7%90%86c++&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-4-112761328.142v88control_2,239v2insert_chatgpt&spm=1018.2226.3001.4187

おすすめ

転載: blog.csdn.net/jiyanghao19/article/details/131240894