Pythonでいろいろやってみる

Pythonを使った画像処理や機械学習などの簡単なプログラムを載せています。

月の写真から欠けの程度を定量化する

満月や三日月など満ち欠けの異なる月の写真をopencvで輪郭検出し明るい部分の面積を求めるとともに、外接円の面積を求め、その比から月のかけ具合を定量化します。

やること
  • 月の写真を読み出し二値化、領域検出し月の面積を求める
  • 検出した領域に対する外接円に面積を求める
  • 月の面積、外接円の面積、それらの比を表示する
  • 二値化画像と領域・外接円を重ね書きしたカラー画像を縦に連結しサイズを半分にして表示する
使った関数
  • cv2.imread : 画像ファイルの読み出し
  • cv2.threshold : 画像の二値化
  • cv2.findContours : 領域の検出
  • cv2.drawContours : 領域の描画
  • cv2.minEnclosingCircle : 領域に対して外接円を求める
  • cv2.circle : 円を描画
  • cv2.cvtColor : 色空間の変換
  • cv2.vconcat : 画像を縦に連結
  • cv2.resize : 画像のサイズ変更
  • cv2.imshow : 画像の表示
環境
  • windows10 home
  • Anaconda 3/ jupyter notebook 5.6.0
  • Python 3.7.0
  • OpenCV 4.0.0
準備

無料の写真素材・Pexelsから月の写真を入手しjupyter notebookファイル(***.ipynb)と同じディレクトリに保存しました。 

f:id:T_A_T:20190324173221j:plain
moon_1.jpg

f:id:T_A_T:20190324173250j:plain
moon_2.jpg

f:id:T_A_T:20190324173321j:plain
moon_3.jpg

コード

※cv2.findContoursの戻り値はこのブログで使っているOpenCV 4では2つですが、前バージョンOpenCV 3では3つのため書式が異なります

import cv2  #OpenCVのインポート

fname="moon_3.jpg" #開く画像ファイル名
threshold=45 #二値化閾値

img_color= cv2.imread(fname) #画像を読み出しオブジェクトimg_colorに代入
img_gray = cv2.imread(fname,cv2.IMREAD_GRAYSCALE) #画像をグレースケールで読み出しオブジェクトimg_grayに代入
img_blur = cv2.blur(img_gray,(11,11)) #img_grayを平均化領域11x11で平均化処理しimg_blurに代入
ret, img_binary= cv2.threshold(img_blur, threshold, 255, cv2.THRESH_BINARY) #オブジェクトimg_blurを閾値threshold(127)で二値化しimg_binaryに代入

contours, hierarchy = cv2.findContours(img_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #img_binaryを領域抽出
cnt=contours[0] #一つ目の領域をcntに代入
cv2.drawContours(img_color, cnt, -1, (0,255,0), 2) #領域cntを緑色でimg_colorに重ね書き
cnt_area = cv2.contourArea(cnt) #領域cntの面積をcnt_areaに代入

(x,y),radius = cv2.minEnclosingCircle(cnt) #領域cntに対して外接円を求め中心座標x,yと半径radiusを取得
center = (int(x),int(y)) #外接円を描画するために中心座標x,yを整数変換し中心座標centerとする
radius = int(radius) #外接円を描画するためにradiusを整数変換し半径とする
img_color = cv2.circle(img_color,center,radius,(0,0,255),2) #img_color上に外接円を赤で描画する

circle_area =radius*radius*3.14 #外接円面積を求めcircle_areaに代入
area_ratio=cnt_area/circle_area #cnt_area/circle_areをarea_ratioに代入

img_binary_bgr = cv2.cvtColor(img_binary, cv2.COLOR_GRAY2BGR)  #二値化画像img_binaryをカラー画像(BGR)に変換しimg_binary_bgrとする
img_result=cv2.vconcat([img_binary_bgr,img_color]) #img_binary_bgrとimg_colorを縦に連結しimg_resultとする
height = img_result.shape[0] #img_resultの高さをheightに
width = img_result.shape[1] #img_resultの幅をwidthに
img_result_resize = cv2.resize(img_result , (int(width*0.5), int(height*0.5))) #img_resultの高さ幅を半分にしてimg_result_resizeとする

print('月の面積 : ',cnt_area) #cnt_areaの表示
print('外接円の面積 : ',circle_area) #circle_areaの表示
print('月の面積/外接円の面積 : ',area_ratio) #cnt_area/circle_areaの表示

cv2.imshow("result",img_result_resize) #img_result_resizeの表示

cv2.waitKey(0) #キー入力待ち
cv2.destroyAllWindows() #ウインドウを閉じる  

実行結果

画像ファイル'moon_1.jpg'の場合

月の面積 : 39340.5
外接円の面積 : 40094.66
月の面積/外接円の面積 : 0.9811905126518095

f:id:T_A_T:20190324175924p:plain

画像ファイル'moon_2.jpg'の場合

月の面積 : 16615.0
外接円の面積 : 45972.740000000005
月の面積/外接円の面積 : 0.361409826779957

f:id:T_A_T:20190324175505p:plain

画像ファイル'moon_3.jpg'の場合

月の面積 : 32727.0
外接円の面積 : 45216.0
月の面積/外接円の面積 : 0.7237924628450106

f:id:T_A_T:20190324175214p:plain

以下のサイトを参考にさせていただきました

OpenCV-Python Tutorials 1 documentation >> 領域(輪郭)の特徴
Pynote >> 領域(輪郭)の特徴

ブログランキングに参加しています

にほんブログ村 IT技術ブログへ
にほんブログ村