2016-06-15 6 views
5

다음 코드를 파이썬으로 구현하고자한다고 가정 해 봅시다.numpy 배열에서 다른 요소에 액세스하는 함수를 벡터화 할 수 있습니까?

이 함수는 이미지를 1 차원 배열로 가져 와서 출력 배열에 영향을주는 배열의 개별 요소 (입력 이미지의 픽셀)를 반복합니다. 또한, 화상은 1 차원 배열로 표현

예 : 입력 화상 (적색)의 단일 화소 (오렌지)의 8 개의 주변 화소에 영향을 는 example 1

C의 기본 구현은

,745 인
/* C version 
* Given an input image create an 
* output image that is shaped by individual pixels 
* of the input image 
*/ 

int image[width * height]; //image retrieved elsewhere 
int output [width * height]; //output image 
int y = 0, x = 0; 
for(y = 1; y < height-1 ; ++ y) { 
    for(x = 1; x < width-1; ++ x) { 
     if (image[y * width + x] > condition) { 
      /* pixel affects the surrounding 8 pixels in the output image */ 

      output[(y-1) * width + x - 1]++; /* upper left */ 
      output[(y-1) * width + x ]++; /* above  */ 
      output[(y-1) * width + x + 1]++; /* upper right */ 
      output[y * width + x + 1 ]++; /* right  */ 
      output[y * width + x - 1 ]++; /* left  */ 
      output[(y+1) * width + x - 1]++; /* lower left */ 
      output[(y+1) * width + x ]++; /* below  */ 
      output[(y+1) * width + x + 1]++; /* lower right */ 


     } 
    } 
} 

파이썬에서 순진한 접근 방식이 구현하는 더 나은 방법이

#Python version 
input = blah # formed elsewhere 
output = np.zeros(width * height) 
for y in xrange(1, height-1): 
    for x in xrange(1, width-1): 
     if input[y * width + x] > condition: 
      output[(y-1) * width + x - 1]+= 1; # upper left 
      output[(y-1) * width + x ]+= 1; # above  
      output[(y-1) * width + x + 1]+= 1; # upper right 
      output[y * width + x + 1 ]+= 1; # right  
      output[y * width + x - 1 ]+= 1; # left   
      output[(y+1) * width + x - 1]+= 1; # lower left 
      output[(y+1) * width + x ]+= 1; # below  
      output[(y+1) * width + x + 1]+= 1; # lower right 

아래 그림과 같이 정확히 같은 요소 현명한 접근을 사용하는 것입니다? 이 함수를 벡터화 할 수 있습니까?

답변

0

입력란을 나타내는 숫자가 arr이고 각 입력 요소와 비교할 문턱치가 thresh이라고 가정 해 보겠습니다. 이제 주어진 임계 값에 대해 입력 배열을 임계 값으로 설정하여 마스크/부울 배열을 얻을 수 있습니다. 그런 다음 2D 컨볼 루션을 수행하고 임계 값 배열에 대해 True 값이있는 곳에서 1s을 뺍니다.

따라서, 구현이이 같은 보일 것이다 - 내가 제대로, 다음 접근 방식은 거꾸로 할 수있는 질문을 이해하면

from scipy.signal import convolve2d 

# Get thresholded mask as int array & set first, last cols and rows as 0s 
mask = (arr > thresh).astype(int) 
mask[[0,-1]] = 0 
mask[:,[0,-1]] = 0 

# Perform 2D convolution and subtract 1s corresponding to True elems in mask 
out = convolve2d(mask,np.ones((3,3),dtype=int),'same') - mask 
5

을 : 픽셀이 조건에 일치의 이웃 픽셀이있는 경우, 매치마다 1 씩 증가시킵니다. 모든 픽셀에 대해이 작업을 수행하십시오. (다른 사람의 사이에서) Scipy는 filtering images위한 도구를 제공합니다

In [51]: import scipy.ndimage 

는 1 차원 배열에서 샘플 이미지를 만듭니다. 모양 변경 대신 복사 도면을 작성

다음 조건 (여기서는 128)을 초과하는 픽셀의 바이너리 마스크로부터 원래의 각 화소에 간격을 유지하는 이미지를 만들 회선 사용

In [62]: I1d 
Out[62]: 
array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 129, 0, 129, 129, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129]) 

In [63]: height 
Out[63]: 8 

In [64]: width 
Out[64]: 8 

In [65]: I = I1d.reshape((height, width)) 

In [66]: I 
Out[66]: 
array([[ 0, 0, 0, 0, 0, 0, 0, 0], 
     [ 0, 0, 0, 0, 0, 0, 0, 0], 
     [ 0, 0, 129, 0, 129, 129, 0, 0], 
     [ 0, 0, 0, 0, 0, 0, 0, 0], 
     [ 0, 0, 0, 0, 129, 0, 0, 0], 
     [ 0, 0, 0, 0, 0, 0, 0, 0], 
     [ 0, 0, 0, 0, 0, 0, 0, 0], 
     [ 0, 0, 0, 0, 0, 0, 0, 129]]) 

In [67]: scipy.ndimage.filters.convolve(
    (I > 128).astype(np.int), # conditioned binary image 
    weights=np.array([[1, 1, 1], # each match weighted as 1 
         [1, 0, 1], 
         [1, 1, 1]]), 
    mode='constant', cval=0) # Use zeros as constant fill values on edges 
