【MATLAB画像処理の実践事例詳細解説(23)】——モルフォロジー処理に基づく溶接エッジ検出アルゴリズム

1. 問題の説明

現在、多くの重要な機械部品は鋼溶接構造であり、鋼溶接構造は、亀裂、溶接の欠落、溶接の不規則な外観などの欠陥が発生しやすいため、溶接の品質検査は特に重要です。溶接部のエッジは、溶接画像の最も重要な特徴です.古典的なエッジ抽出アルゴリズムは、接続されたピクセル間のグレーレベルの変化を考慮し、エッジ隣接の1次または2次導関数の変化法則を使用してエッジ抽出を実現します. 一般的に使用される一部のエッジ検出演算子では、ソーベルは閉じていない領域を形成することが多く、ラプラス演算子などの他の演算子は通常重い応答を生成します。** この論文では、解析に T 字型の溶接シーム画像を使用し、信号対ノイズ比が大きく高精度であるモルフォロジカル処理に基づく溶接エッジ検出の方法について説明します。**このアルゴリズムは、最初にメジアン フィルタリング、ホワイト バランス処理、画像正規化処理などの画像前処理技術を使用して収集した画像を補正し、次にモルフォロジー処理アルゴリズムを使用して溶接のバイナリ画像を抽出します.このアルゴリズムは効果的に溶接を削減するだけでなく、ノイズ 、および画像の有用な情報が失われないようにします。溶接イメージは次のとおりです。
ここに画像の説明を挿入
コードは次のとおりです。

clear
close all;
ps=imread('1.jpg');
subplot(121),imshow(ps)
background=imopen(ps,strel('disk',4));
% imshow(background);
subplot(122),surf(double(background(1:4:end,1:4:end))),zlim([0 256]);
set(gca,'Ydir','reverse');

2. 画像の前処理

2.1 メディアンフィルターのノイズ除去

中央値フィルタリングは、畳み込みに似た近傍操作です. 信号の中央値は、信号値の順に並べられた中央値です. 中央値フィルタリングを使用すると、パルス干渉をより適切に除去し、信号エッジを維持できます. コードは以下のように表示されます:

%% 读取焊缝图像
clc,clear,close all
obj=imread('1.jpg');
r=obj(:,:,1);g=obj(:,:,2);b=obj(:,:,3);
%% 去噪中值滤波
objn=imnoise(g,'salt & pepper',0.04);%加入少许椒盐噪声
K1=medfilt2(objn,[3,3]);%3x3模板中值滤波
K2=medfilt2(objn,[5,5]);%5x5模板中值滤波
figure('color',[1,1,1])
subplot(121),imshow(objn);xlabel('加噪图像')
subplot(122),imshow(K1);xlabel('去噪图像')

操作結果:
ここに画像の説明を挿入

2.2 ホワイトバランス処理

キャプチャされた画像に大量のノイズが含まれているため、画像内のすべてのオブジェクトの色が元の本来の色から逸脱していることが多く、ホワイト バランス方式を使用して画像の歪みを処理し、画像の色を色付きで補正します。通常の色の画像を取得するためのチップ。コードは以下のように表示されます:

clc,clear,close all
img=imread('1.jpg');
subplot(121),imshow(img),xlabel('原始图像')
img_1=img(:,:,1);
img_2=img(:,:,2);
img_3=img(:,:,3);
Y=0.299*img_1+0.587*img_2+0.114*img_3;  % 白平衡系数
[m,n]=size(Y);
k=Y(1,1);
for i=1:m
    for j=1:n
        if Y(i,j)>=k
            k=Y(i,j);
            k1=i;
            k2=j;
        end
    end
end
[m1,n1]=find(Y==k);
Rave=sum(sum(img_1));
Rave=Rave/(m*n);
Gave=sum(sum(img_2));
Gave=Gave/(m*n);
Bave=sum(sum(img_3));
Bave=Bave/(m*n);
Kave=(Rave+Gave+Bave)/3;
img__1=(Kave/Rave)*img_1;
img__2=(Kave/Gave)*img_2;
img__3=(Kave/Bave)*img_3;
imgysw=cat(3,img__1,img__2,img__3);
subplot(122),imshow(imgysw),xlabel('白平衡处理结果')

