記事ディレクトリ
勾配とは、量が変化する速度のことで、数学では、勾配または特定の方向の勾配を求めるために、通常、微分と偏微分が使用されます。
デジタル画像における傾きは、x方向とy方向のそれぞれの画素値の変化速度とみなすことができますが、デジタル画像は離散型であり、画素が最小の処理単位である特性から、傾きを計算する際には、デジタル画像の勾配を計算する場合、微分を計算する必要はなく、加算と減算のみが必要です。(実際には、微分近似形式の導出です。) 以下の図に示すように:
1. ソーベル演算子
Sobel オペレーターには、水平テンプレートと垂直テンプレートである 2 セットの 3 * 3 行列が含まれており、これらは画像と畳み込まれて水平および垂直の輝度差の近似値をそれぞれ取得します。以下はG x G_xですG×和GyG_yGはいデフォルト
G x = [ + 1 0 − 1 + 2 0 − 2 + 1 0 − 1 ] ∗ A G_x= \left[ \begin{array} {cccc} +1&0&-1\\ +2 &0&-2\ \ + 1 &0&-1 \end{配列}\right]*AG×=
+1 _+2 _+1 _000− 1− 2− 1
∗あ
G y = [ + 1 + 2 + 1 0 0 0 − 1 − 2 − 1 ] ∗ A G_y= \left[ \begin{array} {cccc} +1&+2&+1\\ 0&0&0\\ -1&-2& -1 \end{配列} \right]*AGはい=
+1 _0− 1+2 _0− 2+1 _0− 1
∗A
は上式の通り、G x G_xG×与G y G_yGはい画像 A に対して水平方向と垂直方向の勾配検出を実行して得られた結果をそれぞれ示します。
2 つの二乗の合計を取得して、画像上の各点の勾配値を取得します。つまり、この点でのxxを同時に計算します。x方向とyyy方向の勾配。
G = G x 2 + G y 2 G=\sqrt{G_x^2+G_y^2}G=Gバツ2+Gy2
その点での勾配の方向は、これら 2 つの値の比のarctan arctan arctan を求めることによって決定できます。arctan比: Θ = arctan ( G y G x ) \Theta=arctan\left(\frac{G_y}{G_x}\ right )
Th=ごめんなさい_ _ _(G×Gはい)
実装コードは次のとおりです。
def SobelX(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
v = np.sum(G_x * img[i:i + 3, j:j + 3])
result[i,j] =v
if(result[i,j]<threshold):
result[i,j]=0
return result
def SobelY(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
h = np.sum(G_y * img[i:i + 3, j:j + 3])
result[i,j] =h
if(result[i,j]<threshold):
result[i,j]=0
return result
def Sobel(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
v = np.sum(G_x * img[i:i + 3, j:j + 3])
h = np.sum(G_y * img[i:i + 3, j:j + 3])
result[i,j] = np.sqrt((v ** 2) + (h ** 2))
if(result[i,j]<threshold):
result[i,j]=0
return result
テスト結果は次のとおりです。
2、シャール演算子
Scharr 演算子は、Sobel 演算子の特別な形式です。そのカーネルの形式は次のとおりです:
[ + 3 0 − 3 + 10 0 − 10 + 3 0 − 3 ] \left[ \begin{array} {cccc} +3&0&-3\\ +10 &0&-10\\ +3&0&- 3 \end{配列} \right]
+3 _+10 _+ 3000− 3−10 _− 3
[ − 3 − 10 − 3 0 0 0 + 3 + 10 + 3 ] \left[ \begin{配列} {cccc} -3&-10&-3\\ 0 &0&0\\ +3&+10&+3 \end{配列} } \右]
− 30+ 3−10 _0+10 _− 30+ 3
前述したように、Sobel オペレーターのカーネルが大きくなるほど、近似導関数が向上し、精度が高くなります。したがって、カーネルが 3×3 など比較的小さい場合、ソーベル カーネルの精度は低く、3×3 ソーベル カーネルの代わりに Scharr 演算子を使用すると精度が向上します。x方向またはy方向の重みを大きくするため、勾配角度(勾配方向)がx方向またはy方向から離れすぎず、誤差が大きくなりません。たとえば、x 方向の勾配のみを計算する場合、カーネルの中心点の x 方向の 2 つの重みが他の重みよりもはるかに大きいため、取得された勾配が x 方向に近くなり、誤差が小さくなります。ある程度まで。
def Scharr(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_x = np.array([[-3, 0, 3], [-10, 0, 10], [-3, 0, 3]])
G_y = np.array([[-3, -10, -3], [0, 0, 0], [3, 10, 3]])
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
v = np.sum(G_x * img[i:i + 3, j:j + 3])
h = np.sum(G_y * img[i:i + 3, j:j + 3])
result[i,j] = np.sqrt((v ** 2) + (h ** 2))
if(result[i,j]<threshold):
result[i,j]=0
return result
試験結果:
3. ロバーツオペレーター
[ − 1 0 0 1 ] \left[ \begin{配列} {cccc} -1&0\\ 0&1\\ \end{配列} \right][− 1001]
[ 0 − 1 1 0 ] \left[ \begin{配列} {cccc} 0&-1\\ 1 &0\\ \end{配列} \right][01− 10】
Roberts 演算子のカーネルは上図に示されており、単純な相互差分アルゴリズムであり、±45°の勾配を計算する場合に最も効果的です。
一般的な水平および垂直差分演算子と比較して、ロバーツ演算子はエッジの角点を効果的に保存することができ、計算速度が速くなります。欠点は、細部に敏感であり、ノイズにも非常に敏感であることです。
実装コード:
def Roberts(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_x = np.array([[-1, 0], [0,1]])
G_y = np.array([[0, -1], [1,0]])
result = np.zeros(img.shape)
for i in range(0, width - 1):
for j in range(0, height - 1):
v = np.sum(G_x * img[i:i + 2, j:j + 2])
h = np.sum(G_y * img[i:i + 2, j:j + 2])
result[i,j] = np.sqrt((v ** 2) + (h ** 2))
if(result[i,j]<threshold):
result[i,j]=0
return result
テスト結果は次のとおりです。
4. ラプラシアン演算子
ラプラシアンは二次導関数によって定義できます:
Δ 2 ( x , y ) = ∂ 2 f ( x , y ) ∂ x 2 + ∂ 2 f ( x , y ) ∂ y 2 \Delta^2(x, y) =\frac{\partial^2f(x,y)}{\partial x^2}+\frac{\partial^2f(x,y)}{\partial y^2}D2 (x,y )=∂ ×2∂2 f(x,y )+∂y _2∂2 f(x,y )
ただし、デジタル画像の離散化では、2 次差分は次のように表されます。
∂ 2 f ( x , y ) ∂ x 2 ≈ Δ xf ( i + 1 , j ) − Δ xf ( i , j ) = [ f ( i + 1 , j ) − f ( i , j ) ] − [ f ( i , j ) − f ( i − 1 , j ) ] = f ( i + 1 , j ) + f ( i − 1 , j ) − 2 f ( i , j ) \begin{align*} \begin{split} \frac{\partial^2f(x,y)}{\partial x^2} &\about \Delta_xf(i+1, j)- \Delta_xf(i,j) \\ &= \left[ f(i+1,j)-f(i,j) \right]- \left[f(i,j)-f(i- 1,j ) \right] \\ &=f(i+1,j)+f(i-1,j)-2f(i,j) \end{split} \end{align*}∂ ×2∂2 f(x,y )≈D×f (私+1 、j )−D×f ( i ,j )=[ f ( i+1 、j )−f ( i ,j ) ]−[ f ( i ,j )−f (私−1 、j ) ]=f (私+1 、j )+f (私−1 、j )−2 f ( i ,j )
同理可能:
∂ 2 f ( x , y ) ∂ y 2 ≈ f ( i , j + 1 ) + f ( i , j − 1 ) − 2 f ( i , j ) \frac{\partial^2f( x,y)}{\partial y^2} \およそ f(i,j+1)+f(i,j-1)-2f(i,j)∂y _2∂2 f(x,y )≈f ( i ,j+1 )+f ( i ,j−1 )−2 f ( i ,j )
したがって、ラプラシアン演算子は次のように表すことができます。
Δ 2 ( x , y ) = f ( i + 1 , j ) + f ( i − 1 , j ) + f ( i , j + 1 ) + f ( i , j − 1 ) − 4 f ( i , j ) \Delta^2(x,y)=f(i+1,j)+f(i-1,j)+f(i,j+1) +f (i,j-1)-4f(i,j)D2 (x,y )=f (私+1 、j )+f (私−1 、j )+f ( i ,j+1 )+f ( i ,j−1 )−4 f ( i ,j )
畳み込みカーネルは次のとおりです:
[ 0 1 0 1 − 4 1 0 1 0 ] \left[ \begin{array} {cccc} 0&1&0\\ 1&-4&1\\ 0&1&0 \end{array} \right]
0101− 41010
ラプラシアン法は実際には画像のエッジ強調演算子であり、画像の鮮明化によく使用されます。エッジを強調すると同時にノイズも強調するため、使用前に平滑化またはフィルタリングする必要があります。下図に示すように、関数値が急変する場合、二次微分により急変点とその両側のコントラストが強調されることがわかります。デジタル画像では画像の輪郭を強調し、画像の鮮明さを実現します。
コードは次のように実装されます。
def Laplacian(img):
temLaplacian = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
height, width = img.shape[::-1]
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
result[i][j] = np.abs(np.sum(temLaplacian * img[i:i + 3, j:j + 3]))
return result
テスト結果は次のとおりです。
全体のコードは次のとおりです。
import numpy as np
import cv2
import imgShow as iS
def SobelX(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
v = np.sum(G_x * img[i:i + 3, j:j + 3])
result[i,j] =v
if(result[i,j]<threshold):
result[i,j]=0
return result
def SobelY(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
h = np.sum(G_y * img[i:i + 3, j:j + 3])
result[i,j] =h
if(result[i,j]<threshold):
result[i,j]=0
return result
def Sobel(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
v = np.sum(G_x * img[i:i + 3, j:j + 3])
h = np.sum(G_y * img[i:i + 3, j:j + 3])
result[i,j] = np.sqrt((v ** 2) + (h ** 2))
if(result[i,j]<threshold):
result[i,j]=0
return result
def Sobel(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
v = np.sum(G_x * img[i:i + 3, j:j + 3])
h = np.sum(G_y * img[i:i + 3, j:j + 3])
result[i,j] = np.sqrt((v ** 2) + (h ** 2))
if(result[i,j]<threshold):
result[i,j]=0
return result
def Scharr(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_x = np.array([[-3, 0, 3], [-10, 0, 10], [-3, 0, 3]])
G_y = np.array([[-3, -10, -3], [0, 0, 0], [3, 10, 3]])
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
v = np.sum(G_x * img[i:i + 3, j:j + 3])
h = np.sum(G_y * img[i:i + 3, j:j + 3])
result[i,j] = np.sqrt((v ** 2) + (h ** 2))
if(result[i,j]<threshold):
result[i,j]=0
return result
def Roberts(img,threshold):
height = img.shape[0]
width = img.shape[1]
G_x = np.array([[-1, 0], [0,1]])
G_y = np.array([[0, -1], [1,0]])
result = np.zeros(img.shape)
for i in range(0, width - 1):
for j in range(0, height - 1):
v = np.sum(G_x * img[i:i + 2, j:j + 2])
h = np.sum(G_y * img[i:i + 2, j:j + 2])
result[i,j] = np.sqrt((v ** 2) + (h ** 2))
if(result[i,j]<threshold):
result[i,j]=0
return result
def Laplacian(img):
temLaplacian = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
height, width = img.shape[::-1]
result = np.zeros(img.shape)
for i in range(0, width - 2):
for j in range(0, height - 2):
result[i][j] = np.abs(np.sum(temLaplacian * img[i:i + 3, j:j + 3]))
return result
img=cv2.imread("./originImg/HorizontalAndVertical.jpg")
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
sobelImg=Sobel(img,56)
iS.showImagegray(sobelImg, img, 25, 15, 'sobelDetection', 'origin', './ProcessedImg/sobelDetection.jpg')
imageList=[]
origin_img=[img,'origin_img']
imageList.append(origin_img)
sobelx=SobelX(img,0)
sobel2=[sobelx,'Sobel_X']
imageList.append(sobel2)
sobely=SobelY(img,0)
sobel1=[sobely,'Sobel_Y']
imageList.append(sobel1)
sobelImg=Sobel(img,56)
sobel3=[sobelImg,'Sobel']
imageList.append(sobel3)
iS.showMultipleimages(imageList,25,25,'./ProcessedImg/sobelEdge.jpg')
img1=cv2.imread('./originImg/Goldhill.tif')
img1=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
LapImg=Laplacian(img1)
iS.showImagegray(LapImg, img1, 25, 15, 'LapImg', 'origin', './ProcessedImg/lapImg.jpg')
scharrImg=Scharr(img,56)
iS.showImagegray(scharrImg, img, 25, 15, 'scharrDetection', 'origin', './ProcessedImg/scharrDetection.jpg')
robertsImg=Roberts(img,56)
iS.showImagegray(robertsImg, img, 25, 15, 'robertsDetection', 'origin', './ProcessedImg/robertsDetection.jpg')
# cv2.imshow('sobely',sobely)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
描画コード:
import matplotlib.pyplot as plt
import numpy as np
import math
#图像实际大小为 W*100 * H*100 像素 ,
def showImagegray(newImg,oldImg,W,H,newImgtitle,oldImgtitle,saveImgpath):
plt.figure(figsize=(W,H))
plt.subplot(121)
plt.title(oldImgtitle,fontsize=30)
plt.axis('off')
plt.imshow(oldImg, cmap='gray')
plt.subplot(122)
plt.title(newImgtitle,fontsize=30)
plt.axis('off')
plt.imshow(newImg, cmap='gray')
# plt.tight_layout() # 调整整体空白
plt.savefig(saveImgpath)
plt.show()
def showMultipleimages(imageList,W,H,saveImgpath):
imageLength=len(imageList)
plt.rcParams['figure.figsize'] = (W,H)
col=row=math.ceil(np.sqrt(imageLength))
fig, a = plt.subplots(col, row)
m = 0
for i in range(col):
for j in range(row):
a[i][j].set_title(imageList[m][1])
a[i][j].imshow(imageList[m][0], cmap=plt.cm.gray)
m += 1
#去掉边框和刻度
for ax in a.flat:
ax.set_axis_off()
fig.tight_layout() # 调整整体空白
plt.subplots_adjust(wspace=0.2, hspace=0.2) # 调整子图间距
plt.savefig(saveImgpath)
plt.show()