実現したいこと
python初心者です。
ポケモンの画像の複雑さを数値化したいと思っています。
丸みを帯びていれば数値が小さく、凹凸が多いポケモンは数値が大きくなるようにしたいです。
前提
現在輪郭を抽出し、複雑さを数値化するコードを作成してみましたが、
丸みを帯びているポケモンの方が、凹凸の多いポケモンよりも数値が高くなってしまいました。
該当のソースコード
以下のコードが現在作ってみたコードです。
python
1import cv2 2import numpy as np 3from scipy.spatial import ConvexHull 4 5# 画像の読み込み 6image = cv2.imread("pokemon_img/0039.png") 7 8# グレースケールに変換 9gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 10 11# 白黒反転 12gray = 255 - gray 13 14#パラメータ調整 15blur = cv2.GaussianBlur(gray, (5, 5), 0) 16 17 18# 2値化 19#ret, thresh = cv2.threshold(gray, 120, 255, cv2.THRESH_BINARY) 20 21#パラーメータ調整 22ret, thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) 23 24 25# 輪郭の抽出 26contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 27 28# 輪郭の複雑さを数値化 29complexity = 0 30for contour in contours: 31 # 輪郭の凸包を計算 32 hull = ConvexHull(contour.reshape(-1, 2)) 33 34 # 凸包の頂点数を取得 35 vertex_count = hull.vertices.shape[0] 36 37 # 複雑さを加算 38 complexity += vertex_count 39 40print("輪郭の複雑さ:", complexity) 41 42
補足情報(FW/ツールのバージョンなど)
上記のコードは輪郭を抽出したのち、以下の手順で複雑さを数値化しました。
- 'complexity = 0' で複雑さを初期化する変数を作成。
- 'hull = ConvexHull(contour, reshape(-1,-2))' で凸包の数を計算。
- 'vertex_count = hull.vertices.shape[0]' で凸包の頂点の数を計算。
- 'complexity += vertex_count' で複雑さを加算。
 
なお今回のコードで使用したポケモンの画像は公式のポケモンずかんの画像から取得しています。
円に近いほど多角形に近似したときの頂点数は多くなるのでそのような結果になります。
よって頂点数(だけ)ではない別の尺度を考えた方がよいと思います。
趣味ならまだしも
> 研究
と称する活動の内容をこんなところで訊いてて大丈夫なんですかね? いろんな意味で.
一個前の質問:https://teratail.com/questions/k3yzgx5n2xwl56
は,単純なライブラリ関数の使い方の話だったけど,今回は研究内容面に踏み込んでますよね.
findContoursで出した頂点の数とconvexHullで出した頂点の数で
その比率を複雑さとするのはどうでしょうか?
アイデアありがとうございます。
findContoursで出した頂点の数とconvexHullで出した頂点の数でその比率を以下のコードで示しましたが、
マルマイン:96.8048907186198,  ムゲンダイナ:40.37359532721007 となってしまいました。
complexity = 0
for contour in contours:
    # 輪郭の面積を計算
    contour_area = cv2.contourArea(contour)
    
    # 輪郭の凸包を計算
    hull = ConvexHull(contour.reshape(-1, 2))
    
    # 凸包の面積を計算
    hull_area = hull.area
    
    # 輪郭と凸包の比率を計算
    ratio = contour_area / hull_area
print("輪郭と凸包の比率:", ratio)
fourteenlengthさんの回答のコードを、質問の画像のようなボケてない画像に適用すると、線の輪郭の長さの総和でほとんど数値が決まってしまうような
たとえば、下記のコードで円のみが描画された画像を作って、それを使って実行してみてください
import numpy as np
import cv2
img0 = np.ones((2000, 2000, 3)).astype("uint8") * 255
img1 = np.ones((2000, 2000, 3)).astype("uint8") * 255
img2 = np.ones((2000, 2000, 3)).astype("uint8") * 255
cv2.circle(img0, (1000, 1000), 400, (0, 0, 0), thickness=10)
cv2.circle(img1, (1000, 1000), 800, (0, 0, 0), thickness=10)
cv2.circle(img2, (1000, 1000), 400, (0, 0, 0), thickness=-1)
cv2.imwrite("img0.png", img0)
cv2.imwrite("img1.png", img1)
cv2.imwrite("img2.png", img2)
img0.pngに対して、円の直径が倍のimg1.pngでは数値が2倍になります
円の内部を塗りつぶしてないimg0.pngに対して、円の内部を塗りつぶしたimg2.pngでは数値が半分になります
上記の結果は、質問者さんの意図に合ってるのでしょうか?
【追記】
比較する各ポケモンの画像上のサイズ(見た目ではなく、縦横の実際の画素数)がだいたい同じなら、直径の方は気にしなくてもいいかもしれません
塗りつぶし有無で数値が変わるのは、ほぼ同じ輪郭でも、白っぽいポケモンと黒っぽいポケモンで数値が大きく変わることが有るかもしれません
質問の意図とは少しずれているかもしれませんが、
輪郭の凹凸では数値化が難しそうであり、アイデアも集まらなさそうだったので
fourteenlengthさんの回答のコードを、ベストアンサーとさせていただきました。

回答3件
あなたの回答
tips
プレビュー







