안녕하세요. 지난 포스팅의 넘파이 알고 쓰자 - 넘파이의 원소 제거 및 추가(delete, add)에서는 넘파이 원소를 제거하거나 추가하는 다양한 방법에 대해서 알아보았습니다. 오늘 포스팅에서는 조금 특별한 routine 함수를 소개해드릴려고 합니다. 이는 영상 처리에서도 굉장히 많이 쓰이는 함수 중에 하나인 flip과 관련된 함수들입니다. 그리고 그와 못지않게 중요한 roll 함수와 rot90 함수에 대해서 소개하도록 하겠습니다.
1. numpy.flip(m, axis=None)
이 함수는 뒤집는(flip) 함수입니다. 말 그대로이죠. 영상 처리에서 뒤집기 연산은 크게 2가지입니다. 수직축을 중심으로 뒤집는 vertical flip, 그리고 수평축을 중심으로 뒤집는 horizontal flip이 있습니다. 이 함수는 axis에 따라서 다양한 뒤집기 연산이 구현되어있습니다. 이때, flip 함수와 유사하지만 축이 고정되어있는 함수는 flipud, fliplr 함수와 같이 설명하도록 하겠습니다.
a = np.arange(1, 10).reshape((3, 3))
# array([[3, 2, 1],
# [6, 5, 4],
# [9, 8, 7]])
np.flip(a, 0)
# array([[7, 8, 9],
# [4, 5, 6],
# [1, 2, 3]])
np.flipud(a)
# array([[7, 8, 9],
# [4, 5, 6],
# [1, 2, 3]])
먼저, flip 함수와 flipud 함수와 비교해보면 flip 함수에서 axis를 0으로 고정한 것이 flipud 함수와 동일합니다. 그 결과는 중앙 horizontal line을 기준으로 위아래를 뒤집는 것과 동일합니다. 직관적으로 잘 이해가 되는 함수입니다. 이번에는 flip과 fliplr 함수를 같이 설명하도록 하겠습니다.
a = np.arange(1, 10).reshape(3, 3)
# array([[1, 2, 3],
# [4, 5, 6],
# [7, 8, 9]])
np.flip(a, 1)
# array([[3, 2, 1],
# [6, 5, 4],
# [9, 8, 7]])
np.fliplr(a)
# array([[3, 2, 1],
# [6, 5, 4],
# [9, 8, 7]])
보시면 flip 함수에서 axis를 1로 고정한 것이 fliplr 함수인 것을 알 수 있습니다. 그 결과는 중앙 vertical line을 기준으로 좌우로 뒤집는 것과 동일합니다. 이 역시 직관으로 쉽게 이해할 수 있습니다. 음... 하지만 한 가지 궁금한 점이 있습니다. 만약, axis를 2 이상으로 설정하게 되면 어떻게 될까요? 사실 flip을 파이썬스럽게 정의하면 아래의 코드와 동일합니다.
a[::-1]
#array([[7, 8, 9],
# [4, 5, 6],
# [1, 2, 3]])
위 함수가 어떤 것인지 기억나시나요? 기억나시는 분들은 쉽게 이해하실 겁니다. 이 키워드가 리스트를 "뒤집는다."라는 것과 동일합니다. 넘파이 객체는 파이썬의 리스트와 유사한 특징을 굉장히 많이 가지고 있다고 하였습니다. 넘파이에서도 저런식으로 적으면 동일하게 "뒤집는다."라는 것을 명시해주게 되는 것이죠. 결과를 보시면 axis를 0으로 하는 것과 동일합니다. axis를 1로 하는 것은 아래와 같이 쓸 수 있습니다.
a[:, ::-1]
# array([[3, 2, 1],
# [6, 5, 4],
# [9, 8, 7]])
이렇게 보면 규칙성이 이해가실겁니다. 즉!! axis를 2로 설정한 다는 것은 0, 1번 축은 그대로 유지하고 나머지 축인 2번 축을 기준으로 뒤집는 다는 것입니다.
2. numpy.roll(a, shift, axis=None)
다음은 roll 함수입니다. 이 함수는 넘파이 배열을 굴리는(roll) 함수입니다. 아니 잠깐! 넘파이 배열을 굴린다는 게 어떤 의미일까요? 사실 이것도 알고보면 단순한 함수입니다. 예를 들어 0, 1, 2, ..., 9로 이루어진 넘파이 배열이 있다고 가정했을 때, roll 함수를 적용하면 9, 0, 1, ..., 8과 같이 될 수 있습니다. 즉, 가장 앞의 원소를 가장 뒤로 보내고 땡겨오거나, 가장 뒤의 원소를 가장 앞으로 보내고 밀 수 있으며 shift 함수에 의해서 몇 칸이나 밀지 결정할 수 있습니다. 또한 다차원 배열에서는 어떤 axis를 기준으로 밀 것인지도 결정할 수 있겠죠. 예제 코드를 보도록 하겠습니다.
a = np.arange(10)
np.roll(a, shift=0)
# array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.roll(a, shift=1)
# array([9, 0, 1, 2, 3, 4, 5, 6, 7, 8])
np.roll(a, shift=2)
# array([8, 9, 0, 1, 2, 3, 4, 5, 6, 7])
np.roll(a, shift=-1)
# array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])
np.roll(a, shift=-2)
# array([2, 3, 4, 5, 6, 7, 8, 9, 0, 1])
위와 같이 shift를 양수로 입력하면 앞의 원소가 뒤로 밀리고, 음수로 입력하면 앞의 원소가 앞으로 땡겨지는 것을 볼 수 있습니다.
3. numpy.rot90(m, k=1, axes=(0, 1))
이 함수는 반시계방향으로 원소를 몇 칸이나 옮길지(k)에 따라서 값이 달라지게 됩니다. 만약, 시계방향으로 돌리고 싶다면 k를 -1로 설정하면 됩니다. 아래의 예시를 보도록 하겠습니다.
m = np.array([[1,2],[3,4]], int)
# array([[1, 2],
# [3, 4]])
np.rot90(m)
# array([[2, 4],
# [1, 3]])
np.rot90(m, k=-1)
# array([[3, 1],
# [4, 2]])
이와 같이 오늘은 단순하지만 강력한 기능을 하는 flip, roll, rot90 함수에 대해서 알아보았습니다. 다음 포스팅에서는 넘파이 배열에서의 bitwise 연산에 대해서 알아보도록 하겠습니다.
'Programming > Python' 카테고리의 다른 글
넘파이 알고 쓰자 - Bit packing & output formatting (0) | 2020.09.13 |
---|---|
넘파이 알고 쓰자 - Elementwise bit operations (0) | 2020.09.08 |
넘파이 알고 쓰자 - 넘파이의 원소 제거 및 추가(delete, add) (0) | 2020.09.01 |
넘파이 알고 쓰자 - 배열 복붙하기(Tiling) (0) | 2020.08.30 |
넘파이 알고 쓰자 - split (0) | 2020.08.28 |