回答編集履歴
10
コード内のコメントを修正
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:縦軸ピクセル数
|
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()
|
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
一部修正
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
一部修正
answer
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
- 最初の重心、平行移動、回転は、全て`scipy.ndimage`を使い、モーメント演算だけは見当たらないので自作、そしてモーメント最小を求めるのに`scipy.optimize`を使いました。
|
6
6
|
- なお、歯の画像は質問者様の最初の画像をキャプチャして作成しました(ですのでピクセルサイズは元とは異なります)。回転によって歯の画像が枠外にはみ出ない前提でいます。
|
7
7
|
|
8
|
-
以下がコードと実行結果の図です。-23.
|
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
一部修正
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
アルゴリズムを修正
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
|
-
以下がコードと実行結果の図です。-
|
8
|
+
以下がコードと実行結果の図です。-23.35度ほどの回転が最適である、と出ました。とてもバランスが良いように見えます。
|
8
9
|
|
9
|
-
|
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
|
-
#
|
27
|
+
# mass:縦軸ピクセル数 * radius:中心軸からの左右のピクセル距離を合計している
|
27
|
-
def
|
28
|
+
def inertia(img):
|
28
|
-
|
29
|
+
mass = img.sum(axis=0)
|
29
|
-
|
30
|
+
radius = np.abs(np.arange(-len(mass)//2, len(mass)//2+1))
|
30
|
-
if len(
|
31
|
+
if len(mass) != len(radius):
|
31
|
-
|
32
|
+
radius = radius[radius != 0] # 中心位置の補正
|
32
|
-
return (
|
33
|
+
return (mass * radius * radius).sum() # 慣性モーメント= Σ m*r^2
|
33
34
|
|
34
|
-
# 回転させて
|
35
|
+
# 回転させて慣性モーメントを測定する=最小化関数
|
35
|
-
def
|
36
|
+
def rotated_inertia(degree, img):
|
36
|
-
return
|
37
|
+
return inertia(ndimage.rotate(img, degree, reshape=False))
|
37
38
|
|
38
|
-
# 最小化関数の最小値を求めることで、-90〜90度の回転時の最小モーメントを得る
|
39
|
+
# 最小化関数の最小値を求めることで、-90〜90度の回転時の最小曲げモーメントを得る
|
39
40
|
res = optimize.minimize_scalar(
|
40
|
-
|
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
|
-

|
5
一部修正
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
一部修正
answer
CHANGED
@@ -4,8 +4,10 @@
|
|
4
4
|
- 最初の重心、平行移動、回転は、全て`scipy.ndimage`を使い、モーメント演算だけは見当たらないので自作、そしてモーメント最小を求めるのに`scipy.optimize`を使いました。
|
5
5
|
- なお、歯の画像は質問者様の最初の画像をキャプチャして作成しました(ですのでピクセルサイズは元とは異なります)。回転によって歯の画像が枠外にはみ出ない前提でいます。
|
6
6
|
|
7
|
-
以下がコードと実行結果の図です。-34.14度ほどの回転が最適である、と出ました。
|
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
一部修正
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算出が違っていたため修正
answer
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
- 最初の重心、平行移動、回転は、全て`scipy.ndimage`を使い、モーメント演算だけは見当たらないので自作、そしてモーメント最小を求めるのに`scipy.optimize`を使いました。
|
5
5
|
- なお、歯の画像は質問者様の最初の画像をキャプチャして作成しました(ですのでピクセルサイズは元とは異なります)。回転によって歯の画像が枠外にはみ出ない前提でいます。
|
6
6
|
|
7
|
-
以下がコードと実行結果の図です。-
|
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
|
-
|
26
|
+
arr = img.sum(axis=0)
|
27
|
-
|
27
|
+
mul = np.arange(-len(arr)//2, len(arr)//2+1)
|
28
|
-
|
28
|
+
if len(arr) != len(mul):
|
29
|
+
mul = mul[mul != 0]
|
29
|
-
|
30
|
+
return (arr * mul).sum()
|
30
31
|
|
31
32
|
# 回転させてmomentの絶対値を測定する=最小化関数
|
32
33
|
def rotated_moment(degree, img):
|
33
|
-
|
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
|
-

|
1
一部修正
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,
|
17
|
+
_, img = cv2.threshold(img, 100, 1, cv2.THRESH_BINARY)
|
18
18
|
|
19
19
|
# 平行移動して重心を中心にする
|
20
20
|
center = ndimage.center_of_mass(img)
|