Out[67]: 
array([[0, 0, 0, 0, 0, 0, 0, 0], 
     [0, 1, 1, 2, 2, 2, 1, 0], 
     [0, 1, 0, 2, 1, 1, 1, 0], 
     [0, 1, 1, 3, 3, 3, 1, 0], 
     [0, 0, 0, 1, 0, 1, 0, 0], 
     [0, 0, 0, 1, 1, 1, 0, 0], 
     [0, 0, 0, 0, 0, 0, 1, 1], 
     [0, 0, 0, 0, 0, 0, 1, 0]]) 

In [68]: conv = _ 

최종 목표는 원본과 증분 추가하는 경우

In [69]: I + conv 
Out[69]: 
array([[ 0, 0, 0, 0, 0, 0, 0, 0], 
     [ 0, 1, 1, 2, 2, 2, 1, 0], 
     [ 0, 1, 129, 2, 130, 130, 1, 0], 
     [ 0, 1, 1, 3, 3, 3, 1, 0], 
     [ 0, 0, 0, 1, 129, 1, 0, 0], 
     [ 0, 0, 0, 1, 1, 1, 0, 0], 
     [ 0, 0, 0, 0, 0, 0, 1, 1], 
     [ 0, 0, 0, 0, 0, 0, 1, 129]]) 

w 같은 1 차원 어레이의 출력을받는 예를 들어, ravel() 또는 flatten()을 사용하십시오. 전자는 후자가 평평 복사본을 생성, 원래의 2 차원 배열을 1 차원 뷰를 작성 :

In [70]: conv.ravel() 
Out[70]: 
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 1, 0, 0, 1, 0, 2, 1, 1, 1, 
     0, 0, 1, 1, 3, 3, 3, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 
     0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0]) 
3

내가 무엇을 당신이하려고하는 것은 2 차원 배열 인덱싱 쉬운라고 생각합니다. numpy로 배열을 쉽게 바꿀 수 있습니다. 데이터가 복사되지 않습니다. 새로운 2D 배열은 원래 배열에 저장된 것과 동일한 값을 색인하는 편리한 방법을 제공합니다. 다음은 예제 코드입니다.

#imports 
import numpy as np 


# Setup 
Nx = 5 
Ny = 7 
cutoff = 3.0 
arr_input = np.array([[0, 0, 0, 0, 0, 0, 9], 
         [0, 4, 0, 0, 0, 0, 0], 
         [0, 0, 0, 0, 0, 3, 0], 
         [0, 2, 0, 0, 0, 0, 1], 
         [0, 0, 0, 0, 5, 0, 0]]).flatten() 

# Make an array of center locations with input value bigger than the cutoff value 
centers_array_2d = np.where(arr_input>=cutoff, 1.0, 0.0) 

# Initialize the output array 
arr_output = np.zeros_like(centers_array_2d) 

# Reshape the arrays to use 2D indexing 
ai = centers_array_2d.reshape(Nx, Ny) 
ao = arr_output.reshape(Nx, Ny) 

# Do the neighbor calculation with numpy indexing rules 
ao[:-1, :-1] += ai[1:, 1:]    # lower left 
ao[:, :-1] += ai[:, 1:]     # lower center 
ao[1:, :-1] += ai[:-1, 1:]    # lower right 
ao[:-1, :] += ai[1:, :]     # middle left 
# ao[:, :] += ai[:, :]     # middle center 
ao[1:, :] += ai[:-1, :]     # middle right 
ao[:-1, 1:] += ai[1:, :-1]    # top left 
ao[:, 1:] += ai[:, :-1]     # top center 
ao[1:, 1:] += ai[:-1, :-1]    # top right 

# Reshape the output array to return a 1D array like the input 
arr_output = ao.flatten() 

# Print the results 
print('input1d: \n{}\n'.format(arr_input)) 
print("2D array 'ai':\n{}\n".format(ai)) 
print("2D array 'ao':\n{}\n".format(ao)) 
print('output1d: \n{}\n'.format(arr_output)) 

배열은 다음과 같습니다.

input1d: 
[0 0 0 0 0 0 9 0 4 0 0 0 0 0 0 0 0 0 0 3 0 0 2 0 0 0 0 1 0 0 0 0 5 0 0] 

2D array 'ai': 
[[ 0. 0. 0. 0. 0. 0. 1.] 
[ 0. 1. 0. 0. 0. 0. 0.] 
[ 0. 0. 0. 0. 0. 1. 0.] 
[ 0. 0. 0. 0. 0. 0. 0.] 
[ 0. 0. 0. 0. 1. 0. 0.]] 

2D array 'ao': 
[[ 1. 1. 1. 0. 0. 1. 0.] 
[ 1. 0. 1. 0. 1. 2. 2.] 
[ 1. 1. 1. 0. 1. 0. 1.] 
[ 0. 0. 0. 1. 2. 2. 1.] 
[ 0. 0. 0. 1. 0. 1. 0.]] 

output1d: 
[ 1. 1. 1. 0. 0. 1. 0. 1. 0. 1. 0. 1. 2. 2. 1. 1. 1. 0. 1. 0. 1. 0. 0. 0. 1. 2. 2. 1. 0. 0. 0. 1. 0. 1. 0.] 

이 값은 찾고 계셨습니까? 이것은 당신이 준 코드를 벡터화하는 것으로 해석 할 것입니다. 또한 각 이웃에 해당하는 1D 배열에 대한 인덱스 목록을 만들 수 있습니다. 이것은 본질적으로 2D 슬라이스 인덱스를 사용하여 2D 배열의 요소에 액세스 할 때 내부적으로 진행되고있는 것입니다.

관련 문제