2D 어레이에서 피크 검출


874

나는 개 발 아래 압력을 측정하는 동물 병원을 돕고 있습니다. 데이터 분석에 Python을 사용하고 이제 발을 (해부) 하위 영역으로 나누려고 노력하고 있습니다.

나는 각 발의 2D 배열을 만들었습니다. 각 발은 시간이 지남에 따라 발에 의해로드 된 각 센서의 최대 값으로 구성됩니다. 다음은 한 발의 예입니다. Excel에서 '감지'할 영역을 그렸습니다. 이것들은 로컬 최대 값을 가진 센서 주위에 2 x 2 상자이며, 가장 큰 합계를 갖습니다.

대체 텍스트

그래서 나는 약간의 실험을 시도하고 단순히 각 열과 행의 최대 값을 찾기로 결정했습니다 (발 모양으로 인해 한 방향으로 볼 수 없음). 이것은 개별 발가락의 위치를 ​​상당히 잘 감지하는 것처럼 보이지만 인접한 센서를 표시합니다.

대체 텍스트

그렇다면 파이썬에이 최대 값 중 내가 원하는 최대 값을 알려주는 가장 좋은 방법은 무엇입니까?

참고 : 2x2 사각형은 별도의 발가락이어야하므로 겹쳐 질 수 없습니다!

또한 편의를 위해 2x2를 사용했지만 더 이상 고급 솔루션을 환영하지만, 저는 단순히 인간 운동 과학자이기 때문에 실제 프로그래머 나 수학자가 아니므로 간단하게 유지하십시오.

다음은 로드 할 수 있는 버전입니다np.loadtxt


결과

그래서 @jextee의 솔루션을 시도했습니다 (아래 결과 참조). 보시다시피, 앞발에서 매우 효과적이지만 뒷다리에서는 잘 작동하지 않습니다.

보다 구체적으로, 네 번째 발가락 인 작은 피크를 인식 할 수 없습니다. 이것은 현재 위치를 고려하지 않고 루프가 가장 낮은 값으로 하향 보인다는 사실에 내재되어 있습니다.

누구든지 @jextee의 알고리즘을 조정하여 4 번째 발가락도 찾을 수 있도록 알고 있습니까?

대체 텍스트

아직 다른 시험을 처리하지 않았으므로 다른 샘플을 제공 할 수 없습니다. 그러나 이전에 제공된 데이터는 각 발의 평균이었습니다. 이 파일은 플레이트와 접촉 한 순서대로 최대 9 발의 데이터를 가진 배열입니다.

이 이미지는 판 위에 공간적으로 어떻게 퍼져 있는지 보여줍니다.

대체 텍스트

최신 정보:

내가 관심있는 사람들을위한 블로그를 설정 하고 나는 원시 측정 모두와 스카이 드라이브 설정을 가지고있다. 더 많은 데이터를 요청하는 사람에게는 더 많은 힘이 필요합니다!


새로운 업데이트:

그래서 발 감지발 정렬 에 관한 질문에 대한 도움을 얻은 후에 마침내 모든 발에 대한 발가락 감지를 확인할 수있었습니다! 결과적으로, 그것은 내 자신의 예에서와 같은 크기의 발 외에는 잘 작동하지 않습니다. 뒤늦은 시각에서 2x2를 임의로 선택하는 것은 내 잘못입니다.

손톱이 발가락으로 인식되고 '발 뒤꿈치'가 너무 넓어서 두 번 인식됩니다!

대체 텍스트

발이 너무 커서 겹치지 않고 2x2 크기를 사용하면 발가락이 두 번 감지됩니다. 다른 방법으로, 작은 개에서는 종종 5 번째 발가락을 찾지 못합니다 .2x2 영역이 너무 커서 원인이되는 것 같습니다.

모든 측정에서 현재 솔루션을 시도한 후 거의 모든 작은 개에 대해 5 번째 발가락을 찾지 못했고 큰 개에 대한 영향의 50 % 이상에서 더 많은 것을 발견 할 수 있다는 놀라운 결론에 도달했습니다!

