Programing

발을 정렬하는 방법?

crosscheck 2020. 7. 16. 08:13
반응형

발을 정렬하는 방법?


에서 내 앞의 질문 나는 훌륭한 답변을 얻었다 앞발이 압력 판을 칠 경우 나 감지 도움이,하지만 지금은 그에 상응하는 발에이 결과를 링크 사투를 벌인거야 :

대체 텍스트

발에 수동으로 주석을 달았습니다 (RF = 오른쪽 앞, RH = 오른쪽 뒷, LF = 왼쪽 앞, LH = 왼쪽 뒷).

보시다시피 반복되는 패턴이 있으며 거의 ​​모든 측정에서 다시 나타납니다. 다음은 수동으로 주석이 달린 6 개의 평가판 프레젠테이션에 대한 링크입니다.

내 생각은 다음과 같이 휴리스틱을 사용하여 정렬을 수행하는 것이 었습니다.

  • 앞발과 뒷발 사이에 무게 베어링의 ~ 60-40 % 비율이 있습니다.
  • 뒷발은 일반적으로 표면이 더 작습니다.
  • 발은 (종종) 공간적으로 왼쪽과 오른쪽으로 나뉩니다.

그러나 나는 휴리스틱에 대해 약간 회의적입니다. 왜냐하면 생각하지 않은 변형이 발생하자마자 실패 할 것입니다. 그들은 또한 자신의 규칙을 가지고있는 절름발이 강아지의 측정에 대처할 수 없습니다.

또한 Joe가 제안한 주석이 때때로 엉망이되어 발이 실제로 어떻게 보이는지 고려하지 않습니다.

발 내 피크 검출에 대한 내 질문에 대한 답변을 바탕으로 을 정렬하는 더 고급 솔루션이 있기를 바랍니다. 특히, 압력 분포 및 이의 진행이 지문과 같이 각각의 개별 발마다 상이하기 때문에. 발을 발생 순서대로 정렬하는 대신 발을 묶는 데 사용할 수있는 방법이 있기를 바랍니다.

대체 텍스트

그래서 결과를 해당 발로 정렬하는 더 좋은 방법을 찾고 있습니다.

도전에 직면 한 사람이라면, 각 발의 압력 데이터 (측정으로 묶음)와 위치 (플레이트의 위치 및 시간) 를 설명하는 슬라이스가 포함 된 모든 슬라이스 배열 로 사전절인했습니다 .

명확하게하기 위해 : walk_sliced_data는 측정 이름 인 [ 'ser_3', 'ser_2', 'sel_1', 'sel_2', 'ser_1', 'sel_3']을 포함하는 사전입니다. 각 측정에는 추출 된 영향을 나타내는 다른 사전 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] (예 : 'sel_1')이 포함됩니다.

또한 발이 부분적으로 측정되는 위치 (공간 또는 시간)와 같은 '거짓'영향은 무시할 수 있습니다. 패턴 인식에 도움이 될 수 있지만 분석 할 수 없기 때문에 유용합니다.

그리고 관심있는 사람 은 프로젝트에 관한 모든 업데이트를 블로그에 보관하고 있습니다!


좋구나! 나는 마침내 일관되게 작동하는 것을 얻었습니다! 이 문제는 며칠 동안 나를 끌어 들였다 ... 재미있는 것들! 이 답변의 길이에 대해 죄송하지만 몇 가지 사항을 자세히 설명해야합니다 ... (스팸이 아닌 가장 긴 스택 오버플로 답변에 대한 레코드를 설정할 수는 있습니다!)

참고로, Ivo 원래 질문 에서 링크를 제공 한 전체 데이터 세트를 사용하고 있습니다. 각각 ascii 배열로 저장된 여러 실험 실행을 포함하는 일련의 rar 파일 (개당 1 개)입니다. 독립형 코드 예제를이 질문에 복사하여 붙여 넣는 대신 완전한 독립형 코드 가 포함 된 비트 버킷 수은 저장소 가 있습니다. 당신은 그것을 복제 할 수 있습니다

hg clone https://joferkington@bitbucket.org/joferkington/paw-analysis


개요

질문에서 언급했듯이 본질적으로 문제에 접근하는 두 가지 방법이 있습니다. 실제로 다른 방법으로 두 가지를 모두 사용하려고합니다.

  1. 발 충격의 (시간적 및 공간적) 순서를 사용하여 어느 발이 어느 발인지 결정하십시오.
  2. 모양에 따라 "발자국"을 찾아보십시오.

기본적으로 첫 번째 방법은 강아지의 발에 위의 Ivo의 질문에 표시된 사다리꼴 같은 패턴을 따르지만 발이 해당 패턴을 따르지 않으면 실패합니다. 작동하지 않을 때 프로그래밍 방식으로 쉽게 감지 할 수 있습니다.

