2011-02-18 2 views
11

MATLAB에 행렬이 있습니다. 모든 요소에 대해 4 개의 연결된 이웃 (왼쪽, 오른쪽, 위쪽, 아래쪽)을 확인하고 싶습니다. 현재 요소가 이웃 요소 중 하나보다 작 으면 0으로 설정하고 그렇지 않으면 값을 유지합니다. 루프를 사용하면 쉽게 할 수 있지만 수천 개의 매트릭스가 있으므로 비용이 많이 듭니다.MATLAB에서 루프를 사용하지 않고 행렬 요소를 인접 요소와 비교하는 방법은 무엇입니까?

가장자리 감지 후 최대가 아닌 억압으로 인식 할 수 있습니다.

답변

8

한 가지 방법을 각각 M에 소정 함수를 적용 Image Processing Toolbox에서 함수 NLFILTER, 함께 해결할 매트릭스 그래밍 N 블록 :

>> A = magic(6) %# A sample matrix 

A = 

    35  1  6 26 19 24 
    3 32  7 21 23 25 
    31  9  2 22 27 20 
    8 28 33 17 10 15 
    30  5 34 12 14 16 
    4 36 29 13 18 11 

>> B = nlfilter(A,[3 3],@(b) b(5)*all(b(5) >= b([2 4 6 8]))) 

B = 

    35  0  0 26  0  0 
    0 32  0  0  0 25 
    31  0  0  0 27  0 
    0  0  0  0  0  0 
    30  0 34  0  0 16 
    0 36  0  0 18  0 

상기 코드는 3 바이 3 행렬의 중심 요소를 얻을 linear indexing을 사용하는 정의 anonymous function을 참조하여 연결된 4 개 이웃 b([2 4 6 8])과 비교하십시오. center 요소의 값에 함수 ALL에 의해 반환 된 논리 결과가 곱해집니다. 가운데 요소 값이 가장 가까운 이웃 요소보다 클 경우 1이고 그렇지 않으면 0입니다.

+0

정확히 내가 무엇을 찾고 있었는지 ... 나는 그 성능이 루프보다 좋기를 바랍니다. :) 감사합니다. gnovie – Shan

+2

+1 imdilate가 여전히 더 빠를 것 같아요. – Jonas

+0

@ Jonas : [IMDILATE 성능은 MATLAB의 마지막 몇 가지 버전에서 몇 가지 중요한 개선 사항을 보았 기 때문에] 속도에 관해서는 옳을 수도 있습니다. (http://blogs.mathworks.com/steve/2010/04/23/more- r2010a- 성능 향상 - 이미지 처리 도구 상자 /). – gnovice

9

이미지 처리 도구 상자가있는 경우 morpological dilation으로이 작업을 수행하여 로컬 최대 값을 찾고 다른 모든 요소를 ​​표시하지 않을 수 있습니다.

array = magic(6); %# make some data 

msk = [0 1 0;1 0 1;0 1 0]; %# make a 4-neighbour mask 

%# dilation will replace the center pixel with the 
%# maximum of its neighbors 
maxNeighbour = imdilate(array,msk); 

%# set pix to zero if less than neighbors 
array(array<maxNeighbour) = 0; 

array = 
    35  0  0 26  0  0 
    0 32  0  0  0 25 
    31  0  0  0 27  0 
    0  0  0  0  0  0 
    30  0 34  0  0 16 
    0 36  0  0 18  0 

편집 @gnovice와 같은 데이터를 사용하고, 코드를 이렇게

+0

대답 에 대한 감사합니다. 이것은 멋진 방법이지만 내가 찾고있는 것이 아닙니다 ...(x = 1; x Shan

+2

@Shan : 예, 그렇습니다. 나는 해결책을 고쳤다. – Jonas

+0

고마워요 조나스 ... – Shan

5

Image Processing Toolbox에 액세스 할 수없는 경우이를 수행하는 또 다른 방법은 각 점의 위쪽, 오른쪽, 아래쪽 및 왼쪽 첫 번째 차이를 나타내는 4 개의 행렬을 작성한 다음 4 개 행렬 모두에서 해당 요소를 검색하는 것입니다. (즉 요소가 모든 인접 요소를 초과합니다).

 
>> sizeA = 3; 
A = randi(255, sizeA) 

A = 

    254 131 94 
    135 10 124 
    105 191 84 

패드 제로 요소와 국경 :

 
>> A2 = zeros(sizeA+2) * -Inf; 
A2(2:end-1,2:end-1) = A 

A2 = 

    0  0  0  0  0 
    0 254 131 94  0 
    0 135 10 124  0 
    0 105 191 84  0 
    0  0  0  0  0 

가 네 첫 차 행렬을 구축 여기

는 테스트 데이터를 생성 ... 나눌 생각입니다 :

 
>> leftDiff = A2(2:end-1,2:end-1) - A2(2:end-1,1:end-2) 

leftDiff = 

    254 -123 -37 
    135 -125 114 
    105 86 -107 

>> topDiff = A2(2:end-1,2:end-1) - A2(1:end-2,2:end-1) 

topDiff = 

    254 131 94 
    -119 -121 30 
    -30 181 -40 

>> rightDiff = A2(2:end-1,2:end-1) - A2(2:end-1,3:end) 

rightDiff = 

    123 37 94 
    125 -114 124 
    -86 107 84 

>> bottomDiff = A2(2:end-1,2:end-1) - A2(3:end,2:end-1) 

bottomDiff = 

    119 121 -30 
    30 -181 40 
    105 191 84 
얻어진 매트릭스 생성

 
indexKeep = find(leftDiff >= 0 & topDiff >= 0 & rightDiff >= 0 & bottomDiff >= 0) 

: 모든 함수에이 포장 1000 난수는 100x100 행렬에서 테스트 후

 
>> B = zeros(sizeA); 
B(indexKeep) = A(indexKeep) 

B = 

    254  0  0 
    0  0 124 
    0 191  0 

를 알고리즘이 나타나는 0

는 이웃 모두를 초과하는 요소를 찾아 매우 빠르다 :

 
>> tic; 
for ii = 1:1000 
A = randi(255, 100); 
B = test(A); 
end; toc 
Elapsed time is 0.861121 seconds. 
+3

+1 : 아주 좋네요. 멋진 도구 상자에 액세스 할 때 이와 같은 간단한 구현을 잊어 버리는 것은 쉽습니다. ;) 하나의 제안 ... 당신은 다음과 같이 [CIRCSHIFT] (http://www.mathworks.com/help/techdoc/ref/circshift.html)를 사용하여 코드를 단순화 할 수있다 :'index = A2> = circshift (A2, (A2, [0-1]) 및 A2> = 순환 쉬프트 (A2, [0-1]) 및 A2> = 순환 쉬프트 (A2, [1 0]) 및 A2> A2 = A2 * 색인; A2 = A2 (2 : end-1,2 : end-1);'또한'> '대신'> ='를 사용하고 싶습니다. – gnovice

+2

아, 또 다른 제안은 알고리즘을 좀 더 일반화하기 위해서'-Inf'를 사용하여 행렬에 음의 값이 올 가능성을 설명하기 위해 행렬을 0 대신 채우는 것입니다 (즉, 패딩을 표시하지 않으려 고합니다 로컬 맥시마로 업). – gnovice

+1

@gnovice : 제안에 감사드립니다. 그들을 포함하도록 편집 됨. 더 멋진 방법을 유지하기 위해 CIRCSHIFT를 구현하지 않았지만 CIRCSHIFT를 사용하는 것이 더 좋은 솔루션이된다는 것에 동의합니다. –

관련 문제