操作結果:
ここに画像の説明を挿入

3. 溶接エッジ検出

画像のエッジは、画像内の不連続または急激なグレースケール変化を持つすべてのピクセルの集まりであり、画像のほとんどの情報が集中しており、画像の最も基本的な特徴の 1 つです。エッジ検出は、画像セグメンテーション、特徴抽出、認識などの後続の画像解析分野における重要なステップであり、エンジニアリング アプリケーションで非常に重要な役割を果たします。従来の検出方法は、画像の各ピクセルの一次微分または二次微分を計算することによってエッジを決定し、画像の一次微分のピーク点または二次微分のゼロクロス点が対応します。より一般的な検出演算子は、Sobel 、Prewitt および Canny 演算子です。

3.1 ソーベル演算子のエッジ検出

ソーベル演算子は、画像内の各ピクセルの上下左右の近傍のグレー値の差に重みを付け、エッジのメカニズムに到達してエッジを検出します。S
x = [ f ( x + 1 , y − 1 ) + 2 f ( x + 1 , y ) + f ( x + 1 , y + 1 ) ] − [ f ( x − 1 , y − 1 ) + 2 f ( x − 1 , y ) + f ( x − 1 , y + 1 ) ] {S_x} = \left[ {f\left( {x + 1{\rm{,}}y{ \ rm{ - }}1} \right) + 2f\left( {x + 1{\rm{,}}y} \right) + f\left( {x + 1{\rm{,}}y + 1 } \right)} \right]{\rm{ - }}\left[ {f\left( {x{\rm{ - }}1{\rm{,}}y{\rm{ - }}1 } \right) + 2f\left( {x{\rm{ - }}1{\rm{,}}y} \right) + f\left( {x{\rm{ - }}1{\rm{ , }}y + 1} \right)} \right]S×=[ f( ×+1 , y 1 )+2F _( ×+1 , y )+( ×+1 y+1 ) ][ f( x 1 , y 1 )+2F _( x 1 , y )+( x 1 , y+1 ) ]
S y = [ f ( x − 1 , y + 1 ) + 2 f ( x , y + 1 ) + f ( x + 1 , y + 1 ) ] − [ f ( x − 1 , y − 1 ) ) + 2 f ( x , y − 1 ) + f ( x + 1 , y − 1 ) ] {S_y} = \left[ {f\left( {x{\rm{ - }}1{\rm{, }}y + 1} \right) + 2f\left( {x{\rm{,}}y + 1} \right) + f\left( {x + 1{\rm{,}}y + 1} \right)} \right]{\rm{ - }}\left[ {f\left( {x{\rm{ - }}1{\rm{,}}y{\rm{ - }}1} \右) + 2f\左( {x{\rm{,}}y{\rm{ - }}1} \右) + f\左( {x + 1{\rm{,}}y{\rm{ - }}1} \right)} \right]Sy=[ f( x 1 , y+1 )+2F _( x , y+1 )+( ×+1 y+1 ) ][ f( x 1 , y 1 )+2F _( x , y 1 )+( ×+1 , y 1 ) ]
画像の各ピクセルは、次の 2 つのカーネルで畳み込まれます。一方のカーネルは垂直方向のエッジに最大の影響を与え、もう一方のカーネルは水平方向のエッジに最大の影響を与えます。このピクセル出力値として 2 つの畳み込みが使用されます。Sobel 演算子の畳み込みテンプレートは
ここに画像の説明を挿入
次のとおりです。 Sobel 演算子のコードは次のとおりです。