따라서, 우리는 어느 발이 어느 발인지 인식하기 위해 훈련 데이터 세트 (~ 30 개의 다른 개로부터 ~ 2000 발의 충격)를 구축하기 위해 수행 한 측정을 사용할 수 있으며 문제는 감독 된 분류 (일부 주름 추가)로 줄어 듭니다. .. 이미지 인식은 "일반적인"감독 분류 문제보다 약간 어렵습니다.


패턴 분석

첫 번째 방법을 자세히 설명하기 위해 개가 정상적으로 걷지 않을 때 (일부 개는 그렇지 않을 수 있음) 앞발 왼쪽, 뒷쪽 오른쪽, 앞 오른쪽, 뒷 왼쪽 순서로 발이 영향을 줄 것으로 예상됩니다. , Front Left 등. 패턴은 앞 왼쪽 또는 앞 오른쪽 앞발로 시작할 수 있습니다.

이것이 항상 사실이라면, 우리는 단순히 초기 접촉 시간에 따라 영향을 분류하고 모듈로 4를 사용하여 발로 그룹화 할 수 있습니다.

정상적인 영향 시퀀스

그러나 모든 것이 "정상"인 경우에도 작동하지 않습니다. 이것은 사다리꼴 모양의 패턴 때문입니다. 뒷발은 공간적으로 이전 앞발 뒤에 떨어진다.

따라서 초기 앞발 충격 후 뒷발 충격은 종종 센서 플레이트에서 떨어져 기록되지 않습니다. 유사하게, 마지막 발 충격은 종종 센서 플레이트에서 발생하기 전에 발 충격이 기록되지 않았기 때문에 시퀀스의 다음 발이 아니다.

놓친 뒷발

그럼에도 불구하고, 우리는 발 충격 패턴의 모양을 사용하여 언제 이런 일이 발생했는지, 그리고 왼쪽 발 또는 오른쪽 앞발로 시작했는지 여부를 결정할 수 있습니다. (실제로 마지막 영향과 관련된 문제는 무시하고 있습니다. 추가하기는 어렵지 않습니다.)

def group_paws(data_slices, time):   
    # Sort slices by initial contact time
    data_slices.sort(key=lambda s: s[-1].start)

    # Get the centroid for each paw impact...
    paw_coords = []
    for x,y,z in data_slices:
        paw_coords.append([(item.stop + item.start) / 2.0 for item in (x,y)])
    paw_coords = np.array(paw_coords)

    # Make a vector between each sucessive impact...
    dx, dy = np.diff(paw_coords, axis=0).T

    #-- Group paws -------------------------------------------
    paw_code = {0:'LF', 1:'RH', 2:'RF', 3:'LH'}
    paw_number = np.arange(len(paw_coords))

    # Did we miss the hind paw impact after the first 
    # front paw impact? If so, first dx will be positive...
    if dx[0] > 0: 
        paw_number[1:] += 1

    # Are we starting with the left or right front paw...
    # We assume we're starting with the left, and check dy[0].
    # If dy[0] > 0 (i.e. the next paw impacts to the left), then
    # it's actually the right front paw, instead of the left.
    if dy[0] > 0: # Right front paw impact...
        paw_number += 2

    # Now we can determine the paw with a simple modulo 4..
    paw_codes = paw_number % 4
    paw_labels = [paw_code[code] for code in paw_codes]

    return paw_labels

이 모든 것에도 불구하고 자주 제대로 작동하지 않습니다. 전체 데이터 세트에있는 많은 개들이 달리고있는 것으로 보이며, 발이 미치는 영향은 개가 걸을 때와 같은 시간적 순서를 따르지 않습니다. (또는 아마도 개는 심각한 엉덩이 문제를 겪고 있습니다 ...)

비정상적인 영향 순서

다행히도, 발의 영향이 예상되는 공간 패턴을 따르는 지 여부를 프로그래밍 방식으로 감지 할 수 있습니다.

def paw_pattern_problems(paw_labels, dx, dy):
    """Check whether or not the label sequence "paw_labels" conforms to our
    expected spatial pattern of paw impacts. "paw_labels" should be a sequence
    of the strings: "LH", "RH", "LF", "RF" corresponding to the different paws"""
    # Check for problems... (This could be written a _lot_ more cleanly...)
    problems = False
    last = paw_labels[0]
    for paw, dy, dx in zip(paw_labels[1:], dy, dx):
        # Going from a left paw to a right, dy should be negative
        if last.startswith('L') and paw.startswith('R') and (dy > 0):
            problems = True
            break
        # Going from a right paw to a left, dy should be positive
        if last.startswith('R') and paw.startswith('L') and (dy < 0):
            problems = True
            break
        # Going from a front paw to a hind paw, dx should be negative
        if last.endswith('F') and paw.endswith('H') and (dx > 0):
            problems = True
            break
        # Going from a hind paw to a front paw, dx should be positive
        if last.endswith('H') and paw.endswith('F') and (dx < 0):
            problems = True
            break
        last = paw
    return problems