분명히 바꿔야합니다. 내 자신의 추측은 neighborhood작은 개의 경우 더 작고 큰 개의 경우 더 큰 것으로 크기를 변경하는 것입니다. 그러나 generate_binary_structure배열의 크기를 변경할 수는 없습니다.

따라서 다른 사람이 발가락 위치를 지정하는 데 더 나은 제안이 있기를 바라고 있습니다. 발 크기가 발가락 크기로되어 있습니까?


쉼표는 값 구분 기호가 아닌 소수점 이하 자릿수입니다.
MattH

예, 쉼표입니다. 그리고 @Christian, 나는 그것을 쉽게 읽을 수있는 파일에 붙이려 고 노력하고 있지만 그조차도 나에게 실패합니다 :(
Ivo Flipse

3
타당성 조사를 진행하면서 모든 것이 실제로 진행됩니다. 그래서 나는 소 지역을 포함하여 압력을 정의하는 많은 방법을 찾고 있습니다. 또한 오리엔테이션을 추정하기 위해 '빅토'와 '작은 토'를 구분할 수 있어야합니다. 그러나이 때문에 우리는 :-) 찾을 수 무슨 이야기가 없습니다, 이전에 수행하지 않은
이보 Flipse

2
@Ron :이 연구의 목표 중 하나는 시스템의 크기 / 무게가 적절한 지 확인하는 것입니다. 따라서이 개는 약 20kg이었습니다. 나는 상당히 작은 (그리고 더 큰) 일부를 가지고 있으며 실제 작은 것들에 대해 똑같이 할 수 없을 것이라고 기대합니다.
Ivo Flipse

2
@frank 발은 시간이 지남에 따라 측정되므로 3 차원입니다. 그러나, 그들은 (상대적으로 말하면) 자신의 자리에서 움직이지 않으므로 발가락이 2D로 어디에 위치하고 있는지에 관심이 있습니다. 그 후 3D 영상은 무료로 제공됩니다
Ivo Flipse

답변:


331

로컬 최대 필터를 사용하여 피크를 감지했습니다 . 4 발의 첫 번째 데이터 세트에 대한 결과는 다음과 같습니다. 피크 검출 결과

나는 또한 9 발의 두 번째 데이터 세트에서 그것을 실행했으며 잘 작동했습니다 .

방법은 다음과 같습니다.

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
(eroded_background ^ local_peaks)보다 간단한 해결책이 있습니다. 그냥 (전경 및 지역 피크) 할
라이언 Soklaski

53

해결책

데이터 파일 : 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"

사각형이 겹치지 않고 출력 됩니다. 귀하의 예에서와 동일한 영역이 선택된 것 같습니다.

일부 의견

까다로운 부분은 모든 2x2 제곱의 합을 계산하는 것입니다. 나는 당신이 그들 모두를 필요로한다고 가정 했으므로 약간 겹칠 수 있습니다. 슬라이스를 사용하여 원래 2D 배열에서 첫 번째 / 마지막 열과 행을 잘라낸 다음 모두 함께 겹쳐서 합계를 계산했습니다.

더 잘 이해하려면 3x3 배열을 이미징하십시오.

>>> 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]])

이제 그것들을 다른 것 위에 쌓고 같은 위치에 요소를 합산한다고 상상해보십시오. 이 합계는 왼쪽 위 모서리가 같은 위치에있는 2x2 정사각형에 대해 정확히 같은 합계입니다.

>>> sums = a[:-1,:-1] + a[1:,:-1] + a[:-1,1:] + a[1:,1:]; sums
array([[ 8, 12],
       [20, 24]])

합계가 2x2 제곱을 초과 max하면 최대 값 sort또는 sorted을 찾거나 피크를 찾는 데 사용할 수 있습니다 .

피크의 위치를 ​​기억하기 위해 모든 값 (합)을 평평한 배열의 서수 위치와 결합합니다 (참조 zip). 그런 다음 결과를 인쇄 할 때 행 / 열 위치를 다시 계산합니다.

노트

2x2 사각형이 겹치도록 허용했습니다. 편집 된 버전은 겹치지 않는 사각형 만 결과에 나타나도록 일부를 필터링합니다.

손가락 선택 (아이디어)