%% Sobel
clc,clear,close all
I=imread('1.jpg');  % 读入图像
r=I(:,:,1);g=I(:,:,2);b=I(:,:,3);
nI=size(r);
im = single(I) / 255;

	yfilter = fspecial('sobel'); % sobel
	xfilter = yfilter';
	
	rx = imfilter(im(:,:,1), xfilter);
	gx = imfilter(im(:,:,2), xfilter);
	bx = imfilter(im(:,:,3), xfilter);
	
	ry = imfilter(im(:,:,1), yfilter);
	gy = imfilter(im(:,:,2), yfilter);
	by = imfilter(im(:,:,3), yfilter);
	
	Jx = rx.^2 + gx.^2 + bx.^2;
	Jy = ry.^2 + gy.^2 + by.^2;
	Jxy = rx.*ry + gx.*gy + bx.*by;

	D = sqrt(abs(Jx.^2 - 2*Jx.*Jy + Jy.^2 + 4*Jxy.^2)); % 2x2 matrix J'*J的第一个特征值
	e1 = (Jx + Jy + D) / 2;
	%  e2 = (Jx + Jy - D) / 2;   %第二个特征值

edge_magnitude = sqrt(e1);
edge_orientation = atan2(-Jxy, e1 - Jy);
% figure,
% subplot(121),imshow(edge_magnitude)
% subplot(122),imshow(edge_orientation)

sob=edge(edge_magnitude,'sobel',0.29);
% sob=bwareaopen(sob,100);
% figure,imshow(y),title('Sobel Edge Detection')

% 3*3 sobel
f=edge_magnitude;
sx=[-1 0 1;-2 0 2;-1 0 1]; % 卷积模板convolution mask
sy=[-1 -2 -1;0 0 0;1 2 1]; % 卷积模板convolution mask
for x=2:1:nI(1,1)-1
    for y=2:1:nI(1,2)-1
        mod=[f(x-1,y-1),2*f(x-1,y),f(x-1,y+1);
            f(x,y-1),2*f(x,y),f(x,y+1);
            f(x+1,y-1),2*f(x+1,y),f(x+1,y+1)];
        mod=double(mod);
        fsx=sx.*mod;
        fsy=sy.*mod;
        ftemp(x,y)=sqrt((sum(fsx(:)))^2+(sum(fsy(:)))^2);
    end
end
fs=im2bw(ftemp); % fs=im2uint8(ftemp);
fs=bwareaopen(fs,500);
% figure,imshow(fs);title('Sobel Edge Detection')

subplot(131),imshow(edge_magnitude),title('edge magnitude')
subplot(132),imshow(sob),title('edge magnitude extraction')
subplot(133),imshow(fs);title('sobel Edge Detection')

操作結果:
ここに画像の説明を挿入

3.2 Prewitt 演算子のエッジ検出

Prewitt オペレーターは、エッジ検出オペレーター テンプレートのサイズを 2x2 から 3x3 に拡張し、差オペレーターを計算し、方向差オペレーターをローカル平均と組み合わせて、イメージ エッジ検出に対するノイズの影響を減らします。S
x = [ f ( x − 1 , y + 1 ) + f ( x , y + 1 ) + f ( x + 1 , y + 1 ) ] − [ f ( x − 1 , y − 1 ) − f ( x , y − 1 ) − f ( x + 1 , y − 1 ) ] {S_x} = \left[ {f\left( {x{\rm{ - }}1{\rm{, } }y + 1} \right) + f\left( {x{\rm{,}}y + 1} \right) + f\left( {x + 1{\rm{,}}y + 1} \ right)} \right]{\rm{ - }}\left[ {f\left( {x{\rm{ - }}1{\rm{,}}y{\rm{ - }}1} \右 ){\rm{ - }}f\left( {x{\rm{,}}y{\rm{ - }}1} \right){\rm{ - }}f\left( {x + 1 { \rm{,}}y{\rm{ - }}1} \right)} \right]S×=[ f( x 1 , y+1 )+( x , y+1 )+( ×+1 y+1 ) ][ f( x 1 , y 1 ) f( x , y 1 ) f( ×+1 , y 1 ) ]
S y = [ f ( x + 1 , y − 1 ) + f ( x + 1 , y ) + f ( x + 1 , y + 1 ) ] − [ f ( x − 1 , y − 1 ) − f ( x − 1 , y ) − f ( x − 1 , y + 1 ) ] {S_y} = \left[ {f\left( {x + 1{\rm{,}}y{ \rm{ - }}1} \right) + f\left( {x + 1{\rm{,}}y} \right) + f\left( {x + 1{\rm{,}}y + 1} \right)} \right]{\rm{ - }}\left[ {f\left( {x{\rm{ - }}1{\rm{,}}y{\rm{ - }}1 } \right){\rm{ - }}f\left( {x{\rm{ - }}1{\rm{,}}y} \right){\rm{ - }}f\left( {x {\rm{ - }}1{\rm{,}}y + 1} \right)} \right]Sy=[ f( ×+1 , y 1 )+( ×+1 , y )+( ×+1 y+1 ) ][ f( x 1 , y 1 ) f( x 1 , y ) f( x 1 , y+1 ) ]
Prewitt 演算子の畳み込みテンプレートは次のとおりです。G ( i , j ) = ∣ P x ∣ + ∣ P y ∣ G(i,j)=|P_x|+|P_y|G ( i ,j )=P×+Py、ここで:
ここに画像の説明を挿入
Prewitt 演算子のコードは次のとおりです。

