PythonのライブラリであるOpenCVを用いた中心差分による画素値ごとの微分
※この記事は自分のQiitaの記事の転載です。
Qiitaの記事はこちら
前回の記事はこちら
はじめに
前回の記事では、数値微分の中で最も精度が高いのは中心差分らしいということが分かりました。
今回は、中心差分を用いて画像の画素値ごとに中心差分を施していきOpenCV
を用いて表示させようと思います。また、matplotlib
を用いてRGBのそれぞれのヒストグラムを表示させようと思います。
前回の記事はこちら
よろしければこちらもどうぞ!!
マイページについて
X(Twitter)について
Qiitaについて
実行環境
実行環境は次の通りです。
実行環境
-
環境
Windows 10
Python 3.10.5
-
ライブラリ
OpenCV 4.8.0
matplotlib 3.6.1
画像はこちらを使います。
使った画像
画像の引用元はこちらです
画像の画素値へのアクセス方法
BGRでの画素値へのアクセス方法
上の参照元によると、
画像の画素値へのアクセスは画像の配列に画像の
座標を第1引数、画像の y 座標を第2引数、整数値を第3引数に指定するとBGRそれぞれの画素値が整数値で返される x
らしいのでその方法でRGBの画素値へアクセスします。
ちなみに、第3引数に指定する整数値は次の通りです。
第3引数の整数値の説明
整数値の説明
整数値 | 色 |
---|---|
0 | 青(B) |
1 | 緑(G) |
2 | 赤(R) |
グレースケールでの画素値へのアクセス方法
また、グレースケール画像では第1引数に画像の
座標、第2引数に画像の y 座標を指定すると画素値が整数値で返される x
らしいのでその方法でグレースケールの画素値へアクセスします。
画素値の演算方法
画像の画素値へのアクセス方法で紹介した方法で画像の画素値を取得します。
その次に、前回の記事で紹介した中心差分を求める式である下の式
の
具体例
今回は、
理由
以上のことから、画像の画素値の中心差分を用いた式は次のように書き換えられます。
ソースコード
下にソースコードを示します。おそらく実行環境で示した環境では動くはず。
ソースコード(青(B)の処理)
import cv2 #OpenCVをインポート
import matplotlib.pyplot as plt #matplotlibをpltという名前でインポート
h = 10**(-4) #中心差分のhの定義
blue_val=[] #青(B)の画素値を格納する配列の定義
green_val=[] #緑(G)の画素値を格納する配列の定義
red_val=[] #赤(R)の画素値を格納する配列の定義
img = cv2.imread('lena_std.jpg') #画像の読み込み
for i in range(img.shape[0]): #画像のy座標iを画像の高さの分imgの配列の第1引数に入力
for j in range(img.shape[1]): #画像のx座標jを画像の幅の分imgの配列の第2引数に入力
img[i,j,0] = ((img[i,j,0]+h)**2-(img[i,j,0]-h)**2)/(2*h) #画像上にあるすべての青(B)の画素値に中心差分を施す
img[i,j,1]=0 #画像上にあるすべての緑(G)の画素値を0にする
img[i,j,2]=0 #画像上にあるすべての赤(R)の画素値を0にする
blue_val.append(img[i,j,0]) #blue_valに新しくimg[i,j,0]の計算結果を代入
green_val.append(img[i,j,1]) #green_valに新しく値0を代入
red_val.append(img[i,j,2]) #red_valに新しく値0を代入
cv2.imshow("tyuusinsabun",img) #処理結果を出力
cv2.waitKey() #window closeボタンが押されるまで待機
plt.figure(tight_layout=True) #ヒストグラムが重ならないように調整
plt.subplot(221,title="Blue") #2×2のグラフ領域の左上に青(B)のヒストグラムを表示
plt.hist(blue_val,ec='black') #青(B)のヒストグラムのグラフの枠線を黒(black)に設定
plt.subplot(222,title="Green") #2×2のグラフ領域の右上に緑(G)のヒストグラムを表示
plt.hist(green_val,ec='black') #緑(G)のヒストグラムのグラフの枠線を黒(black)に設定
plt.subplot(223,title="Red") #2×2のグラフ領域の左下に赤(R)のヒストグラムを表示
plt.hist(red_val,ec='black') #赤(R)のヒストグラムのグラフの枠線を黒(black)に設定
plt.show() #全体のヒストグラムを表示
ソースコード(緑(G)の処理)
import cv2 #OpenCVをインポート
import matplotlib.pyplot as plt #matplotlibをpltという名前でインポート
h = 10**(-4) #中心差分のhの定義
blue_val=[] #青(B)の画素値を格納する配列の定義
green_val=[] #緑(G)の画素値を格納する配列の定義
red_val=[] #赤(R)の画素値を格納する配列の定義
img = cv2.imread('lena_std.jpg') #画像の読み込み
for i in range(img.shape[0]): #画像のy座標iを画像の高さの分imgの配列の第1引数に入力
for j in range(img.shape[1]): #画像のx座標jを画像の幅の分imgの配列の第2引数に入力
img[i,j,0]=0 #画像上にあるすべての青(B)の画素値を0にする
img[i,j,1] = ((img[i,j,1]+h)**2-(img[i,j,1]-h)**2)/(2*h) #画像上にあるすべての緑(G)の画素値に中心差分を施す
img[i,j,2]=0 #画像上にあるすべての赤(R)の画素値を0にする
blue_val.append(img[i,j,0]) #blue_valに新しく値0を代入
green_val.append(img[i,j,1]) #green_valに新しくimg[i,j,1]の計算結果を代入
red_val.append(img[i,j,2]) #red_valに新しく値0を代入
cv2.imshow("tyuusinsabun",img) #処理結果を出力
cv2.waitKey() #window closeボタンが押されるまで待機
plt.figure(tight_layout=True) #ヒストグラムが重ならないように調整
plt.subplot(221,title="Blue") #2×2のグラフ領域の左上に青(B)のヒストグラムを表示
plt.hist(blue_val,ec='black') #青(B)のヒストグラムのグラフの枠線を黒(black)に設定
plt.subplot(222,title="Green") #2×2のグラフ領域の右上に緑(G)のヒストグラムを表示
plt.hist(green_val,ec='black') #緑(G)のヒストグラムのグラフの枠線を黒(black)に設定
plt.subplot(223,title="Red") #2×2のグラフ領域の左下に赤(R)のヒストグラムを表示
plt.hist(red_val,ec='black') #赤(R)のヒストグラムのグラフの枠線を黒(black)に設定
plt.show() #全体のヒストグラムを表示
ソースコード(赤(R)の処理)
import cv2 #OpenCVをインポート
import matplotlib.pyplot as plt #matplotlibをpltという名前でインポート
h = 10**(-4) #中心差分のhの定義
blue_val=[] #青(B)の画素値を格納する配列の定義
green_val=[] #緑(G)の画素値を格納する配列の定義
red_val=[] #赤(R)の画素値を格納する配列の定義
img = cv2.imread('lena_std.jpg') #画像の読み込み
for i in range(img.shape[0]): #画像のy座標iを画像の高さの分imgの配列の第1引数に入力
for j in range(img.shape[1]): #画像のx座標jを画像の幅の分imgの配列の第2引数に入力
img[i,j,0]=0 #画像上にあるすべての青(B)の画素値を0にする
img[i,j,1]=0 #画像上にあるすべての緑(G)の画素値を0にする
img[i,j,2] = ((img[i,j,2]+h)**2-(img[i,j,2]-h)**2)/(2*h) #画像上にあるすべての赤(R)の画素値に中心差分を施す
blue_val.append(img[i,j,0]) #blue_valに新しく値0を代入
green_val.append(img[i,j,1]) #green_valに新しく値0を代入
red_val.append(img[i,j,2]) #red_valに新しくimg[i,j,2]の計算結果を代入
cv2.imshow("tyuusinsabun",img) #処理結果を出力
cv2.waitKey() #window closeボタンが押されるまで待機
plt.figure(tight_layout=True) #ヒストグラムが重ならないように調整
plt.subplot(221,title="Blue") #2×2のグラフ領域の左上に青(B)のヒストグラムを表示
plt.hist(blue_val,ec='black') #青(B)のヒストグラムのグラフの枠線を黒(black)に設定
plt.subplot(222,title="Green") #2×2のグラフ領域の右上に緑(G)のヒストグラムを表示
plt.hist(green_val,ec='black') #緑(G)のヒストグラムのグラフの枠線を黒(black)に設定
plt.subplot(223,title="Red") #2×2のグラフ領域の左下に赤(R)のヒストグラムを表示
plt.hist(red_val,ec='black') #赤(R)のヒストグラムのグラフの枠線を黒(black)に設定
plt.show() #全体のヒストグラムを表示
ソースコード(グレースケールの処理)
import cv2 #OpenCVをインポート
import matplotlib.pyplot as plt #matplotlibをpltという名前でインポート
h = 10**(-4) #中心差分のhの定義
grayscale_val=[] #グレースケールの画素値を格納する配列の定義
img = cv2.imread('lena_std.jpg') #画像の読み込み
img_2 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #読み込んだ画像をグレースケールに変換
for i in range(img_grayscale.shape[0]): #画像のy座標iを画像の高さの分imgの配列の第1引数に入力
for j in range(img_grayscale.shape[1]): #画像のx座標jを画像の幅の分imgの配列の第2引数に入力
img_grayscale[i,j] = ((img_grayscale[i,j]+h)**2-(img_grayscale[i,j]-h)**2)/(2*h) #画像上にあるすべてのグレースケールの画素値に中心差分を施す
grayscale_val.append(img_grayscale[i,j]) #graycale_valに新しくimg[i,j]の計算結果を代入
cv2.hconcat("tyuusinsabun",[img_2,img_grayscale]) #処理結果を出力
cv2.waitKey() #window closeボタンが押されるまで待機
plt.hist(grayscale_val,ec='black') #グレースケールのヒストグラムを表示
plt.show() #グレースケールのヒストグラムを表示
結果
まず、画像の処理結果が
青(B)の処理結果
画像
青(B)の処理結果(画像)
ヒストグラム
青(B)のヒストグラム
緑(G)の処理結果
画像
緑(G)の処理結果(画像)
ヒストグラム
緑(G)のヒストグラム
赤(R)の処理結果
画像
赤(R)の処理結果(画像)
ヒストグラム
赤(R)のヒストグラム
グレースケールの処理結果
画像
オリジナルのグレースケール画像
変換後の画像
ヒストグラム
グレースケール(オリジナル)のヒストグラム
グレースケール(変換後)のヒストグラム
となります。
特徴
画像処理で微分と聞くと微分フィルタを思い浮かべられると思いますが、微分フィルタでは隣り合う画素の差分を取ることで微分を表現しています。
この手法では、画素ごとに中心差分を取ることで画像の画素単体での微分を行うことができます。
手法についての特徴
従来 | この手法 |
---|---|
隣り合う画素の差分を取る | 画素ごとの中心差分を計算 |
ヒストグラムについての特徴
各処理結果のヒストグラムを見ると、ヒストグラムの先端が2次関数で近似できそうなところがあります!!
処理画像についての特徴
処理結果の画像を見ると、ところどころ共通な部分がありそうです!!
まとめ
今回は、Pythonのライブラリである OpenCV
を用いてRGB画像やグレースケール画像の画像上のすべての画素値を取得しました。また、それらの画素値を用いて画素値ごとの中心差分を行うことで画像の微分を実装しました。
そして、画像のRGBの画素値やグレースケールの画素値からヒストグラムを作成しました。
この記事が実際に役に立つかどうかは分かりませんが、誰かの役に立ってくれると嬉しいです。
記事を執筆する余力があれば、次回も記事を投稿する予定です。
次回の予定としては、動画から手の姿勢を推論するライブラリである MediaPipe Hands
を用いて指の先端部分をマークすることができたのでそのことに関しての記事を投稿する予定です。
Discussion
質問があれば、Qiitaのコメント欄にて!!
可能な限り答えます。