또 다른 문제는 모든 피크에서 손가락이 될 가능성을 선택하는 방법입니다. 작동하거나 작동하지 않을 수있는 아이디어가 있습니다. 지금 당장 구현할 시간이 없으므로 의사 코드 만 있습니다.

앞 손가락이 거의 완벽한 원 안에 있으면 뒷 손가락이 그 원 안에 있어야한다는 것을 알았습니다. 또한 앞쪽 손가락의 간격이 거의 동일합니다. 이러한 휴리스틱 속성을 사용하여 손가락을 감지하려고 할 수 있습니다.

의사 코드 :

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 가지 방법이 있으므로 모든 발에 대해 3960 개의 사례를 평가합니다.


그는 최대 값 6.8이 포함 된 2 × 2 사각형 구성하기 위해 그에게 네 가지 가능성을 줄 것이다 네 개의 맨 위의 결과를 따기 ... 당신의 결과 목록 제공, 수동으로 발을 필터링해야합니다
요하네스 차라

2x2 박스는 겹칠 수 없습니다. 통계를 원한다면 같은 지역을 사용하고 싶지 않기 때문에 지역을 비교하고 싶습니다 :-)
Ivo Flipse

나는 대답을 편집했다. 이제 결과에 겹치는 사각형이 없습니다.
sastanin

1
나는 그것을 시도했고 앞발에는 효과가있는 것처럼 보이지만 뒷발에는 덜 효과적입니다. 우리는 어디를보아야하는지 아는 무언가를 시도해야 할 것 같아요
Ivo Flipse

1
의사 코드에서 손가락을 감지하는 방법을 설명했습니다. 당신이 그것을 좋아한다면, 나는 내일 저녁에 그것을 구현하려고 할 수 있습니다.
sastanin

34

이것은 이미지 등록 문제 입니다. 일반적인 전략은 다음과 같습니다.

  • 알려진 예 또는 데이터에 대한 사전 이 있습니다.
  • 데이터를 예제에 맞추거나 예제를 데이터에 맞추십시오.
  • 데이터가 처음에 대략적으로 정렬 되면 도움이됩니다 .

다음은 거칠고 준비된 접근 방식입니다 .

  • 대략 원하는 위치에서 5 개의 발가락 좌표로 시작하십시오.
  • 각각이 반복적으로 언덕 꼭대기까지 올라갑니다. 즉, 현재 위치에서 주어진 값이 현재 픽셀보다 큰 경우 최대 인접 픽셀로 이동합니다. 발가락 좌표의 움직임이 멈 추면 멈 춥니 다.

방향 문제를 해결하기 위해 기본 방향 (북쪽, 북동쪽 등)에 대해 8 개 정도의 초기 설정을 지정할 수 있습니다. 각각을 개별적으로 실행하고 두 개 이상의 발가락이 같은 픽셀에서 끝나는 결과를 버리십시오. 나는 이것에 대해 더 생각할 것이지만, 이런 종류의 일은 여전히 ​​이미지 처리에 대해 연구되고 있습니다. 정답은 없습니다!

약간 더 복잡한 아이디어 : (가중치) K- 평균 군집. 그렇게 나쁘진 않네.

  • 5 개의 발가락 좌표로 시작하지만 이제는 "클러스터 센터"입니다.

그런 다음 수렴 될 때까지 반복하십시오.

  • 각 픽셀을 가장 가까운 클러스터에 할당하십시오 (각 클러스터에 대한 목록을 작성하십시오).
  • 각 군집의 질량 중심을 계산하십시오. 각 군집에 대해 Sum (좌표 * 강도 값) / Sum (좌표)입니다.
  • 각 클러스터를 새로운 질량 중심으로 이동하십시오.

이 방법은 거의 확실히 더 나은 결과를 제공하며 발가락을 식별하는 데 도움이 될 수있는 각 클러스터의 질량을 얻습니다.

(먼저 클러스터 수를 미리 지정했습니다. 클러스터링을 사용하면 밀도를 한 가지 방법으로 지정해야합니다.이 경우 적절한 클러스터 수를 선택하거나 클러스터 반경을 선택하고 종료 수를 확인하십시오. 후자의 예는 평균 이동 입니다.)