따라서 단순한 공간 분류가 항상 작동하지는 않지만 합리적인 확신을 가지고 작동하는시기를 결정할 수 있습니다.

교육 데이터 세트

패턴 기반 분류가 올바르게 작동 한 경우 올바르게 분류 된 발에 대한 대규모 훈련 데이터 세트를 구축 할 수 있습니다 (32 개의 다른 개에서 ~ 2400 발의 충격)!

이제 "평균"앞 왼쪽 등이 어떻게 보이는지 볼 수 있습니다.

이를 위해, 우리는 어떤 개와 같은 차원의 "발 측정법"이 필요합니다. (전체 데이터 세트에는 아주 크고 작은 개가 있습니다!) 아일랜드 엘크 하운드의 발자국은 토이 푸들의 발자국보다 훨씬 넓고 무겁습니다. 우리는 각 발자국을 재조정하여 a) 픽셀 수가 동일하고 b) 압력 값이 표준화되도록해야합니다. 이를 위해 각 발자국을 20x20 격자로 다시 샘플링하고 발 충격에 대한 최대, 최소 및 평균 압력 값을 기준으로 압력 값을 다시 조정했습니다.

def paw_image(paw):
    from scipy.ndimage import map_coordinates
    ny, nx = paw.shape

    # Trim off any "blank" edges around the paw...
    mask = paw > 0.01 * paw.max()
    y, x = np.mgrid[:ny, :nx]
    ymin, ymax = y[mask].min(), y[mask].max()
    xmin, xmax = x[mask].min(), x[mask].max()

    # Make a 20x20 grid to resample the paw pressure values onto
    numx, numy = 20, 20
    xi = np.linspace(xmin, xmax, numx)
    yi = np.linspace(ymin, ymax, numy)
    xi, yi = np.meshgrid(xi, yi)  

    # Resample the values onto the 20x20 grid
    coords = np.vstack([yi.flatten(), xi.flatten()])
    zi = map_coordinates(paw, coords)
    zi = zi.reshape((numy, numx))

    # Rescale the pressure values
    zi -= zi.min()
    zi /= zi.max()
    zi -= zi.mean() #<- Helps distinguish front from hind paws...
    return zi

이 모든 작업을 마친 후에는 평균 왼쪽 앞, 뒤 오른쪽 등이 어떻게 생겼는지 살펴볼 수 있습니다. 이것은 크기가 크게 다른 30 마리 이상의 개에서 평균치이며 일관된 결과를 얻는 것 같습니다!

평균 앞발

그러나 이것에 대한 분석을 수행하기 전에 평균 (모든 강아지의 모든 다리에 대한 평균 발)을 빼야합니다.

평균 발

이제 우리는 평균과의 차이점을 분석 할 수 있습니다.

차동 발

이미지 기반 발 인식

좋아 ... 마침내 우리는 발과 일치하려고 시도 할 수있는 일련의 패턴을 가졌다. 각 발은 paw_image이 4 개의 400 차원 벡터와 비교할 수 있는 400 차원 벡터 ( 함수에 의해 반환 됨 )로 취급 될 수 있습니다.

불행히도, 만약 우리가 단지 "일반적인"감독 분류 알고리즘을 사용한다면 (즉, 간단한 거리를 사용하여 4 가지 패턴 중 특정 발자국에 가장 가까운 패턴을 찾으면) 일관되게 작동하지 않습니다. 실제로 훈련 데이터 세트에서 무작위 확률보다 훨씬 나아지지는 않습니다.

이것은 이미지 인식에서 일반적인 문제입니다. 입력 데이터의 높은 차원 성과 이미지의 다소 "퍼지"특성 (즉, 인접한 픽셀은 높은 공분산을 가짐)으로 인해 템플릿 이미지와 이미지의 차이를 보는 것만으로도 그들의 모양의 유사성.

고 유발

이 문제를 해결하려면 얼굴 인식의 "고유 얼굴"과 같이 "고유 발"세트를 만들고 각 발자국을 이들 고유 발의 조합으로 설명해야합니다. 이는 주성분 분석과 동일하며 기본적으로 데이터의 차원을 줄이는 방법을 제공하므로 거리가 모양을 잘 측정 할 수 있습니다.

우리는 크기 (2400 대 400)보다 더 많은 훈련 이미지를 가지고 있기 때문에 속도를 위해 "멋진"선형 대수를 수행 할 필요가 없습니다. 훈련 데이터 세트의 공분산 행렬로 직접 작업 할 수 있습니다.