%% Prewitt
clc,clear,close all
I=imread('1.jpg');   % 读入图像
r=I(:,:,1);g=I(:,:,2);b=I(:,:,3);
nI=size(r);
im = single(I) / 255;

	yfilter = fspecial('prewitt');  % prewitt
	xfilter = yfilter';
	
	rx = imfilter(im(:,:,1), xfilter);
	gx = imfilter(im(:,:,2), xfilter);
	bx = imfilter(im(:,:,3), xfilter);
	
	ry = imfilter(im(:,:,1), yfilter);
	gy = imfilter(im(:,:,2), yfilter);
	by = imfilter(im(:,:,3), yfilter);
	
	Jx = rx.^2 + gx.^2 + bx.^2;
	Jy = ry.^2 + gy.^2 + by.^2;
	Jxy = rx.*ry + gx.*gy + bx.*by;
	
	D = sqrt(abs(Jx.^2 - 2*Jx.*Jy + Jy.^2 + 4*Jxy.^2)); % 2x2 matrix J'*J的第一个特征值
	e1 = (Jx + Jy + D) / 2;
	%  e2 = (Jx + Jy - D) / 2; %第二个特征值

edge_magnitude = sqrt(e1);
edge_orientation = atan2(-Jxy, e1 - Jy);
% figure,
% subplot(121),imshow(edge_magnitude)
% subplot(122),imshow(edge_orientation)

pre=edge(edge_magnitude,'prewitt',0.19);
% figure,imshow(y),title('Prewitt Edge Detection')

% 3*3 prewitt
f=edge_magnitude;
sx=[-1 0 1;-1 0 1;-1 0 1]; % convolution mask
sy=[1 1 1;0 0 0;-1 -1 -1]; % convolution mask
for x=2:1:nI(1,1)-1
    for y=2:1:nI(1,2)-1
        mod=[f(x-1,y-1),f(x-1,y),f(x-1,y+1);
            f(x,y-1),f(x,y),f(x,y+1);
            f(x+1,y-1),f(x+1,y),f(x+1,y+1)];
        mod=double(mod);
        fsx=sx.*mod;
        fsy=sy.*mod;
        ftemp(x,y)=sqrt((sum(fsx(:)))^2+(sum(fsy(:)))^2);
    end
end
fs=im2bw(ftemp); % fs=im2uint8(ftemp);
fs=bwareaopen(fs,1000);
% figure,imshow(fs);title('Prewitt Edge Detection');

subplot(131),imshow(edge_magnitude),title('edge magnitude')
subplot(132),imshow(pre),title('edge magnitude extraction')
subplot(133),imshow(fs);title('Prewitt Edge Detection');

操作結果:
ここに画像の説明を挿入

3.3 キャニー演算子のエッジ検出

