2014-07-22 5 views
3

문제가 있습니다. 문제는 : numpy 배열의 하위 클래스를 만들고 해당 유형의 객체 배열을 만들고 싶습니다. 해당 배열의 항목을 참조 할 때 여전히 그 하위 클래스의 인스턴스가되고 싶습니다. 대신, 그것은 numpy 배열의 인스턴스입니다.numpy의 하위 클래스 배열

import numpy as np 


class ImageWrapper(np.ndarray): 

    def __new__(cls, image_data): 
     assert image_data.ndim in (2, 3) 
     return image_data.view(cls) 

    @property 
    def n_colours(self): 
     return 1 if self.ndim==2 else self.shape[2] 


n_frames = 10 
frames = [ImageWrapper(np.random.randint(255, size = (20, 15, 3)).astype('uint8')) for _ in xrange(n_frames)] 
video = np.array(frames) 
assert video[0].n_colours == 3 

나에게 제공합니다 : AttributeError를 'numpy.ndarray'개체가 어떤 속성 'n_colours'가

가 어떻게이 작품을 만들 수 있습니다

가 여기에

실패 테스트입니다?

상황이 이미 시도 :

  • 설정 subok = 비디오를 구성 할 때 진정한 -이 단지 작품 서브 클래스 객체의 단일 인스턴스가 아닌 목록에서 배열을 구성.
  • 설정 DTYPE = 개체 또는 DTYPE = ImageWrapper 내가 그냥 비디오 목록을 만들 수 있음을 인식

작동하지 않지만, 다른 이유로 NumPy와 배열로 유지하는 것이 바람직 할 것이다.

+0

문제는, 당신이 4D 배열을 얻을 당신이 호출 할 때'3D 배열의 목록에 array' 것이 아니라 1D 배열 가득 3D 어레이의 분명히 4D 배열은'ImageWrapper '가 될 수 없으므로'ndarray'이기 때문에 데이터의 원래 위치와 상관없이 모든 슬라이스가'ndarray'입니다. 질문은 배열을 원하지만? 1D 배열의'object'는 네이티브리스트보다 numpy의 이점을 잃지 않지만, 그것의 _lot_을 잃습니다. 그리고 마지막 문장에서 "다른 이유"를 말할 수 있다면 도움이 될 것입니다. – abarnert

+0

또한, 4D 배열이 'ImageWrapper'가 될 수 없다는 것을 디자인에서 결정해야하는 이유가 무엇입니까? N_3이면 (아니면 예외를 발생시키는 경우) 'n_colours'는 스칼라가 아닌 N-3 차원의 배열을 반환해야하지만 그렇지 않으면 무엇이 문제가됩니까? 그게 훨씬 더 간단해질 것이기 때문에 ... – abarnert

+0

"다른 이유"는 큰 이유가 아니며, 이것은 배열이 예상되는 데이터 유형 인 인터페이스의 일부라는 것입니다. 이 경우 Jaime에서 제안한대로 개체 배열이 수행됩니다. – Peter

답변

2

numpy.array는이 사건을 처리 할 정도로 정교하지 않습니다. subok=True은 하위 클래스를 전달하는 함수를 알려주지 만 ndarray의 하위 클래스를 전달하지 않으면 목록을 전달합니다 (ndarray 하위 클래스의 인스턴스로 채워짐).

import numpy as np 


class ImageWrapper(np.ndarray): 

    def __new__(cls, image_data): 
     assert 2 <= image_data.ndim <= 4 
     return image_data.view(cls) 

    @property 
    def n_colours(self): 
     return 1 if self.ndim==2 else self.shape[-1] 


n_frames = 10 
frame_shape = (20, 15, 3) 
video = ImageWrapper(np.empty((n_frames,) + frame_shape, dtype='uint8')) 
for i in xrange(n_frames): 
    video[i] = np.random.randint(255, size=(20, 15, 3)) 
assert video[0].n_colours == 3 

주의 사항 4 차원 배열을 입력으로 허용하려면 ImageWrapper를 업데이트해야합니다.

3

달성하고자하는 것이 무엇이든, 아마도 ndarray를 서브 클래 싱하는 것보다 더 나은 방법이있을 것입니다. 그러나 배열을 만들 때 조심해야하지만 배열의 유형이 object 일 수 있습니다.

>>> video = np.empty((len(frames),), dtype=object) 
>>> video[:] = frames 
>>> video[0].n_colours 
3 

을하지만이되지 않습니다 :이 작동

>>> video = np.array(frames, dtype=object) 
>>> video[0].n_colours 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'numpy.ndarray' object has no attribute 'n_colours' 
+0

저에게 맞습니다. 고마워요. 이것에 대한 진정한 이유는 기괴한 이미지 형식 (YUV)을 가지고 있기 때문에 자르기 및 다운 샘플링과 같은 작업을 수행하기 위해 메서드가 바인딩되기를 원합니다. 래핑보다는 서브 클래 싱을 사용하는 이유는 더 의문 스럽습니다. 주로 파이썬으로 작업하고 있지만 우리가 자바 인 척하고 싶기 때문입니다. 그리고 인터페이스는 모듈간에 전달되는 데이터가 배열 유형임을 요구합니다. – Peter

+0

@ 피터 : YUV가 그다지 기괴하거나 드문 경우는 아닙니다. 또한,'ImageWrapper'가> 3D의 배열을 가질 수 있다면 당신에게 더 좋을 것 같습니다.이 경우에 메서드를 호출하면 각 3D 하위 배열을 수동으로 반복하지 않고 각 3D 하위 배열에 효과적으로 호출을 브로드 캐스팅합니다 . (필자가 언급 한 바에 따르면 Bi Rico가 그의 대답에서 생각한 바를 잘 알고 있습니다.) 반대로, 실제로 배열을 반복하도록하려면, 그것들은 배열보다. – abarnert