質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

1666閲覧

OpenCVで画像の輪郭の複雑さを数値化したいです。

spot_0104

総合スコア5

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2023/05/26 02:01

編集2023/05/26 11:36

実現したいこと

python初心者です。
ポケモンの画像の複雑さを数値化したいと思っています。

丸みを帯びていれば数値が小さく、凹凸が多いポケモンは数値が大きくなるようにしたいです。

前提

現在輪郭を抽出し、複雑さを数値化するコードを作成してみましたが、
丸みを帯びているポケモンの方が、凹凸の多いポケモンよりも数値が高くなってしまいました。

・マルマイン:101
イメージ説明
・ムゲンダイナ:29
イメージ説明

該当のソースコード

以下のコードが現在作ってみたコードです。

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/ツールのバージョンなど)

上記のコードは輪郭を抽出したのち、以下の手順で複雑さを数値化しました。

  1. 'complexity = 0' で複雑さを初期化する変数を作成。
  2. 'hull = ConvexHull(contour, reshape(-1,-2))' で凸包の数を計算。
  3. 'vertex_count = hull.vertices.shape[0]' で凸包の頂点の数を計算。
  4. 'complexity += vertex_count' で複雑さを加算。

 

なお今回のコードで使用したポケモンの画像は公式のポケモンずかんの画像から取得しています。

https://zukan.pokemon.co.jp

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

can110

2023/05/26 02:25

円に近いほど多角形に近似したときの頂点数は多くなるのでそのような結果になります。 よって頂点数(だけ)ではない別の尺度を考えた方がよいと思います。
fana

2023/05/26 04:07 編集

趣味ならまだしも > 研究 と称する活動の内容をこんなところで訊いてて大丈夫なんですかね? いろんな意味で. 一個前の質問:https://teratail.com/questions/k3yzgx5n2xwl56 は,単純なライブラリ関数の使い方の話だったけど,今回は研究内容面に踏み込んでますよね.
yominet

2023/05/26 09:05

findContoursで出した頂点の数とconvexHullで出した頂点の数で その比率を複雑さとするのはどうでしょうか?
spot_0104

2023/05/26 14:44

アイデアありがとうございます。 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)
jbpb0

2023/05/29 01:27 編集

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では数値が半分になります 上記の結果は、質問者さんの意図に合ってるのでしょうか? 【追記】 比較する各ポケモンの画像上のサイズ(見た目ではなく、縦横の実際の画素数)がだいたい同じなら、直径の方は気にしなくてもいいかもしれません 塗りつぶし有無で数値が変わるのは、ほぼ同じ輪郭でも、白っぽいポケモンと黒っぽいポケモンで数値が大きく変わることが有るかもしれません
spot_0104

2023/05/29 03:21

質問の意図とは少しずれているかもしれませんが、 輪郭の凹凸では数値化が難しそうであり、アイデアも集まらなさそうだったので fourteenlengthさんの回答のコードを、ベストアンサーとさせていただきました。
guest

回答3

0

ベストアンサー

2023-05-27 追記

画像数値(複雑なほど大きい)
マルマイン3616
マルマイン(腕を落書き)5653
ムゲンダイナ7090

Python3

1import os 2import cv2 3import numpy as np 4 5def img_loader(): 6 path = os.path.split(os.path.abspath(__file__))[0] + "/" 7 img_ma = cv2.imread(path + "ma.png") 8 img_mu = cv2.imread(path + "mu.png") 9 return img_ma,img_mu 10 11def DoG(img): 12 blur_3 = cv2.GaussianBlur(img, (3,3), 0) 13 blur_5 = cv2.GaussianBlur(img, (5,5), 0) 14 return blur_5 - blur_3 15 16if __name__ == "__main__": 17 img_ma, img_mu = img_loader() 18 19 if (img_ma is None) or (img_mu is None) : 20 print("パスが間違っているかイメージが破損していてファイルがロードできませんでした。") 21 print("マルマイン:",img_ma ) 22 print("ムゲンダイナ:",img_mu) 23 else: 24 # Laplacianできるようにグレースケールにする 25 img_ma_gray = cv2.cvtColor(img_ma,cv2.COLOR_BGR2GRAY) 26 img_mu_gray = cv2.cvtColor(img_mu,cv2.COLOR_BGR2GRAY) 27 28 # 線だけ抽出する 29 img_ma_gray = DoG(img_ma_gray) 30 img_mu_gray = DoG(img_mu_gray) 31 32 # 穴埋め 33 img_ma_gray = cv2.GaussianBlur(img_ma_gray, (5,5), 0) 34 img_mu_gray = cv2.GaussianBlur(img_mu_gray, (5,5), 0) 35 36 # 淡い灰色までは白判定にしてしまう 37 _,img_ma_gray = cv2.threshold(img_ma_gray, 150, 255, cv2.THRESH_BINARY) 38 _,img_mu_gray = cv2.threshold(img_mu_gray, 150, 255, cv2.THRESH_BINARY) 39 40 # Laplacianの分散を見る 41 var_ma = cv2.Laplacian(img_ma_gray , cv2.CV_64F).var() 42 var_mu = cv2.Laplacian(img_mu_gray , cv2.CV_64F).var() 43 44 # 表示部分 45 cv2.imshow("img_ma_gray " + str(var_ma),img_ma_gray ) 46 cv2.imshow("img_mu_gray " + str(var_mu),img_mu_gray ) 47 cv2.waitKey(0)

