분리 가능한 필터를 살펴보십시오. 무엇보다도 그들은 작동하는 곳에서 대규모 병렬 처리를 허용합니다. 3x3로하여 샘플의 중량 및 필터의 경우, 예를 들어
:
- 샘플 1 × (가로) 화소 버퍼로. 이는 각 픽셀에 대해 독립적으로 수행 할 수 있으므로 1024x1024 이미지는 1024^2 동시 작업을 실행할 수 있으며이 작업은 모두 3 개의 샘플을 수행합니다.
- 버퍼의 샘플 3x1 (수직) 픽셀 . 다시 한번, 이것은 모든 픽셀에서 동시에 수행 될 수 있습니다.
- 버퍼 내용을 사용하여 원래 텍스처의 픽셀을 제거합니다.
이 방법의 장점은, 수학적으로는 소스에 동일한 크기의 버퍼를 필요로하지만, 이미 사본을 수행하는 경우가 있음을, (n^2
에서 2n
에 샘플 작업의 수를 삭감한다는 것입니다 버퍼로 사용할 수 있으며 2 단계에서 원본 소스를 수정할 수 없습니다. 메모리 사용량을 2n
으로 유지하려면 2 단계와 3 단계를 함께 수행 할 수 있습니다 (다소 힘들고 완전히 즐겁지는 않습니다). 메모리가 문제가되지 않으면 3n
을 두 개의 버퍼 (source, hblur, vblur)에 보낼 수 있습니다.
각 작업이 불변 소스와 완전히 분리되어 작동하기 때문에 코어가 충분하면 모든 픽셀에서 동시에 필터를 수행 할 수 있습니다. 또는보다 현실적인 시나리오에서 페이징 및 캐싱을 활용하여 단일 열이나 행을로드하고 처리 할 수 있습니다. 홀수 스트라이드, 행 끝의 패딩 등으로 작업 할 때 편리합니다. 두 번째 샘플 (세로)은 캐시와 결합 될 수 있지만, 최악의 경우 한 라운드는 캐시 친화적 일 것입니다. 처리를 지수에서 선형으로 자른다.
이제 데이터를 비트 단위로 저장하는 경우에 대해서는 아직 다루지 않았습니다. 그것은 상황을 약간 더 복잡하게 만들지 만 그다지 심각하지는 않습니다. 롤 창을 사용할 수 있다고 가정하면 다음과 같이됩니다.
d = s[x-1] + s[x] + s[x+1]
이 작동합니다. 흥미롭게도, 1 단계의 출력 (예 : 읽을 때 (y,x)
의 샘플)에서 이미지를 90도 회전하려면 모든 샘플에 대해 수평 적으로 인접한 바이트 두 개와 같은 단일 바이트 만로드하면됩니다. 시간의 75 %. 이것은 읽는 동안 캐시와 약간 덜 친숙하지만, 알고리즘을 크게 단순화합니다 (손실을 되찾기에 충분할 정도로).
의사 코드 :
buffer source, dest, vbuf, hbuf;
for_each (y, x) // Loop over each row, then each column. Generally works better wrt paging
{
hbuf(x, y) = (source(y, x-1) + source(y, x) + source(y, x+1))/3 // swap x and y to spin 90 degrees
}
for_each (y, x)
{
vbuf(x, 1-y) = (hbuf(y, x-1) + hbuf(y, x) + hbuf(y, x+1))/3 // 1-y to reverse the 90 degree spin
}
for_each (y, x)
{
dest(x, y) = threshold(hbuf(x, y))
}
바이트 내의 비트 액세스는 (source(x, y)
액세스/샘플을 나타냄)을 수행하는 것이 비교적 간단하지만, 통증의 종류는, 여기에서 매우 독자의 몫이다 써내. 이 방식 (90도 회전)으로 구현 된 원리는 각각 n
개의 샘플을 2 회 통과해야하며 항상 바로 인접한 비트/바이트로부터 샘플링합니다 (다음 행의 비트 위치를 계산할 필요가 없음) . 대체로 어떤 방법보다 훨씬 빠르고 간단합니다.
이미지 너비가 8의 배수입니까, 아니면 각 행이 바이트 경계에서 시작되도록 패딩 된 선입니까? 그것은 대개의 경우이며, 상황이 좀 더 쉬워집니다. 9 대신에 3 개의 마스크 만 필요합니다. –
이미지 너비는 임의이지만 각 줄은 바이트 경계에서 시작됩니다. 행은 더 큰 경계에 패딩 될 수 있지만 바이트로 채워질 수 있습니다. – theotherphil
가장자리의 채우기 방법은 무엇입니까? 반복 또는 클램프? – Ani