구현 세부 사항 또는 기타 세부 사항이 부족하여 죄송합니다. 코드를 작성했지만 마감일이 있습니다. 다음 주까지 다른 일이 없으면 알려 주시면 기회를 드리겠습니다.


1
문제는 발의 방향이 바뀌고 올바른 발의 교정 / 기준선이 없다는 것입니다. 또한 많은 이미지 인식 알고리즘이 제 리그에서 조금 벗어난 것 같습니다.
Ivo Flipse

"거칠고 준비된"접근 방식은 매우 간단합니다. 어쩌면 나는 그 아이디어를 잘 몰랐습니다. 설명하기 위해 의사 코드를 넣겠습니다.
CakeMaster

나는 당신의 제안이 뒷발의 인식을 고치는 데 도움이된다고 생각합니다. 나는 단지 '어떻게'를 모릅니다
Ivo Flipse

다른 아이디어를 추가했습니다. 그건 그렇고 좋은 데이터를 많이 가지고 있다면 온라인 어딘가에 배치하는 것이 좋습니다. 이미지 처리 / 기계 학습을 공부하는 사람들에게 유용 할 수 있으며 더 많은 코드를 얻을 수 있습니다 ...
CakeMaster

1
나는 단순히 Wordpress 블로그에 내 데이터 처리를 작성하려고 생각하고 있었는데, 단순히 다른 사람에게 유용하기 때문에 어쨌든 작성해야합니다. 나는 당신의 모든 제안을 좋아하지만 마감일이없는 누군가를 기다려야 할까 걱정합니다 ;-)
Ivo Flipse

18

지속적인 상 동성을 사용하여 데이터 세트를 분석하면 다음과 같은 결과가 나타납니다 (확대하려면 클릭하십시오).

결과

이것이이 SO 답변에 설명 된 피크 검출 방법의 2D 버전입니다 . 위 그림은 지속성에 따라 정렬 된 0 차원 영구 상 동성 클래스를 보여줍니다.

scipy.misc.imresize ()를 사용하여 원래 데이터 세트를 2 배로 업 스케일했습니다. 그러나 네 발을 하나의 데이터 집합으로 간주했습니다. 4 개로 나누면 문제가 더 쉬워집니다.

방법론. 이 매우 간단한 아이디어는 각 픽셀에 레벨을 할당하는 함수의 함수 그래프를 고려하십시오. 다음과 같이 보입니다 :

3D 함수 그래프

이제 높이 255의 수위가 지속적으로 낮아지는 수위를 고려하십시오. 지역 최대 섬에서 팝업 (출생). 안장 지점에서 두 개의 섬이 합쳐집니다. 우리는 더 낮은 섬이 더 높은 섬 (죽음)과 합쳐지는 것을 고려합니다. 소위 지속성 다이어그램 (우리 섬의 0 차원 상 동성 등급)은 모든 섬의 사망률을 나타냅니다.

지속성 다이어그램

섬 의 지속성 은 출생 수준과 죽음 수준의 차이입니다. 회색 주 대각선에 대한 점의 수직 거리 이 그림은 지속성을 감소시켜 섬을 표시합니다.

첫 번째 그림은 섬의 출생지입니다. 이 방법은 국소 최대 값을 제공 할뿐만 아니라 위에서 언급 한 지속성에 의해 "의미"를 정량화합니다. 그런 다음 지속성이 너무 낮은 모든 섬을 필터링합니다. 그러나 귀하의 예에서 모든 섬 (즉, 모든 지역 최대)은 원하는 피크입니다.

파이썬 코드는 여기 에서 찾을 수 있습니다 .


16

이 문제는 물리학 자에 의해 어느 정도 깊이 연구되었습니다. ROOT 에는 좋은 구현이 있습니다 . 상기 봐 TSpectrum의 클래스 (특히 TSpectrum2 사건에 대한) 그들에 대한 설명서.

참고 문헌 :

  1. M.Morhac 등 : 다차원 일치 감마선 스펙트럼의 배경 제거 방법. 물리학 연구 A 401 (1997) 113-132의 핵기구 및 방법.
  2. M.Morhac et al .: 효율적인 1 차원 및 2 차원 금 deconvolution 및 감마선 스펙트럼 분해에 적용. 물리학 연구 A 401 (1997) 385-408에있는 핵기구 및 방법.
  3. M.Morhac et al .: 다차원 일치 감마선 스펙트럼에서 피크 식별. 연구 물리학의 핵기구 및 방법 A 443 (2000), 108-125.