従来の Canny アルゴリズムは、2x2 近傍の一次偏導関数の有限差分を使用して、平滑化されたデータ配列 I(x,y) の勾配の大きさと勾配の方向を計算します。定義:
P x ( i , j ) = ( I ( i , j + 1 ) − I ( i , j ) + I ( i + 1 , j + 1 ) − I ( i + 1 , j ) ) / 2 {P_x}\left( {i,j} \right) = \left( {I\left( {i,j + 1} \right) - I\left( {i,j} \right) + I\left ( {i + 1,j + 1} \right) - I\left( {i + 1,j} \right)} \right)/2P×(,j )=(私は(,j+1 )(,j )+(私は+1 j+1 )(私は+1 j ) )/2
P y ( i , j ) = ( I ( i , j ) − I ( i + 1 , j ) + I ( i , j + 1 ) − I ( i + 1 , j + 1 ) ) / 2 { P_y}\left( {i,j} \right) = \left( {I\left( {i,j} \right) - I\left( {i + 1,j} \right) + I\left( {i,j + 1} \right) - I\left( {i + 1,j + 1} \right)} \right)/2Py(,j )=(私は(,j )(私は+1 j )+(,j+1 )(私は+1 j+1 ) )/2
ピクセルの勾配振幅と勾配方向は、直角座標から極座標への座標変換式によって計算され、2 次ノルムを使用して勾配振幅が計算されます。 M ( i , j ) = P x ( i ,
j ) 2 + P y ( i , j ) 2 M\left( {i,j} \right) = \sqrt { { P_x}{ {\left( {i,j} \right)}^2} + {P_y}{ {\left( {i,j} \right)}^2}}M(,j )=P×(,j )2+Py(,j )2
勾配方向:
θ [ i , j ] = arctan ⁡ ( P y ( i , j ) / P xj ( i , j ) ) \theta \left[ {i,j} \right] = \arctan \left( { {P_y}\left( {i,j} \right)/{P_{xj}}\left( {i,j} \right)} \right)[,j ]=アークタン( Py(,j )/ Pxj _(,j ) )
キャニー演算子は画像エッジ検出に効果的.サンプルのエッジと溶接位置のノイズを検出するのは正確ですが、溶接面の品質テクスチャは比較的規則的であり、キャニー検出テクスチャはより薄いです. 、計算負荷が増加します。影響が大きくなります。コードは以下のように表示されます:

%% Canny
clc,clear,close all
im=imread('1.jpg');  % 载入图像
im=im2double(im);
r=im(:,:,1);g=im(:,:,2);b=im(:,:,3);
% 滤波器平滑系数
filter= [2 4 5 4 2;
         4 9 12 9 4;
         5 12 15 12 5;
         4 9 12 9 4;
         2 4 5 4 2];
filter=filter/115;
% N-dimensional convolution
smim= convn(im,filter); 
% imshow(smim);title('Smoothened image');

% 计算梯度
gradXfilt=[-1 0 1; % 卷积模板convolution mask
           -2 0 2; 
           -1 0 1];
gradYfilt=[1  2   1; % 卷积模板 convolution mask
           0  0   0; 
          -1  -2  -1];
GradX= convn(smim,gradXfilt);
GradY= convn(smim,gradYfilt);
absgrad=abs(GradX)+abs(GradY);
% computing angle of gradients
[a,b]=size(GradX);
theta=zeros([a b]);
for i=1:a
      for j=1:b
            if(GradX(i,j)==0)
               theta(i,j)=atan(GradY(i,j)/0.000000000001);
            else
                theta(i,j)=atan(GradY(i,j)/GradX(i,j));
            end
      end
 end
  theta=theta*(180/3.14);
  for i=1:a
      for j=1:b
            if(theta(i,j)<0)
                theta(i,j)= theta(i,j)-90;
                theta(i,j)=abs(theta(i,j));
            end
      end
 end
  for i=1:a
      for j=1:b
          if ((0<theta(i,j))&&(theta(i,j)<22.5))||((157.5<theta(i,j))&&(theta(i,j)<181))
                theta(i,j)=0;
          elseif (22.5<theta(i,j))&&(theta(i,j)<67.5)
                 theta(i,j)=45;
          elseif (67.5<theta(i,j))&&(theta(i,j)<112.5)  
                  theta(i,j)=90;
          elseif (112.5<theta(i,j))&&(theta(i,j)<157.5)
                  theta(i,j)=135;
          end
      end
  end 