ポケモンの画像の複雑さを数値化したいと思っています。

cv2.Laplacian()をして、その後に.var()とすると、画像のエッジがどれくらい立っているかが見えます。
これは、画像のピントが合っているかどうか探るアルゴリズムで使われるものです。

「輪郭のー」という考え方と少しずれますが、「エッジが立っている」という指標が「ポケモンの画像の複雑さを数値化したい」の代替ができるのであれば、ラプラシアンフィルタの分散を見る、で良いのではないでしょうか。

投稿2023/05/26 13:57

編集2023/05/27 06:24
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

spot_0104

2023/05/26 14:24

アイデアありがとうございます。 アルゴリズムを理解してコードを作成してみようと思います!
spot_0104

2023/05/27 14:49

上記コードを試してみたところ、複雑なポケモンほど数値が高いような出力結果にできました。 丁寧な対応ありがとうございました!助かりました!
guest

0

すっごい昔の私の質問ですが,
この辺の話とかをどうにか使えませんかね?

例えば,
元の形状 と 丸めた形状 の差分を見るとか,そんなことをすれば,
十分滑らかな箇所の差分は少なく,尖っているとか細かく入り組んでいるような箇所では差分がたくさん生じるんじゃないかな,と.
(別の画像との比較には何らかの正規化が必要そうだけど.元の形状の面積で除すとか?)

投稿2023/05/26 04:01

fana

総合スコア11712

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2023/05/26 04:09 編集

要は,元の輪郭形状をある適度滑らかなカーブで近似した結果と元の輪郭形状との違いを見る,的な. (「円形度」みたいなのと,意味的には似たような.)
spot_0104

2023/05/26 14:30

ありがとうございます。 円形度で画像の分析を行ってみたいと思います!
guest

0

ChatGPTの回答

多角形の輪郭が滑らかであるかを数値的に判定する尺度として、曲率を利用する方法があります。曲率は、曲線上の点における曲線の曲がり具合を表す指標であり、曲率が小さいほど曲線は滑らかです。

以下の手順で多角形の輪郭の滑らかさを評価する尺度を計算することができます:

  1. 多角形の各頂点における曲率を計算します。頂点における曲率は、その頂点に隣接する2つの辺のなす角度の差を利用して計算することができます。
  2. 全ての頂点の曲率を合計し、平均曲率を求めます。
  3. 平均曲率が小さいほど多角形の輪郭は滑らかであると判断できます。

具体的な計算式は、以下のようになります:

1. 各頂点における曲率の計算:

頂点P_iについて、その前後の頂点をP_{i-1}とP_{i+1}とします。P_iにおける曲率K_iは、以下の式で求めることができます:

K_i = |θ_{i-1} - θ_{i+1}|

ここで、θ_{i-1}はP_iを中心とするベクトルP_{i-1}P_iと、P_iを中心とするベクトルP_iP_{i+1}のなす角です。

2. 平均曲率の計算:

全ての頂点の曲率K_iを合計し、頂点の総数で割って平均曲率K_avgを求めます:

K_avg = (K_1 + K_2 + ... + K_n) / n

ここで、nは多角形の頂点の総数です。

3. 判定:

平均曲率K_avgが小さいほど多角形の輪郭は滑らかであると判断できます。適切な閾値を設定し、K_avgがその閾値以下であれば「滑らか」と判定することができます。

この方法を利用することで、多角形の輪郭の滑らかさを数値的に評価することができます。ただし、この尺度はあくまで一つの指標であり、他の滑らかさの定義に応じて適切な尺度を選ぶ必要があります。

投稿2023/05/26 02:40

can110

総合スコア38280

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問