... 그리고 NIM 구독이없는 사람들을 위해 :


이 기사를 살펴보면 여기에서 시도하는 것과 동일한 데이터 처리를 설명하는 것 같지만 프로그래밍 기술을 크게 능가하는 것으로 보입니다. (
Ivo Flipse

@ Ivo : 나는 그것을 직접 구현하려고 시도하지 않았습니다. 나는 단지 루트를 사용합니다. 그럼에도 불구하고 파이썬 바인딩이 있지만 ROOT는 꽤 무거운 패키지입니다.
dmckee --- ex-moderator 고양이

@Ivo Flipse : dmckee에 동의합니다. 다른 답변에 유망한 리드가 많이 있습니다. 그들 모두가 실패하고 시간을 투자하고 싶다고 느끼면 ROOT를 탐구 할 수 있으며 아마도 필요한 것을 할 것입니다. 나는 자연스럽게 C ++이 아닌 파이썬 바인딩을 통해 ROOT를 배우려고 한 사람을 결코 알지 못했기 때문에 운이 좋기를 바랍니다.
물리학 Michael

13

아이디어는 다음과 같습니다. 이미지의 (이산적인) 라플라시안을 계산합니다. 나는 그것이 원래 이미지보다 더 극적인 방식으로 최대에서 (부정적이고) 클 것으로 기대합니다. 따라서 최대 값을 찾기가 더 쉬울 수 있습니다.

또 다른 아이디어는 다음과 같습니다. 고압 스폿의 일반적인 크기를 알고 있다면 먼저 동일한 크기의 가우시안으로 이미지를 변환하여 이미지를 부드럽게 할 수 있습니다. 이렇게하면 처리하기 더 간단한 이미지를 얻을 수 있습니다.


11

내 머리 위로 몇 가지 아이디어가 있습니다.

  • 스캔의 기울기 (파생)를 취하여 잘못된 호출을 제거하는지 확인하십시오.
  • 극댓값을 최대한 활용하다

OpenCV를 살펴보고 싶을 수도 있지만 꽤 괜찮은 Python API가 있으며 유용한 기능이있을 수 있습니다.


그래디언트를 사용하면 경사의 가파른 정도를 계산해야합니다.이 값이 특정 값을 초과하면 '피크'가 있음을 알고 있습니까? 나는 이것을 시도했지만 일부 발가락은 다른 것 (8 N / cm)에 비해 매우 낮은 피크 (1.2 N / cm) 만 가지고 있습니다. 그렇다면 매우 낮은 기울기로 피크를 어떻게 처리해야합니까?
Ivo Flipse

2
그라디언트를 직접 사용할 수 없다면 과거에 효과가 있었던 것은 그라디언트와 최대 값을 보는 것입니다. 관심.
ChrisC

11

지금까지는 충분하다고 확신하지만 k- 평균 군집화 방법을 사용하는 것이 좋습니다. k- 평균은 감독되지 않은 클러스터링 알고리즘으로, 데이터를 임의의 수의 차원으로 가져 와서 (3D에서이 작업을 수행함) 명확한 경계를 갖는 k 개의 클러스터로 배열합니다. 이 개들이 가지고있는 발가락의 수를 정확히 알고 있기 때문에 여기가 좋습니다.

또한 Scipy에서 구현되어 정말 좋습니다 ( http://docs.scipy.org/doc/scipy/reference/cluster.vq.html ).

3D 클러스터를 공간적으로 해결하기 위해 수행 할 수있는 작업의 예는 다음과 같습니다. 여기에 이미지 설명을 입력하십시오

당신이하고 싶은 것은 약간 다릅니다 (2D 및 압력 값 포함).하지만 여전히 샷을 줄 수 있다고 생각합니다.


10

원시 데이터에 감사드립니다. 나는 기차에 올라 탔다. 정규식으로 txt 파일을 마사지하고 시각화를 위해 일부 자바 스크립트가있는 html 페이지에 넣었습니다. 나처럼 일부는 파이썬보다 쉽게 ​​해킹 할 수 있기 때문에 여기에서 공유하고 있습니다.

나는 좋은 접근 방식이 스케일과 회전 불변성이 될 것이라고 생각하며, 다음 단계는 가우스 혼합을 조사하는 것입니다. (각 발 패드는 가우시안의 중심 임).

    <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>

대체 텍스트


1
나는이 권장 가우스 기술은 사람이 ;-) 파이썬을 증명할 수 해주기 경우 일 수 있다는 개념의 증거라고 생각한다
이보 Flipse

8

물리학 자의 해결책 :
자신의 위치로 식별되는 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. 랜덤 마커를 선택하고 랜덤 방향으로 한 픽셀 씩 이동하십시오.
2.이 움직임으로 인한 에너지의 차이 인 dE를 계산합니다.
3. 0-1에서 균일 한 난수를 구하여 r이라고 부릅니다.
4. dE<0또는 exp(-beta*dE)>r인 경우 이동을 승인하고 1로 이동하십시오. 그렇지 않으면 이동을 취소하고 1로 가십시오
. 마커가 발에 수렴 할 때까지이 과정을 반복해야합니다. 베타는 검색을 최적화하여 트레이드 오프를 최적화하므로 실험적으로 최적화해야합니다. 시뮬레이션 시간 (시뮬레이션 어닐링)에 따라 지속적으로 증가 할 수도 있습니다.


이것이 내 예에서 어떻게 작동하는지 보여줄 수 있습니까? 나는 이미 :( 제안 공식 해명 힘든 시간을 가지고, 그래서 내가, 높은 수준의 수학에 정말 아니에요로
이보 Flipse을

1
이것은 고등학교 수학입니다. 아마도 내 표기법은 난독 화되었을 것입니다. 확인할 계획이 있으니 계속 지켜봐 주시기 바랍니다.
mbq

4
저는 입자 물리학 자입니다. 오랫동안 우리 학문에서 사용하는 소프트웨어 도구는 PAW라고하며 "마커"라는 그래프와 관련된 엔티티가있었습니다. 나는 주위 시대의 첫 번째 커플이 대답을 발견하는 방법을 혼동 당신은 ... 상상할 수
dmckee --- 전 사회자 고양이

6

다음은 대형 망원경과 비슷한 것을 할 때 사용했던 또 다른 접근법입니다.

1) 가장 높은 픽셀을 검색하십시오. 일단 그것을 찾으면 2x2에 가장 잘 맞는지 (2x2 합계를 최대화 할 수 있음)를 검색하거나 가장 높은 픽셀을 중심으로 4x4의 하위 영역 내에서 2d 가우스 맞춤을 수행하십시오.

그런 다음 피크 중심 주위에서 찾은 2x2 픽셀을 0 또는 3x3으로 설정하십시오.

1)로 돌아가서 가장 높은 피크가 노이즈 임계 값 아래로 떨어질 때까지 반복하거나 필요한 모든 발가락을 갖습니다.


