teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

10

コード内のコメントを修正

2020/11/27 23:34

投稿

toast-uz
toast-uz

スコア3266

answer CHANGED
@@ -24,19 +24,20 @@
24
24
  img = ndimage.shift(img, np.array(img.shape)/2-np.array(center))
25
25
 
26
26
  # 図形を立てた時の、中心軸に対する慣性モーメント
27
- # mass:縦軸ピクセル数 * radius:中心軸からの左右のピクセル距離を合計している
27
+ # mass:縦軸ピクセル数radius:中心軸からの左右のピクセル距離
28
+ # 慣性モーメント = Σ mass * radius^2
28
29
  def inertia(img):
29
30
  mass = img.sum(axis=0)
30
31
  radius = np.abs(np.arange(-len(mass)//2, len(mass)//2+1))
31
32
  if len(mass) != len(radius):
32
33
  radius = radius[radius != 0] - 0.5 # 中心位置の補正
33
- return (mass * radius * radius).sum() # 慣性モーメント= Σ m*r^2
34
+ return (mass * radius * radius).sum()
34
35
 
35
36
  # 回転させて慣性モーメントを測定する=最小化関数
36
37
  def rotated_inertia(degree, img):
37
38
  return inertia(ndimage.rotate(img, degree, reshape=False))
38
39
 
39
- # 最小化関数の最小値を求めることで、-90〜90度の回転時の最小曲げモーメントを得る
40
+ # 最小化関数の最小値を求めることで、-90〜90度の回転時の最小慣性モーメントを得る
40
41
  res = optimize.minimize_scalar(
41
42
  rotated_inertia, bounds=[-90,90], args=(img), method='Bounded')
42
43
 

9

一部修正

2020/11/27 23:34

投稿

toast-uz
toast-uz

スコア3266

answer CHANGED
@@ -1,7 +1,7 @@
1
1
  scipyをフル活用することで全体的にすっきりと作ってみました。
2
2
 
3
- - アイデアとしては、まずは歯の形を平面に置いた重心に中心を揃え、その後、歯の形を立てて中心を軸に自重で回転できるようにしたときにバランスが取れる回転位置を求める、というものです。
3
+ - アイデアとしては、まずは歯の形を平面に置いた重心に中心を揃え、その後、歯の形を立ててバランスが取れる回転位置を求める、というものです。
4
- - バランスが取れるかどうかは歯全体を重さ密度一定の剛体としてみた場合に、垂直に立てた状態で、中心軸に対する慣性モーメントが最小になる、という定義をしました。
4
+ - バランスが取れるかどうかは歯全体を重さ密度一定の剛体としてみた場合に、垂直に立てた状態で、中心軸に対する慣性モーメントが最小になる、という定義をしました。
5
5
  - 最初の重心、平行移動、回転は、全て`scipy.ndimage`を使い、モーメント演算だけは見当たらないので自作、そしてモーメント最小を求めるのに`scipy.optimize`を使いました。
6
6
  - なお、歯の画像は質問者様の最初の画像をキャプチャして作成しました(ですのでピクセルサイズは元とは異なります)。回転によって歯の画像が枠外にはみ出ない前提でいます。
7
7
 

8

一部修正

2020/11/27 12:49

投稿

toast-uz
toast-uz

スコア3266

answer CHANGED
@@ -5,7 +5,7 @@
5
5
  - 最初の重心、平行移動、回転は、全て`scipy.ndimage`を使い、モーメント演算だけは見当たらないので自作、そしてモーメント最小を求めるのに`scipy.optimize`を使いました。
6
6
  - なお、歯の画像は質問者様の最初の画像をキャプチャして作成しました(ですのでピクセルサイズは元とは異なります)。回転によって歯の画像が枠外にはみ出ない前提でいます。
7
7
 
8
- 以下がコードと実行結果の図です。-23.35度ほどの回転が最適である、と出ました。質問者様の結果と比較して、ほんの少しだけ右回転しており、とてもバランスが良いように見えます。
8
+ 以下がコードと実行結果の図です。-23.36度ほどの回転が最適である、と出ました。質問者様の結果と比較して、ほんの少しだけ右回転しており、とてもバランスが良いように見えます。
9
9
 
10
10
  ※ 当初は、左右で逆向きの回転モーメントを使ってましたが、慣性モーメントを使った方が安定した形になるとわかりました。回転モートメントだと横に伸ばした形でも左右対称であれば安定するのに対して、慣性モーメントだと横をなるべく小さくするような形が有利になります。フィギュアスケートの選手が腕をたたんで高速回転することと、原理は同じです。
11
11
 
@@ -29,7 +29,7 @@
29
29
  mass = img.sum(axis=0)
30
30
  radius = np.abs(np.arange(-len(mass)//2, len(mass)//2+1))
31
31
  if len(mass) != len(radius):
32
- radius = radius[radius != 0] # 中心位置の補正
32
+ radius = radius[radius != 0] - 0.5 # 中心位置の補正
33
33
  return (mass * radius * radius).sum() # 慣性モーメント= Σ m*r^2
34
34
 
35
35
  # 回転させて慣性モーメントを測定する=最小化関数

7

一部修正

2020/11/27 12:45

投稿

toast-uz
toast-uz

スコア3266

answer CHANGED
@@ -5,7 +5,7 @@
5
5
  - 最初の重心、平行移動、回転は、全て`scipy.ndimage`を使い、モーメント演算だけは見当たらないので自作、そしてモーメント最小を求めるのに`scipy.optimize`を使いました。
6
6
  - なお、歯の画像は質問者様の最初の画像をキャプチャして作成しました(ですのでピクセルサイズは元とは異なります)。回転によって歯の画像が枠外にはみ出ない前提でいます。
7
7
 
8
- 以下がコードと実行結果の図です。-23.35度ほどの回転が最適である、と出ました。とてもバランスが良いように見えます。
8
+ 以下がコードと実行結果の図です。-23.35度ほどの回転が最適である、と出ました。質問者様の結果比較し、ほんの少しだけ右回転しており、とてもバランスが良いように見えます。
9
9
 
10
10
  ※ 当初は、左右で逆向きの回転モーメントを使ってましたが、慣性モーメントを使った方が安定した形になるとわかりました。回転モートメントだと横に伸ばした形でも左右対称であれば安定するのに対して、慣性モーメントだと横をなるべく小さくするような形が有利になります。フィギュアスケートの選手が腕をたたんで高速回転することと、原理は同じです。
11
11
 

6

アルゴリズムを修正

2020/11/27 12:41

投稿

toast-uz
toast-uz

スコア3266

answer CHANGED
@@ -1,12 +1,13 @@
1
1
  scipyをフル活用することで全体的にすっきりと作ってみました。
2
2
 
3
- - アイデアとしては、まずは歯の形を平面に置いた重心に中心を揃え、その後、歯の形を立てて中心を軸に自重で回転できるようにしたときにバランスが取れる回転位置を求める、というものです。バランスが取れるかどうかは歯全体を重さ密度一定の剛体としてみた場合の回転モーメントが最小になる、という定義をしました。
3
+ - アイデアとしては、まずは歯の形を平面に置いた重心に中心を揃え、その後、歯の形を立てて中心を軸に自重で回転できるようにしたときにバランスが取れる回転位置を求める、というものです。
4
+ - バランスが取れるかどうかは歯全体を重さ密度一定の剛体としてみた場合に、垂直に立てた状態で、中心軸に対する慣性モーメントが最小になる、という定義をしました。
4
5
  - 最初の重心、平行移動、回転は、全て`scipy.ndimage`を使い、モーメント演算だけは見当たらないので自作、そしてモーメント最小を求めるのに`scipy.optimize`を使いました。
5
6
  - なお、歯の画像は質問者様の最初の画像をキャプチャして作成しました(ですのでピクセルサイズは元とは異なります)。回転によって歯の画像が枠外にはみ出ない前提でいます。
6
7
 
7
- 以下がコードと実行結果の図です。-34.14度ほどの回転が最適である、と出ました。個人的には、重さ的バランスはいると思いますが、形的バランスだともう少し左に回転していたほうが良さそな気が・・・
8
+ 以下がコードと実行結果の図です。-23.35度ほどの回転が最適である、と出ました。とてバランスが良いよに見えます
8
9
 
9
- moment関数(絶対値)が最小となる回転を求めるわすの、moment関数を入替えことで「バラス良いは何か」つきつめて、より質問者様の求めものに合う形にすることも可能です例えば図上側の「重さ密度」少し増やすこと的不安定さを打ち消ような丁度よいバランスが出るかと思います
10
+ ※ 当初は、左右で逆向きの回転モーメント使ってましたが、慣性モーメントを使った方が安定した形になかりました。回転モートメントだと横に伸ばした形も左右対称ば安定すのに対して慣性モーメトだべく小さくするよが有利なります。フィギュアスケート選手が腕たたんで高速回転ことは同じです。
10
11
 
11
12
  ```Python
12
13
  import numpy as np
@@ -22,22 +23,22 @@
22
23
  center = ndimage.center_of_mass(img)
23
24
  img = ndimage.shift(img, np.array(img.shape)/2-np.array(center))
24
25
 
25
- # 中心からの左右のバランスを求め関数
26
+ # 図形を立てた時の、中心軸に対す慣性モーメント
26
- # arr:縦軸ピクセル数 * mul:中心軸からの左右のピクセル距離(左が+/右が-) を合計している
27
+ # mass:縦軸ピクセル数 * radius:中心軸からの左右のピクセル距離を合計している
27
- def moment(img):
28
+ def inertia(img):
28
- arr = img.sum(axis=0) # 現在は図の上も下も重さ密度は同じとして単純に縦軸ピクセル数を求める
29
+ mass = img.sum(axis=0)
29
- mul = np.arange(-len(arr)//2, len(arr)//2+1)
30
+ radius = np.abs(np.arange(-len(mass)//2, len(mass)//2+1))
30
- if len(arr) != len(mul):
31
+ if len(mass) != len(radius):
31
- mul = mul[mul != 0]
32
+ radius = radius[radius != 0] # 中心位置の補正
32
- return (arr * mul).sum()
33
+ return (mass * radius * radius).sum() # 慣性モーメント= Σ m*r^2
33
34
 
34
- # 回転させてmomentの絶対値を測定する=最小化関数
35
+ # 回転させて慣性モーメントを測定する=最小化関数
35
- def rotated_moment(degree, img):
36
+ def rotated_inertia(degree, img):
36
- return abs(moment(ndimage.rotate(img, degree, reshape=False)))
37
+ return inertia(ndimage.rotate(img, degree, reshape=False))
37
38
 
38
- # 最小化関数の最小値を求めることで、-90〜90度の回転時の最小モーメントを得る
39
+ # 最小化関数の最小値を求めることで、-90〜90度の回転時の最小曲げモーメントを得る
39
40
  res = optimize.minimize_scalar(
40
- rotated_moment, bounds=[-90,90], args=(img), method='Bounded')
41
+ rotated_inertia, bounds=[-90,90], args=(img), method='Bounded')
41
42
 
42
43
  # 最小値の時の回転角度を求める
43
44
  print(res.x)
@@ -51,4 +52,4 @@
51
52
 
52
53
  結果
53
54
 
54
- ![回転結果](e23ed991fdf5f0fe1b45741a8a845309.png)
55
+ ![回転結果](73ac151c5e0f33fa43908bb84c97bd09.png)

5

一部修正

2020/11/27 12:39

投稿

toast-uz
toast-uz

スコア3266

answer CHANGED
@@ -25,7 +25,7 @@
25
25
  # 中心からの左右のバランスを求める関数
26
26
  # arr:縦軸ピクセル数 * mul:中心軸からの左右のピクセル距離(左が+/右が-) を合計している
27
27
  def moment(img):
28
- arr = img.sum(axis=0) # 現在は図の上も下も重さ密度は同じとして単純合計
28
+ arr = img.sum(axis=0) # 現在は図の上も下も重さ密度は同じとして単純に縦軸ピクセル数を求める
29
29
  mul = np.arange(-len(arr)//2, len(arr)//2+1)
30
30
  if len(arr) != len(mul):
31
31
  mul = mul[mul != 0]

4

一部修正

2020/11/26 22:30

投稿

toast-uz
toast-uz

スコア3266

answer CHANGED
@@ -4,8 +4,10 @@
4
4
  - 最初の重心、平行移動、回転は、全て`scipy.ndimage`を使い、モーメント演算だけは見当たらないので自作、そしてモーメント最小を求めるのに`scipy.optimize`を使いました。
5
5
  - なお、歯の画像は質問者様の最初の画像をキャプチャして作成しました(ですのでピクセルサイズは元とは異なります)。回転によって歯の画像が枠外にはみ出ない前提でいます。
6
6
 
7
- 以下がコードと実行結果の図です。-34.14度ほどの回転が最適である、と出ました。なかなか「バランスよく」回転しているかと思います。なお、moment関数(の絶対値)が最小となる回転を求めるわけですので、moment関数を入れ替えることで、「バランス良いとは何か」をつきつめて、より質問者様の求めるものに合う形にすることも可能です。個人的には、重さ的バランスはとれていると思いますが、形的バランスだともう少し左に回転していたほうが良さそうな気が・・・。
7
+ 以下がコードと実行結果の図です。-34.14度ほどの回転が最適である、と出ました。個人的には、重さ的バランスはとれていると思いますが、形的バランスだともう少し左に回転していたほうが良さそうな気が・・・。
8
8
 
9
+ moment関数(の絶対値)が最小となる回転を求めるわけですので、moment関数を入れ替えることで、「バランス良いとは何か」をつきつめて、より質問者様の求めるものに合う形にすることも可能です。例えば図の上側の「重さ密度」を少し増やすことで、心理的不安定さを打ち消すような丁度よいバランスが出るかと思います。
10
+
9
11
  ```Python
10
12
  import numpy as np
11
13
  from scipy import ndimage, optimize
@@ -21,9 +23,9 @@
21
23
  img = ndimage.shift(img, np.array(img.shape)/2-np.array(center))
22
24
 
23
25
  # 中心からの左右のバランスを求める関数
24
- # 中心軸からの左右のピクセル距離(左が+/右が-)*縦軸ピクセル数積算
26
+ # arr:縦軸ピクセル数 * mul:中心軸からの左右のピクセル距離(左が+/右が-) 合計している
25
27
  def moment(img):
26
- arr = img.sum(axis=0)
28
+ arr = img.sum(axis=0) # 現在は図の上も下も重さ密度は同じとして単純合計
27
29
  mul = np.arange(-len(arr)//2, len(arr)//2+1)
28
30
  if len(arr) != len(mul):
29
31
  mul = mul[mul != 0]

3

一部修正

2020/11/26 22:28

投稿

toast-uz
toast-uz

スコア3266

answer CHANGED
@@ -4,7 +4,7 @@
4
4
  - 最初の重心、平行移動、回転は、全て`scipy.ndimage`を使い、モーメント演算だけは見当たらないので自作、そしてモーメント最小を求めるのに`scipy.optimize`を使いました。
5
5
  - なお、歯の画像は質問者様の最初の画像をキャプチャして作成しました(ですのでピクセルサイズは元とは異なります)。回転によって歯の画像が枠外にはみ出ない前提でいます。
6
6
 
7
- 以下がコードと実行結果の図です。-34.14度ほどの回転が最適である、と出ました。なかなか「バランスよく」回転しているかと思います。なお、moment関数が最小となる回転を求めるわけですので、moment関数を入れ替えることで、「バランス良いとは何か」をつきつめて、より質問者様の求めるものに合う形にすることも可能です。
7
+ 以下がコードと実行結果の図です。-34.14度ほどの回転が最適である、と出ました。なかなか「バランスよく」回転しているかと思います。なお、moment関数(の絶対値)が最小となる回転を求めるわけですので、moment関数を入れ替えることで、「バランス良いとは何か」をつきつめて、より質問者様の求めるものに合う形にすることも可能です。個人的には、重さ的バランスはとれていると思いますが、形的バランスだともう少し左に回転していたほうが良さそうな気が・・・。
8
8
 
9
9
  ```Python
10
10
  import numpy as np

2

moment算出が違っていたため修正

2020/11/26 22:22

投稿

toast-uz
toast-uz

スコア3266

answer CHANGED
@@ -4,7 +4,7 @@
4
4
  - 最初の重心、平行移動、回転は、全て`scipy.ndimage`を使い、モーメント演算だけは見当たらないので自作、そしてモーメント最小を求めるのに`scipy.optimize`を使いました。
5
5
  - なお、歯の画像は質問者様の最初の画像をキャプチャして作成しました(ですのでピクセルサイズは元とは異なります)。回転によって歯の画像が枠外にはみ出ない前提でいます。
6
6
 
7
- 以下がコードと実行結果の図です。-21.24度ほどの回転が最適である、と出ました。なかなか「バランスよく」回転しているかと思います。
7
+ 以下がコードと実行結果の図です。-34.14度ほどの回転が最適である、と出ました。なかなか「バランスよく」回転しているかと思います。なお、moment関数が最小となる回転を求めるわけですので、moment関数を入れ替えることで、「バランス良いとは何か」をつきつめて、より質問者様の求めるものに合う形にすることも可能です。
8
8
 
9
9
  ```Python
10
10
  import numpy as np
@@ -23,14 +23,15 @@
23
23
  # 中心からの左右のバランスを求める関数
24
24
  # 中心軸からの左右のピクセル距離(左が+/右が-)*縦軸ピクセル数を積算
25
25
  def moment(img):
26
- arr = img.sum(axis=0)
26
+ arr = img.sum(axis=0)
27
- arr1, arr2 = np.array_split(arr, 2)
27
+ mul = np.arange(-len(arr)//2, len(arr)//2+1)
28
- arr3 = arr1[::-1] - arr2
28
+ if len(arr) != len(mul):
29
+ mul = mul[mul != 0]
29
- return (arr3 * np.arange(len(arr3))).sum()
30
+ return (arr * mul).sum()
30
31
 
31
32
  # 回転させてmomentの絶対値を測定する=最小化関数
32
33
  def rotated_moment(degree, img):
33
- return abs(moment(ndimage.rotate(img, degree, reshape=False)))
34
+ return abs(moment(ndimage.rotate(img, degree, reshape=False)))
34
35
 
35
36
  # 最小化関数の最小値を求めることで、-90〜90度の回転時の最小モーメントを得る
36
37
  res = optimize.minimize_scalar(
@@ -48,4 +49,4 @@
48
49
 
49
50
  結果
50
51
 
51
- ![回転結果](ba79ab90332ddc899c3582df9266c224.png)
52
+ ![回転結果](e23ed991fdf5f0fe1b45741a8a845309.png)

1

一部修正

2020/11/26 22:19

投稿

toast-uz
toast-uz

スコア3266

answer CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  # 画像読み込みと2値化
16
16
  img = cv2.imread('tooth.png', 0)
17
- _, img = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)
17
+ _, img = cv2.threshold(img, 100, 1, cv2.THRESH_BINARY)
18
18
 
19
19
  # 平行移動して重心を中心にする
20
20
  center = ndimage.center_of_mass(img)