私は犬の足の下の圧力を測定する獣医クリニックを手伝っています。私はデータ分析にPythonを使用していますが、今度は足を(解剖学的な)小領域に分割しようとしています。
各足の2D配列を作成しました。これは、足によって時間の経過とともにロードされた各センサーの最大値で構成されています。これは私が '検出'したい領域を描くためにExcelを使った一足の例です。これらは、極大値を持つセンサーの周囲2×2の箱で、合計で最大の合計を持ちます。
そこで私はいくつかの実験を試みて、単純に各列と行の最大値を探すことにしました(足の形のために一方向には見えません)。これは、別々のつま先の位置をかなりよく「検出」しているように見えますが、隣接するセンサーもマークします。
それで、Pythonにこれらの最大値のどれが私が欲しいものであるかを伝えるための最善の方法は何でしょうか?
注意:2x2の正方形は別々のつま先でなければならないので、重なり合うことはできません。
また、私は便利なものとして2x2を取り、より高度な解決策は大歓迎ですが、私は単に人間の運動科学者なので、私は本当のプログラマーでも数学者でもないので、それを「単純」にしてください。
そこで、私は@ jexteeの解決策を試しました(以下の結果を参照)。お分かりのように、それは前足には非常に効果的ですが、後肢にはあまり効果的ではありません。
より具体的には、それは4番目のつま先である小さなピークを認識することはできません。これがどこにあるかを考慮せずに、ループが最小値に向かってトップダウンに見えるという事実に明らかに固有のものです。
4番目のつま先も見つけられるように、@ jexteeのアルゴリズムを調整する方法を知っている人はいますか?
まだ他の試験を処理していないので、他のサンプルを提供することはできません。しかし、私が以前に与えたデータは各足の平均でした。このファイルは、それらがプレートと接触した順序で9本の足の最大データを持つ配列です。
この画像は、それらがプレート上でどのように空間的に広がっているかを示しています。
興味のある人のためにブログを立ち上げましたそして私はすべての生の測定値を使ってSkyDriveをセットアップしました。それで、より多くのデータを要求する人には:あなたにもっと力を!
だから私は私の質問で私が得た助けの後に足の検出そして足のソート、私はついに各足のつま先の検出をチェックすることができました!結局のところ、それは私の自身の例のもののような大きさの足以外の何にもそれほどうまくいかない。後知恵ではもちろん、それは2×2をとても恣意的に選ぶことに対する私自身の責任です。
これは、うまくいかない場合の良い例です。ネイルがつま先として認識され、「ヒール」が非常に広いため、2回認識されます。
足が大きすぎるので、重ならないように2 x 2のサイズを取ると、つま先が2回検出されます。反対に、小さな犬では5番目のつま先が見つからないことがよくありますが、これは2×2の面積が大きすぎることが原因と考えられます。
後に私のすべての測定に対して現在の解決策を試す私はほとんどすべての私の小型犬のためにそれが5番目のつま先を見つけられず、大型犬のための影響の50%以上でそれがもっと見つけるだろうという驚異的な結論に達しました!
だから明らかに私はそれを変更する必要があります。私自身の推測は、neighborhood
小さい犬のための小さいものと大きい犬のための大きいものへ。しかしgenerate_binary_structure
私は配列のサイズを変更させないだろう。
したがって、足のサイズに合わせて足の面積を調整するなど、他の誰かが足の位置を特定するためのより良い提案を得られることを願っていますか?
を使用してピークを検出しました極大値フィルタ。これが4足の最初のデータセットの結果です。
私はまた、9本の足と2本目のデータセットでそれを実行しました。それは同様に働いた。
これがあなたのやり方です。
import numpy as np
from scipy.ndimage.filters import maximum_filter
from scipy.ndimage.morphology import generate_binary_structure, binary_erosion
import matplotlib.pyplot as pp
#for some reason I had to reshape. Numpy ignored the shape header.
paws_data = np.loadtxt("paws.txt").reshape(4,11,14)
#getting a list of images
paws = [p.squeeze() for p in np.vsplit(paws_data,4)]
def detect_peaks(image):
"""
Takes an image and detect the peaks usingthe local maximum filter.
Returns a boolean mask of the peaks (i.e. 1 when
the pixel's value is the neighborhood maximum, 0 otherwise)
"""
# define an 8-connected neighborhood
neighborhood = generate_binary_structure(2,2)
#apply the local maximum filter; all pixel of maximal value
#in their neighborhood are set to 1
local_max = maximum_filter(image, footprint=neighborhood)==image
#local_max is a mask that contains the peaks we are
#looking for, but also the background.
#In order to isolate the peaks we must remove the background from the mask.
#we create the mask of the background
background = (image==0)
#a little technicality: we must erode the background in order to
#successfully subtract it form local_max, otherwise a line will
#appear along the background border (artifact of the local maximum filter)
eroded_background = binary_erosion(background, structure=neighborhood, border_value=1)
#we obtain the final mask, containing only peaks,
#by removing the background from the local_max mask (xor operation)
detected_peaks = local_max ^ eroded_background
return detected_peaks
#applying the detection and plotting results
for i, paw in enumerate(paws):
detected_peaks = detect_peaks(paw)
pp.subplot(4,2,(2*i+1))
pp.imshow(paw)
pp.subplot(4,2,(2*i+2) )
pp.imshow(detected_peaks)
pp.show()
あとは、使用するだけです。scipy.ndimage.measurements.label
すべての異なるオブジェクトにラベルを付けるそれからあなたはそれらと個別に遊ぶことができるでしょう。
注意背景が騒々しくないので方法がうまくいくこと。もしそうなら、あなたはバックグラウンドで他の不要なピークの束を検出するでしょう。もう1つの重要な要素は、サイズです。ご近所。ピークサイズが変化した場合は調整する必要があります(大体比例しているはずです)。
regmax
からピモルフ。 - gnovice
データファイル:paw.txt。ソースコード:
from scipy import *
from operator import itemgetter
n = 5 # how many fingers are we looking for
d = loadtxt("paw.txt")
width, height = d.shape
# Create an array where every element is a sum of 2x2 squares.
fourSums = d[:-1,:-1] + d[1:,:-1] + d[1:,1:] + d[:-1,1:]
# Find positions of the fingers.
# Pair each sum with its position number (from 0 to width*height-1),
pairs = zip(arange(width*height), fourSums.flatten())
# Sort by descending sum value, filter overlapping squares
def drop_overlapping(pairs):
no_overlaps = []
def does_not_overlap(p1, p2):
i1, i2 = p1[0], p2[0]
r1, col1 = i1 / (width-1), i1 % (width-1)
r2, col2 = i2 / (width-1), i2 % (width-1)
return (max(abs(r1-r2),abs(col1-col2)) >= 2)
for p in pairs:
if all(map(lambda prev: does_not_overlap(p,prev), no_overlaps)):
no_overlaps.append(p)
return no_overlaps
pairs2 = drop_overlapping(sorted(pairs, key=itemgetter(1), reverse=True))
# Take the first n with the heighest values
positions = pairs2[:n]
# Print results
print d, "\n"
for i, val in positions:
row = i / (width-1)
column = i % (width-1)
print "sum = %f @ %d,%d (%d)" % (val, row, column, i)
print d[row:row+2,column:column+2], "\n"
出力四角形を重ねずに。あなたの例と同じ領域が選択されているようです。
難しい部分は、すべての2 x 2の正方形の合計を計算することです。私はあなたがそれらすべてを必要としていると仮定したので、いくらかの重複があるかもしれません。スライスを使用して、元の2D配列から最初の列と最後の列と行を切り取り、それらをすべて重ねて合計を計算しました。
理解を深めるために、3×3のアレイをイメージングします。
>>> a = arange(9).reshape(3,3) ; a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
それからそのスライスを取ることができます:
>>> a[:-1,:-1]
array([[0, 1],
[3, 4]])
>>> a[1:,:-1]
array([[3, 4],
[6, 7]])
>>> a[:-1,1:]
array([[1, 2],
[4, 5]])
>>> a[1:,1:]
array([[4, 5],
[7, 8]])
今、あなたがそれらを他のものの上に積み重ね、そして同じ位置で要素を合計することを想像してください。これらの合計は、左上隅が同じ位置にある2 x 2の正方形上でまったく同じ合計になります。
>>> sums = a[:-1,:-1] + a[1:,:-1] + a[:-1,1:] + a[1:,1:]; sums
array([[ 8, 12],
[20, 24]])
あなたが2x2の正方形以上の合計を持っているとき、あなたは使うことができますmax
最大値を見つけるsort
またはsorted
ピークを見つけるために。
ピークの位置を覚えておくために、すべての値(合計)をその平らな配列の平らな配列に結合します(を参照)。zip
)それから結果を印刷するときに、もう一度行/列の位置を計算します。
2×2の正方形を重ね合わせることができました。編集バージョンでは、重ならない四角形だけが結果に表示されるように、それらの一部が除外されています。
もう1つの問題は、すべてのピークからどのようにして指になる可能性があるかを選択する方法です。私はうまくいくかどうかわからない考えを持っています。今は実装する時間がないので、疑似コードだけです。
前部の指がほぼ完全な円の上にある場合、後部の指はその円の内側にあるはずです。また、前部フィンガは、多かれ少なかれ等間隔である。これらのヒューリスティックな性質を使って指を検出しようとするかもしれません。
擬似コード
select the top N finger candidates (not too many, 10 or 12)
consider all possible combinations of 5 out of N (use itertools.combinations)
for each combination of 5 fingers:
for each finger out of 5:
fit the best circle to the remaining 4
=> position of the center, radius
check if the selected finger is inside of the circle
check if the remaining four are evenly spread
(for example, consider angles from the center of the circle)
assign some cost (penalty) to this selection of 4 peaks + a rear finger
(consider, probably weighted:
circle fitting error,
if the rear finger is inside,
variance in the spreading of the front fingers,
total intensity of 5 peaks)
choose a combination of 4 peaks + a rear peak with the lowest penalty
これは強引なアプローチです。 Nが比較的小さければ、それは実行可能だと思います。 N = 12の場合、C_12 ^ 5 = 792の組み合わせがあり、後部の指を選択するには5通りの方法があります。
これは画像登録問題。一般的な戦略は次のとおりです。
これは大まかで手軽な方法です。、「おそらくうまくいく可能性のある最も厄介なこと」
オリエンテーションの問題に対処するために、基本的な方向(北、北東など)に8程度の初期設定を設定できます。それぞれを個別に実行し、2つ以上のつま先が同じピクセルになるような結果はすべて捨てます。もう少し考えてみますが、このようなことはまだ画像処理で研究されています - 正しい答えはありません!
もう少し複雑な考え:(加重)K平均クラスタリングそれは悪いことではありません。
収束するまで繰り返します。
この方法はほぼ確実にはるかに良い結果を与えます、そしてあなたはつま先を識別するのを助けるかもしれない各クラスタの質量を得ます。
(やはり、前もってクラスタの数を指定しました。クラスタリングでは、何らかの方法で密度を指定する必要があります。この場合は適切なクラスタの数を選択するか、クラスタの半径を選択して終了数を確認します。後者の例は平均シフト。)
実装の詳細やその他の詳細が欠けていることについて申し訳ありません。これをコーディングしますが、期限があります。来週までに他に何も上手くいかなかったら私に知らせてくださいそして私はそれに打撃を与えるつもりです。
この問題は物理学者によってある程度深く研究されてきた。に良い実装がありますルート。を見てTSpectrumクラス(特にTSpectrum2あなたの場合)とそれらのドキュメント。
参考文献:
...そしてNIMの購読にアクセスできない人のために:
これがアイデアです:あなたは画像の(離散的な)ラプラシアンを計算します。私はそれが元のイメージより劇的である方法で、最大で(マイナスで)大きくなると予想するでしょう。したがって、最大値を見つけやすくなります。
もう一つのアイデアがあります:あなたが高圧スポットの典型的なサイズを知っているならば、あなたは最初にそれを同じサイズのガウスで畳み込むことによってあなたのイメージを滑らかにすることができます。これにより、処理する画像が簡単になります。
永続的相同性を使用してデータセットを分析すると、次のようになります(クリックすると拡大します)。
これは、この記事で説明されているピーク検出方法の2Dバージョンです。そう答え。上の図は、永続性によってソートされた0次元永続相同性クラスを単に示しています。
scipy.misc.imresize()を使用して、元のデータセットを2倍にアップスケールしました。ただし、4つの足は1つのデータセットと見なしました。それを4つに分割すると問題が簡単になります。
方法論この背後にある考え方は非常に単純です。各ピクセルにそのレベルを割り当てる関数の関数グラフを考えてみましょう。それはこのように見えます:
今度は、継続的により低いレベルまで下がる、高さ255の水位を考えてみましょう。極大島ではポップアップ(出生)。鞍点で2つの島が合流します。下の島は上の島に併合されると考えられます(死)。いわゆる永続図(0次元の相同性クラス、私たちの島)は、すべての島の出生時死亡数を表しています。
の固執島のそれは出生レベルと死レベルの違いです。グレーの主対角線までのドットの垂直距離。この図は、残像を減らすことで島にラベルを付けます。
一番最初の写真は島の出生地を示しています。この方法は、極大値を与えるだけでなく、上記の持続性によってそれらの「重要性」を定量化します。その場合、持続性が低すぎると、すべての島が除外されます。しかし、あなたの例では、すべての島(つまり、すべての極大値)があなたが探しているピークです。
Pythonコードが見つかりますここに。
頭の中からいくつかのアイデアをいくつか紹介します。
あなたも見てみたいかもしれませんOpenCVそれはかなりまともなPython APIを持っていて、あなたが役に立つと思うであろういくつかの機能を持っているかもしれません。
生データをありがとう。私は電車に乗っています、そしてこれは私が得た限りです(私の停車場は上がっています)。私はあなたのtxtファイルを正規表現でマッサージし、可視化のためにいくつかのjavascriptを使ってそれをhtmlページに展開しました。私のように、pythonよりも簡単にハッキングされる可能性があるので、ここで共有しています。
私は良いアプローチはスケールと回転が不変であることになると思います、そして私の次のステップはガウシアンの混合物を調べることです。 (各足パッドはガウス分布の中心です)。
<html>
<head>
<script type="text/javascript" src="http://vis.stanford.edu/protovis/protovis-r3.2.js"></script>
<script type="text/javascript">
var heatmap = [[[0,0,0,0,0,0,0,4,4,0,0,0,0],
[0,0,0,0,0,7,14,22,18,7,0,0,0],
[0,0,0,0,11,40,65,43,18,7,0,0,0],
[0,0,0,0,14,61,72,32,7,4,11,14,4],
[0,7,14,11,7,22,25,11,4,14,65,72,14],
[4,29,79,54,14,7,4,11,18,29,79,83,18],
[0,18,54,32,18,43,36,29,61,76,25,18,4],
[0,4,7,7,25,90,79,36,79,90,22,0,0],
[0,0,0,0,11,47,40,14,29,36,7,0,0],
[0,0,0,0,4,7,7,4,4,4,0,0,0]
],[
[0,0,0,4,4,0,0,0,0,0,0,0,0],
[0,0,11,18,18,7,0,0,0,0,0,0,0],
[0,4,29,47,29,7,0,4,4,0,0,0,0],
[0,0,11,29,29,7,7,22,25,7,0,0,0],
[0,0,0,4,4,4,14,61,83,22,0,0,0],
[4,7,4,4,4,4,14,32,25,7,0,0,0],
[4,11,7,14,25,25,47,79,32,4,0,0,0],
[0,4,4,22,58,40,29,86,36,4,0,0,0],
[0,0,0,7,18,14,7,18,7,0,0,0,0],
[0,0,0,0,4,4,0,0,0,0,0,0,0],
],[
[0,0,0,4,11,11,7,4,0,0,0,0,0],
[0,0,0,4,22,36,32,22,11,4,0,0,0],
[4,11,7,4,11,29,54,50,22,4,0,0,0],
[11,58,43,11,4,11,25,22,11,11,18,7,0],
[11,50,43,18,11,4,4,7,18,61,86,29,4],
[0,11,18,54,58,25,32,50,32,47,54,14,0],
[0,0,14,72,76,40,86,101,32,11,7,4,0],
[0,0,4,22,22,18,47,65,18,0,0,0,0],
[0,0,0,0,4,4,7,11,4,0,0,0,0],
],[
[0,0,0,0,4,4,4,0,0,0,0,0,0],
[0,0,0,4,14,14,18,7,0,0,0,0,0],
[0,0,0,4,14,40,54,22,4,0,0,0,0],
[0,7,11,4,11,32,36,11,0,0,0,0,0],
[4,29,36,11,4,7,7,4,4,0,0,0,0],
[4,25,32,18,7,4,4,4,14,7,0,0,0],
[0,7,36,58,29,14,22,14,18,11,0,0,0],
[0,11,50,68,32,40,61,18,4,4,0,0,0],
[0,4,11,18,18,43,32,7,0,0,0,0,0],
[0,0,0,0,4,7,4,0,0,0,0,0,0],
],[
[0,0,0,0,0,0,4,7,4,0,0,0,0],
[0,0,0,0,4,18,25,32,25,7,0,0,0],
[0,0,0,4,18,65,68,29,11,0,0,0,0],
[0,4,4,4,18,65,54,18,4,7,14,11,0],
[4,22,36,14,4,14,11,7,7,29,79,47,7],
[7,54,76,36,18,14,11,36,40,32,72,36,4],
[4,11,18,18,61,79,36,54,97,40,14,7,0],
[0,0,0,11,58,101,40,47,108,50,7,0,0],
[0,0,0,4,11,25,7,11,22,11,0,0,0],
[0,0,0,0,0,4,0,0,0,0,0,0,0],
],[
[0,0,4,7,4,0,0,0,0,0,0,0,0],
[0,0,11,22,14,4,0,4,0,0,0,0,0],
[0,0,7,18,14,4,4,14,18,4,0,0,0],
[0,4,0,4,4,0,4,32,54,18,0,0,0],
[4,11,7,4,7,7,18,29,22,4,0,0,0],
[7,18,7,22,40,25,50,76,25,4,0,0,0],
[0,4,4,22,61,32,25,54,18,0,0,0,0],
[0,0,0,4,11,7,4,11,4,0,0,0,0],
],[
[0,0,0,0,7,14,11,4,0,0,0,0,0],
[0,0,0,4,18,43,50,32,14,4,0,0,0],
[0,4,11,4,7,29,61,65,43,11,0,0,0],
[4,18,54,25,7,11,32,40,25,7,11,4,0],
[4,36,86,40,11,7,7,7,7,25,58,25,4],
[0,7,18,25,65,40,18,25,22,22,47,18,0],
[0,0,4,32,79,47,43,86,54,11,7,4,0],
[0,0,0,14,32,14,25,61,40,7,0,0,0],
[0,0,0,0,4,4,4,11,7,0,0,0,0],
],[
[0,0,0,0,4,7,11,4,0,0,0,0,0],
[0,4,4,0,4,11,18,11,0,0,0,0,0],
[4,11,11,4,0,4,4,4,0,0,0,0,0],
[4,18,14,7,4,0,0,4,7,7,0,0,0],
[0,7,18,29,14,11,11,7,18,18,4,0,0],
[0,11,43,50,29,43,40,11,4,4,0,0,0],
[0,4,18,25,22,54,40,7,0,0,0,0,0],
[0,0,4,4,4,11,7,0,0,0,0,0,0],
],[
[0,0,0,0,0,7,7,7,7,0,0,0,0],
[0,0,0,0,7,32,32,18,4,0,0,0,0],
[0,0,0,0,11,54,40,14,4,4,22,11,0],
[0,7,14,11,4,14,11,4,4,25,94,50,7],
[4,25,65,43,11,7,4,7,22,25,54,36,7],
[0,7,25,22,29,58,32,25,72,61,14,7,0],
[0,0,4,4,40,115,68,29,83,72,11,0,0],
[0,0,0,0,11,29,18,7,18,14,4,0,0],
[0,0,0,0,0,4,0,0,0,0,0,0,0],
]
];
</script>
</head>
<body>
<script type="text/javascript+protovis">
for (var a=0; a < heatmap.length; a++) {
var w = heatmap[a][0].length,
h = heatmap[a].length;
var vis = new pv.Panel()
.width(w * 6)
.height(h * 6)
.strokeStyle("#aaa")
.lineWidth(4)
.antialias(true);
vis.add(pv.Image)
.imageWidth(w)
.imageHeight(h)
.image(pv.Scale.linear()
.domain(0, 99, 100)
.range("#000", "#fff", '#ff0a0a')
.by(function(i, j) heatmap[a][j][i]));
vis.render();
}
</script>
</body>
</html>
私はあなたがもう十分に行くことができると確信しています、しかし私は助けることができませんk平均クラスタリング方法を使うことを提案します。 k-meansは教師なしのクラスタリングアルゴリズムで、データを(任意の次元で - 私はこれを3Dで行います)受け取り、それを明確な境界を持つk個のクラスタに配置します。あなたがこれらの犬歯が持っているべきである(正確に)つま先を正確に知っているので、それはここで素晴らしいです。
さらに、それはScipyで実装されていて、本当に素晴らしいです(http://docs.scipy.org/doc/scipy/reference/cluster.vq.html)
3Dクラスタを空間的に解決するために何ができるかの例を示します。
あなたがやりたいことは少し異なります(2Dと圧力値を含みます)、しかし私はまだあなたがそれに打撃を与えることができると思います。
物理学者の解決策:
位置によって識別される5つの足跡マーカーを定義しますX_i
そしてそれらをランダムな位置で開始します。
足の位置におけるマーカーの位置に対するいくつかの賞とマーカーの重なりに対するいくつかの罰を組み合わせて、いくつかのエネルギー関数を定義する。まあ言ってみれば:
E(X_i;S)=-Sum_i(S(X_i))+alfa*Sum_ij (|X_i-Xj|<=2*sqrt(2)?1:0)
(S(X_i)
2×2平方あたりの平均力X_i
、alfa
実験的にピークになるパラメータです。
今度はMetropolis-Hastingsの魔法をやる時間です。
1.ランダムマーカーを選択し、ランダムな方向に1ピクセル移動します。
2.この移動が引き起こしたエネルギーの差であるdEを計算します。
3. 0から1までの一様乱数を得て、それをrと呼ぶ。
4.もしdE<0
またはexp(-beta*dE)>r
移動を受け入れて1に進む。そうでない場合は、移動を元に戻して1に進みます。
マーカーが足に収束するまでこれを繰り返します。 Betaはスキャンを最適化するトレードオフを制御するので、実験的にも最適化されるべきです。それはまたシミュレーション(シミュレーテッドアニーリング)の時間と共に絶えず増加することができる。
大きな望遠鏡で似たようなことをするときに私が使った別のアプローチがあります。
1)最高のピクセルを探します。 それができたら、2x2に最適なものを探すために(おそらく2x2の合計を最大にするために)それを検索するか、または最高のピクセルを中心にして4x4のサブ領域の内側に2dガウスフィットを行います。
それからあなたが見つけたそれらの2x2ピクセルをピーク中心の周りにゼロ(あるいは多分3x3)に設定してください
1)に戻り、最も高いピークがノイズしきい値を下回るまで繰り返すか、必要なつま先がすべてあります
トレーニングデータを作成できる場合は、おそらくニューラルネットワークで試してみる価値があります。ただし、これには手作業で注釈を付けた多くのサンプルが必要です。
大まかな概要...
あなたはおそらく各足領域を分離するためにコネクテッドコンポーネントアルゴリズムを使用したいと思うでしょう。 wikiはこれについての適切な説明を(いくつかのコードと共に)ここに持っています:http://en.wikipedia.org/wiki/Connected_Component_Labeling
4つか8つの関連性を使用するかどうかについて決定する必要があります。個人的には、ほとんどの問題で私は6連結性を好む。とにかく、各「足跡」をつながった領域として分離したら、その領域を繰り返し処理して最大値を見つけるのは簡単なはずです。最大値を見つけたら、それを特定の「つま先」として識別するために、あらかじめ決められたしきい値に達するまで領域を繰り返し拡大することができます。
ここで微妙な問題は、コンピュータビジョン技術を使用して何かを右/左/前/後足として識別し始め、個々のつま先を見始めるとすぐに、回転、スキュー、および並進を考慮に入れなければならないことです。これはいわゆる「モーメント」の分析によって達成されます。ビジョンアプリケーションで考慮すべきいくつかの異なる瞬間があります。
中心的な瞬間:翻訳不変 正規化モーメント:スケーリングと並進不変量 モーモーメント:並進、スケール、回転不変
モーメントに関するより多くの情報は、ウィキで "image moment"を検索することで見つけることができます。
おそらくあなたはGaussian Mixture Modelsのようなものを使うことができます。これはGMMをするためのPythonパッケージです(ちょうどグーグル検索をしました)。http://www.ar.media.kyoto-u.ac.jp/members/david/softwares/em/
さて、ここにいくつかの単純でひどく効率的でないコードがあります、しかしデータセットのこのサイズのためにそれは問題ありません。
import numpy as np
grid = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0.4,0.4,0.4,0,0,0],
[0,0,0,0,0.4,1.4,1.4,1.8,0.7,0,0,0,0,0],
[0,0,0,0,0.4,1.4,4,5.4,2.2,0.4,0,0,0,0],
[0,0,0.7,1.1,0.4,1.1,3.2,3.6,1.1,0,0,0,0,0],
[0,0.4,2.9,3.6,1.1,0.4,0.7,0.7,0.4,0.4,0,0,0,0],
[0,0.4,2.5,3.2,1.8,0.7,0.4,0.4,0.4,1.4,0.7,0,0,0],
[0,0,0.7,3.6,5.8,2.9,1.4,2.2,1.4,1.8,1.1,0,0,0],
[0,0,1.1,5,6.8,3.2,4,6.1,1.8,0.4,0.4,0,0,0],
[0,0,0.4,1.1,1.8,1.8,4.3,3.2,0.7,0,0,0,0,0],
[0,0,0,0,0,0.4,0.7,0.4,0,0,0,0,0,0]])
arr = []
for i in xrange(grid.shape[0] - 1):
for j in xrange(grid.shape[1] - 1):
tot = grid[i][j] + grid[i+1][j] + grid[i][j+1] + grid[i+1][j+1]
arr.append([(i,j),tot])
best = []
arr.sort(key = lambda x: x[1])
for i in xrange(5):
best.append(arr.pop())
badpos = set([(best[-1][0][0]+x,best[-1][0][1]+y)
for x in [-1,0,1] for y in [-1,0,1] if x != 0 or y != 0])
for j in xrange(len(arr)-1,-1,-1):
if arr[j][0] in badpos:
arr.pop(j)
for item in best:
print grid[item[0][0]:item[0][0]+2,item[0][1]:item[0][1]+2]
基本的には、左上の位置と2 x 2の各正方形の合計を使って配列を作成し、その合計で並べ替えます。それから私は最大の合計を持つ2x2の正方形を競合から外し、それをbest
配列を作成し、この部分を使用していた他のすべての2 x 2の正方形を削除します。
最後の足(あなたの最初の写真の一番右にある合計が最も小さいもの)を除いてはうまくいくようですが、より大きな合計を持つ2つの2x2平方の適格な正方形があることがわかります。お互い)。そのうちの1つはまだあなたの2x2の正方形から1つの正方形を選択していますが、もう一方は左側にありません。幸いなことに、幸運にも私たちはあなたが望むものをもっと選択しているように見えますが、これはあなたがいつも欲しいものを得るために他のアイデアを使う必要があるかもしれません。
それはあなたがjetxeeのアルゴリズムを使って少しカンニングすることができるようです。彼は最初の3本のつま先を問題なく見つけています、そしてあなたは4本目がそれに基づいているところを推測できるはずです。
面白い問題です。私がしようとする解決策は以下の通りです。
2Dガウスマスクとの畳み込みなどのローパスフィルタを適用します。これはあなたに(おそらく、必ずしも浮動小数点ではない)値の束を与えるでしょう。
各足パッド(またはつま先)の既知のおおよその半径を使用して、2Dの最大ではない抑制を実行します。
これは、互いに近い複数の候補を持つことなくあなたに最大のポジションを与えるべきです。明確にするために、ステップ1のマスクの半径もステップ2で使用した半径と同じである必要があります。この半径は選択可能であるか、獣医が事前に明示的に測定できます(年齢/品種などによって異なります)。
提案された解決策のいくつか(平均シフト、ニューラルネットなど)はおそらくある程度うまくいくでしょうが、過度に複雑で、おそらく理想的ではありません。
pythonを使って画像の中で極大値を見つけるための素晴らしいオプションがあることを皆さんに伝えたいのです。
from skimage.feature import peak_local_max
またはskimage 0.8.0用
from skimage.feature.peak import peak_local_max
http://scikit-image.org/docs/0.8.0/api/skimage.feature.peak.html
たぶんここで素朴なアプローチで十分です:あなたの平面上のすべての2x2の正方形のリストを作り、それらを合計して(降順で)順序付けます。
まず、あなたの "足のリスト"に最も高い値の正方形を選択してください。次に、以前に見つかった正方形のいずれとも交差しない次善の正方形のうちの4つを繰り返し選択します。
ステップバイステップで進むとどうなりますか:最初に大域的最大値を見つけ、必要に応じて周囲の点にその値を与えて処理し、次に見つかった領域をゼロに設定し、次の点に対して繰り返します。
これが質問に答えているかどうかはわかりませんが、隣接していない最も高いn個のピークを探すことができるようです。
要点はここにあります。これはRubyの中にあることに注意してください、しかしその考えははっきりしているはずです。
require 'pp'
NUM_PEAKS = 5
NEIGHBOR_DISTANCE = 1
data = [[1,2,3,4,5],
[2,6,4,4,6],
[3,6,7,4,3],
]
def tuples(matrix)
tuples = []
matrix.each_with_index { |row, ri|
row.each_with_index { |value, ci|
tuples << [value, ri, ci]
}
}
tuples
end
def neighbor?(t1, t2, distance = 1)
[1,2].each { |axis|
return false if (t1[axis] - t2[axis]).abs > distance
}
true
end
# convert the matrix into a sorted list of tuples (value, row, col), highest peaks first
sorted = tuples(data).sort_by { |tuple| tuple.first }.reverse
# the list of peaks that don't have neighbors
non_neighboring_peaks = []
sorted.each { |candidate|
# always take the highest peak
if non_neighboring_peaks.empty?
non_neighboring_peaks << candidate
puts "took the first peak: #{candidate}"
else
# check that this candidate doesn't have any accepted neighbors
is_ok = true
non_neighboring_peaks.each { |accepted|
if neighbor?(candidate, accepted, NEIGHBOR_DISTANCE)
is_ok = false
break
end
}
if is_ok
non_neighboring_peaks << candidate
puts "took #{candidate}"
else
puts "denied #{candidate}"
end
end
}
pp non_neighboring_peaks