이 작업을 수행하는 코드 예제를 공유 하시겠습니까? 난 당신이 뭘 하려는지에 따라,하지만 어떻게 코드를 그 자신 아무 생각이 없다
이보 Flipse

나는 실제로 Matlab과 함께 일했기 때문에 이미 도움이 될 것입니다. 그러나 정말로 외국 함수를 사용한다면 파이썬으로 복제하기가 어려울 수 있습니다.
Ivo Flipse

6

훈련 데이터를 만들 수 있다면 신경망으로 시도해 볼 가치가있을 것입니다. 그러나 여기에는 수작업으로 주석이 달린 많은 샘플이 필요합니다.


문제가 될만한 가치가 있다면, 큰 샘플에 손으로 주석을 달지 않아도됩니다. 내 문제는 : 신경망 프로그래밍에 대해 아무것도 모르기 때문에 어떻게 구현합니까?
Ivo Flipse

6

대략적인 개요 ...

연결된 구성 요소 알고리즘을 사용하여 각 발 영역을 분리하려고합니다. wiki는 이에 대한 적절한 설명이 있습니다 (일부 코드 포함) : http://en.wikipedia.org/wiki/Connected_Component_Labeling

4 개 또는 8 개의 연결을 사용할지 여부를 결정해야합니다. 개인적으로, 대부분의 문제는 6- 연결성을 선호합니다. 어쨌든, 각 "발자국"을 연결된 영역으로 분리 한 후에는 영역을 반복하고 최대 값을 찾을 수있을 정도로 쉬워야합니다. 최대 값을 찾은 후 지정된 "발가락"으로 식별하기 위해 미리 정해진 임계 값에 도달 할 때까지 영역을 반복적으로 확대 할 수 있습니다.