%non-maximum suppression
nmx = padarray(absgrad, [1 1]);
[a,b]=size(theta);
for i=2:a-2
    for j=2:b-2
           if (theta(i,j)==135)
                 if ((nmx(i-1,j+1)>nmx(i,j))||(nmx(i+1,j-1)>nmx(i,j)))
                      nmx(i,j)=0;
                  end
           elseif (theta(i,j)==45)   
                  if ((nmx(i+1,j+1)>nmx(i,j))||(nmx(i-1,j-1)>nmx(i,j)))
                       nmx(i,j)=0;
                  end
           elseif (theta(i,j)==90)   
                  if ((nmx(i,j+1)>nmx(i,j))||(nmx(i,j-1)>nmx(i,j)))
                      nmx(i,j)=0;
                  end
           elseif (theta(i,j)==0)   
                  if ((nmx(i+1,j)>nmx(i,j))||(nmx(i-1,j)>nmx(i,j)))
                      nmx(i,j)=0;
                  end
           end
    end
end

nmx1=im2uint8(nmx); % 图像数据类型转换
tl=85;  % 阈值下限lower threshold
th=100; % 阈值上限upper threshold

% grouping edges based on threshold
[a,b]=size(nmx1);
gedge=zeros([a,b]);
for i=1:a
    for j=1:b
        if(nmx1(i,j)>th)
             gedge(i,j)=nmx1(i,j);
        elseif (tl<nmx1(i,j))&&(nmx1(i,j)<th)
             gedge(i,j)=nmx1(i,j);
        end
    end
end

[a,b]= size(gedge);
finaledge=zeros([a b]);
for i=1:a
    for j=1:b
        if (gedge(i,j)>th)
            finaledge(i,j)=gedge(i,j);
             for i2=(i-1):(i+1)
                 for j2= (j-1):(j+1)
                     if (gedge(i2,j2)>tl)&&(gedge(i2,j2)<th)
                         finaledge(i2,j2)=gedge(i,j);
                     end
                 end
              end
        end
   end
end

%clearing the border
finaledge= im2uint8(finaledge(10:end-10,10:end-10));
  
subplot(131);imshow(absgrad);title('image gradients'); 
subplot(132);imshow(nmx);title('NonMaximum Suppression');
subplot(133);imshow(finaledge(:,1:452-10));title('canny edge detection');

操作結果:
ここに画像の説明を挿入

3.4 モルフォロジー処理エッジ検出

モルフォロジー処理エッジ検出のプロセスは次のとおりです。
ここに画像の説明を挿入
実行結果は次のとおりです。
ここに画像の説明を挿入

4. 結果分析

上の図から、ソーベル オペレータが画像のエッジを検出し、検出結果がより詳細になり、背景の輪郭の干渉が大きすぎて、対象の溶接部を単一抽出できないことがわかります。; Prewitt オペレータは画像のエッジに優れた抽出効果がありますが、溶接シームは背景の影響を大きく受け、抽出効果は低く、抽出のエッジに閉じた領域はありません; Canny オペレータがベースです二重しきい値の非最大値抑制について、および得られた Sobel および Prewit 演算子と比較して、エッジ画像はより細かいテクスチャを検出しますが、閉じた領域がないため、背景エ​​ッジを除去して抽出することは依然として困難です。溶接輪郭のみ; フィルタリングは良好で、得られたバイナリ イメージは実際のターゲットに近く、溶接の特徴情報が失われないことが保証され、溶接の特徴を大きな信号でうまく抽出できます。 -対ノイズ比と高精度。


わかりました、上記はこの記事の全内容です、完全なコードは参照できます: https://download.csdn.net/download/didi_ya/87743384 ; 参考になった場合は、忘れずに気に入ってください~

おすすめ

転載: blog.csdn.net/didi_ya/article/details/130446422