def make_eigenpaws(paw_data):
    """Creates a set of eigenpaws based on paw_data.
    paw_data is a numdata by numdimensions matrix of all of the observations."""
    average_paw = paw_data.mean(axis=0)
    paw_data -= average_paw

    # Determine the eigenvectors of the covariance matrix of the data
    cov = np.cov(paw_data.T)
    eigvals, eigvecs = np.linalg.eig(cov)

    # Sort the eigenvectors by ascending eigenvalue (largest is last)
    eig_idx = np.argsort(eigvals)
    sorted_eigvecs = eigvecs[:,eig_idx]
    sorted_eigvals = eigvals[:,eig_idx]

    # Now choose a cutoff number of eigenvectors to use 
    # (50 seems to work well, but it's arbirtrary...
    num_basis_vecs = 50
    basis_vecs = sorted_eigvecs[:,-num_basis_vecs:]

    return basis_vecs

이들은 basis_vecs"고 유발"입니다.

고 유발

이를 사용하기 위해 각 발 이미지 (20x20 이미지가 아닌 400 차원 벡터)를 기본 벡터로 간단히 점 (즉, 행렬 곱셈)을 사용합니다. 이미지를 분류하는 데 사용할 수있는 50 차원 벡터 (기본 벡터 당 하나의 요소)를 제공합니다. 20x20 이미지를 각 "템플릿"풋의 20x20 이미지와 비교하는 대신 50 차원의 변형 된 이미지를 각 50 차원의 변형 된 템플릿 풋과 비교합니다. 이것은 각 발가락의 위치 등의 작은 변화에 훨씬 덜 민감하며 기본적으로 문제의 차원을 관련 차원으로 줄입니다.

고 유발 기반 발 분류

이제 각 다리에 대해 50 차원 벡터와 "템플릿"벡터 사이의 거리를 사용하여 어느 발이 어떤 발인지를 분류 할 수 있습니다.

codebook = np.load('codebook.npy') # Template vectors for each paw
average_paw = np.load('average_paw.npy')
basis_stds = np.load('basis_stds.npy') # Needed to "whiten" the dataset...
basis_vecs = np.load('basis_vecs.npy')
paw_code = {0:'LF', 1:'RH', 2:'RF', 3:'LH'}
def classify(paw):
    paw = paw.flatten()
    paw -= average_paw
    scores = paw.dot(basis_vecs) / basis_stds
    diff = codebook - scores
    diff *= diff
    diff = np.sqrt(diff.sum(axis=1))
    return paw_code[diff.argmin()]

결과는 다음과 같습니다. 대체 텍스트 대체 텍스트 대체 텍스트

남은 문제

여전히 작은 발자국으로 명확한 발자국을 만들기에는 여전히 몇 가지 문제가 있습니다 ... (발톱이 센서의 해상도에서 더 명확하게 분리되어 있기 때문에 큰 개와 가장 잘 작동합니다.) 또한 부분 발자국은 이것으로 인식되지 않습니다 사다리꼴 패턴 기반 시스템과 함께 사용할 수 있습니다.

그러나 고 유포 분석은 본질적으로 거리 측정법을 사용하기 때문에, 포를 두 가지 방식으로 분류하고, "포드 북"으로부터의 고 유포 분석의 최소 거리가 임계 값을 초과하면 사다리꼴 패턴 기반 시스템으로 폴백 할 수 있습니다. 그래도 아직 구현하지 않았습니다.

휴 ... 너무 길었다! 그런 재미있는 질문을해서 모자가 Ivo를 떠납니다!


지속 시간을 기준으로 정보를 사용하면 운동학 모델링 기술을 적용 할 수 있다고 생각합니다. 역 운동학 . 방향, 길이, 지속 시간 및 총 중량과 결합하여 일정 수준의 주기성을 제공하므로 "발 정렬"문제를 해결하기위한 첫 번째 단계가되기를 바랍니다.

이 모든 데이터를 사용하여 경계 다각형 (또는 튜플)의 목록을 만들 수 있습니다.이를 사용하여 단계 크기와 paw-ness [인덱스]별로 정렬 할 수 있습니다.


기술자가 수동으로 시험을 시작하도록 하시겠습니까? 프로세스는 다음과 같습니다.

  • 기술에 단계 이미지의 순서를 보여주고 첫 발에 주석을 달도록 요구하십시오.
  • 첫 번째 발을 기준으로 다른 발에 라벨을 붙이고 기술자가 수정하거나 테스트를 다시 실행할 수 있도록합니다. 이것은 절름발이 또는 3 다리 개를 허용합니다.

참고 URL : https://stackoverflow.com/questions/4502656/how-to-sort-my-paws

반응형