여기서 미묘한 문제 중 하나는 컴퓨터 비전 기술을 사용하여 무언가를 오른쪽 / 왼쪽 / 앞 / 뒤 발로 식별하고 개별 발가락을보기 시작하자마자 회전, 기울기 및 변환을 고려해야한다는 것입니다. 이것은 소위 "순간"의 분석을 통해 달성됩니다. 비전 애플리케이션에서 고려해야 할 몇 가지 순간이 있습니다.

중심 모멘트 : 변환 불변 정규화 된 모멘트 : 스케일링 및 변환 불변 hu 모멘트 : 변환, 스케일 및 회전 불변

순간에 대한 자세한 정보는 위키에서 "이미지 순간"을 검색하여 찾을 수 있습니다.



4

jetxee의 알고리즘을 사용하여 약간의 부정 행위를 할 수있는 것 같습니다. 그는 처음 세 발가락을 잘 찾아 내고 있으며, 네 번째 부분이 어디인지 추측 할 수있을 것입니다.


4

재미있는 문제. 내가 시도하는 해결책은 다음과 같습니다.

  1. 2D 가우스 마스크를 사용한 컨볼 루션과 같은 저역 통과 필터를 적용하십시오. 이것은 당신에게 (아마도 부동 소수점 일 필요는 없지만) 많은 값을 줄 것입니다.

  2. 알려진 각 발 패드 (또는 발가락)의 대략적인 반경을 사용하여 2D 비 최대 억제를 수행하십시오.

이렇게하면 서로 가까운 여러 후보자가 없어도 최대 위치를 얻을 수 있습니다. 명확히하기 위해, 1 단계에서 마스크의 반경은 2 단계에서 사용 된 반경과 유사해야합니다.이 반경을 선택할 수 있거나 수의사가 미리 명시 적으로 측정 할 수 있습니다 (연령 / 품종 등에 따라 다름).

제안 된 솔루션 중 일부 (평균 이동, 신경망 등)는 어느 정도 작동하지만 지나치게 복잡하고 이상적이지 않을 수 있습니다.


컨볼 루션 행렬 및 가우시안 필터에 대한 경험이 0이므로 내 예제에서 어떻게 작동하는지 보여 주겠습니까?
Ivo Flipse

3

글쎄, 여기에 간단하고 굉장히 효율적인 코드가 있지만,이 크기의 데이터 세트에는 괜찮습니다.

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]

기본적으로 왼쪽 위의 위치와 각 2x2 사각형의 합으로 배열을 만들고 합으로 정렬합니다. 그런 다음 경쟁에서 가장 높은 합계를 가진 2x2 정사각형을 가져 와서 best배열에 넣고 방금 제거 한 2x2 정사각형의 일부를 사용하는 다른 2x2 정사각형을 제거하십시오.

마지막 앞발 (첫 번째 그림에서 가장 오른쪽에 가장 작은 합계가있는 것)을 제외하고는 잘 작동하는 것 같습니다. 서로). 그중 하나는 여전히 2x2 사각형에서 하나의 사각형을 선택하지만 다른 하나는 왼쪽에서 꺼져 있습니다. 운 좋게도, 우리는 당신이 원하는 것을 더 많이 선택하는 것을 볼 수 있지만, 이것은 실제로 당신이 실제로 원하는 것을 얻기 위해 다른 아이디어를 사용해야 할 수도 있습니다.


귀하의 결과는 @Jextee의 답변과 동일하다고 생각합니다. 또는 적어도 내가 테스트 한 것 같습니다.
Ivo Flipse


1

아마도 순진한 접근 방식으로 충분할 수도 있습니다. 비행기에서 모든 2x2 사각형의 목록을 작성하고 합계를 내림차순으로 정렬하십시오.

먼저 "발 목록"에서 가장 높은 값의 사각형을 선택하십시오. 그런 다음 이전에 찾은 사각형과 교차하지 않는 다음 최고 사각형 중 4 개를 반복해서 선택합니다.


나는 실제로 모든 2x2 합계로 목록을 만들었지 만 주문했을 때 반복적으로 비교하는 방법을 알지 못했습니다. 내 문제는 정렬 할 때 좌표를 잃어 버렸다는 것입니다. 아마도 좌표를 키로 사용하여 사전에 붙일 수 있습니다.
Ivo Flipse

그렇습니다. 사전이 필요합니다. 그리드의 표현은 이미 일종의 사전이라고 가정했을 것입니다.
Johannes Charra

위의 이미지는 numpy 배열입니다. 나머지는 현재 다차원 목록에 저장됩니다. 사전을 반복하는 것에 익숙하지는 않지만 그 일을 중단하는 것이 좋습니다.
Ivo Flipse

1

천문학 및 우주론 커뮤니티에서 제공하는 여러 가지 광범위한 소프트웨어가 있습니다. 이것은 역사적으로나 현재 중요한 연구 분야입니다.

천문학자가 아닌 경우 놀라지 마십시오. 일부는 현장 밖에서 사용하기 쉽습니다. 예를 들어, astropy / photutils를 사용할 수 있습니다.

https://photutils.readthedocs.io/en/stable/detection.html#local-peak-detection

[여기에서 짧은 샘플 코드를 반복하는 것은 약간 무례한 것 같습니다.]

관심이있을 수있는 불완전하고 약간 편향 된 기술 / 패키지 / 링크 목록은 아래에 나와 있습니다. 의견을 더 추가하면이 답변을 필요에 따라 업데이트 할 것입니다. 물론 정확성과 계산 리소스의 균형이 있습니다. [정직하게도 이와 같은 단일 답변으로 코드 예제를 제공하기에는 너무 많아서이 답변이 날지 여부는 확실하지 않습니다.]

소스 추출기 https://www.astromatic.net/software/sextractor

MultiNest https://github.com/farhanferoz/MultiNest [+ pyMultiNest]

ASKAP / EMU 소스 찾기 과제 : https://arxiv.org/abs/1509.03931

Planck 및 / 또는 WMAP 소스 추출 문제를 검색 할 수도 있습니다.

...


0

단계별로 진행하는 경우 : 먼저 전역 최대 값을 찾고 필요한 경우 주변 지점에 해당 값이 주어진 경우 처리 한 다음 찾은 영역을 0으로 설정하고 다음 영역에 대해 반복하십시오.


음, 0으로 설정하면 추가 계산에서 적어도 제거 할 수 있으므로 유용합니다.
Ivo Flipse

0으로 설정하는 대신 직접 선택한 매개 변수로 가우스 함수를 계산하고 원래 압력 판독 값에서 찾은 값을 뺍니다. 따라서 발가락이 센서를 누르는 경우 가장 높은 누르는 점을 찾아서 해당 발가락이 센서에 미치는 영향을 줄임으로써 높은 압력 값을 가진 인접 셀을 제거합니다. en.wikipedia.org/wiki/File:Gaussian_2d.png
Daniyar

내 샘플 데이터 @Daniyar를 기반으로 한 예를 보여 주겠습니까? 나는 데이터 처리 같은 종류 정말 익숙하지 않은 해요로
이보 Flipse

0

이것이 질문에 대한 대답인지 확실하지 않지만 이웃이없는 n 개의 최고 봉우리를 찾을 수있는 것처럼 보입니다.

요점은 다음과 같습니다. 루비에 있지만 아이디어는 분명해야합니다.

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

나는 시도하고 모양과 내가 :-) 파이썬 코드로 변환 할 수 있는지거야
이보 Flipse

길이가 적당한 경우 요지에 연결하지 말고 게시물 자체에 코드를 포함 시키십시오.
agf
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.