픽셀 밍을 수행해야한다고 가정하면 전체적인 문제를 살펴 보겠습니다. 30000x4000 픽셀의 중간 이미지는 8 비트 회색의 경우 이미지 데이터가 120M이고 16 비트 이미지 데이터가 240M입니다. 따라서이 방법으로 데이터를 살펴 본다면 "30 분이면 합리적입니까?"라고 물어볼 필요가 있습니다. 90도 회전을 수행하기 위해서는 최악의 문제, 즉 메모리를 유발할 수 있습니다. 행 하나를 채우기 위해 단일 열의 모든 픽셀을 터치하고 있습니다. 행렬로 작업한다면 최소한 메모리 발자국을 두 배로 늘리지는 않을 것입니다.
픽셀의 120M은 120M 읽기 및 120M 쓰기 또는 240M 데이터 액세스를하는 것을 의미합니다. 이것은 초당 대략 66,667 픽셀을 처리하고 있다는 것을 의미합니다. 너무 느린 것 같습니다. 제 생각에는 적어도 초당 120 만 화소의을 처리해야한다고 생각합니다.
이것이 저라면, 프로파일 링 도구를 실행하고 병목 현상이 발생한 위치를 확인한 후이를 잘라 냈습니다. 정확한 구조를 알고 생각하지 않고
, 나는 다음을 수행합니다 : 소스 이미지의 메모리 하나 개의 연속 블록을 사용하는
시도를는
나는 회전을 볼 원합니다 함수는 다음과 같습니다 :
void RotateColumn(int column, char *sourceImage, int bytesPerRow, int bytesPerPixel, int height, char *destRow)
{
char *src = sourceImage + (bytesPerPixel * column);
if (bytesPerPixel == 1) {
for (int y=0; y < height; y++) {
*destRow++ = *src;
src += bytesPerRow;
}
}
else if (bytesPerPixel == 2) {
for (int y=0; y < height; y++) {
*destRow++ = *src;
*destRow++ = *(src + 1);
src += bytesPerRow;
// although I doubt it would be faster, you could try this:
// *destRow++ = *src++;
// *destRow++ = *src;
// src += bytesPerRow - 1;
}
}
else { /* error out */ }
}
저는 루프의 내부가 아마도 8 개의 명령어로 바뀔 것이라고 생각합니다. 2GHz 프로세서에서 (명 령적으로 명령 당 4 사이클, 이는 추측 일뿐입니다), 초당 6 억 2 천 5 백만 픽셀을 회전시킬 수 있어야합니다. 대충.
연속적으로 수행 할 수없는 경우 한 번에 여러 대상 스캔 라인에서 작업하십시오.
소스 이미지가 블록으로 분할되거나 메모리의 추상화 된 스캔 라인이있는 경우 원본 이미지에서 스캔 라인을 가져 와서 한 번에 몇 개의 열을 대상 스캔 라인의 버퍼로 회전해야합니다.
스캔 라인을 획득하고 릴리스 할 수있는 추상적으로 스캔 라인에 액세스하는 메커니즘이 있다고 가정 해 보겠습니다. 이 경우
void RotateNColumns(Pixels &source, Pixels &dest, int startColumn, int nCols)
{
PixelRow &rows[nRows];
for (int i=0; i < nCols; i++)
rows[i] = dest.AcquireRow(i + startColumn);
for (int y=0; y < source.Height(); y++) {
PixelRow &srcRow = source.AcquireRow();
for (int i=0; i < nCols; i++) {
// CopyPixel(int srcX, PixelRow &destRow, int dstX, int nPixels);
sourceRow.CopyPixel(startColumn + i, rows[i], y, 1);
}
source.ReleaseRow(srcRow);
}
for (int i=0; i < nCols; i++)
dest.ReleaseAndWrite(rows[i]);
}
: 당신이 코드는 다음과 같이 보일 것이기 때문에
그런 다음 당신이해야 할 겁니다 것은, 당신이 한 번에 처리 할 의사가있는 많은 소스 열 알아낼 스캔 라인의 큰 블록에 원본 픽셀을 버퍼링하면 반드시 힙을 조각 내고있는 것은 아니며 디코딩 된 행을 디스크로 플러시 할 수 있습니다. 한 번에 n 개의 열을 처리하고 메모리 지역성을 n 배로 향상시켜야합니다. 그렇다면 캐싱이 얼마나 비싼 지에 대한 질문이됩니다.
병렬 처리로 문제를 해결할 수 있습니까?
정직하게 말하자면, 귀하의 문제는 CPU 바인딩이 아닌 IO 바인딩이어야한다고 생각합니다. 나는 당신의 디코딩 시간이 지배적이라고 생각할 것이다. 그러나 그것이 웃지 않는 척하지 말자.
원본 이미지를 한 번에 전체 행을 읽으면 디코딩 된 행을 대상 이미지의 해당 열에 쓰는 스레드로 던질 수 있습니다. 따라서 OnRowDecoded (byte * row, int y, int width, int bytesPerPixel)와 같은 메서드를 갖도록 디코더를 작성하십시오. 그리고 나서 해독하는 동안 회전하고 있습니다. OnRowDecoded()는 정보를 압축하여 대상 이미지를 소유 한 스레드로 전달하고 디코딩 된 전체 행을 올바른 대상 열에 씁니다. 이 스레드는 주 스레드가 다음 행을 디코딩하는 동안 사용중인 모든 쓰기를 수행합니다. 작업자 스레드가 먼저 완료되지만 가능하지 않을 수 있습니다.
destPermel()을 스레드로부터 안전하게 만들 필요가 있지만 그 외의 경우에는 직렬 작업이어야합니다. 실제로 원본 이미지에서 TIFF 기능을 사용하여 밴드 나 타일로 나눠서 사용하는 경우이를 병렬로 해독하거나 할 수 있습니다.
글쎄, 내가 생각할 수있는 최선의 * 메타 최적화는 이미지를 회전시키지 않고 회전하지 않는 형식으로 작업하는 것입니다. 이미지를 회전하는 것보다 다운 스트림 프로세스가 작동하는 방식을 조정하여 성능을 향상시킬 수 있습니다.나는 당신이 이미 이것을 고려하고 그것을 거부했기를 기대합니다. 나는 이미 회전 된 이미지를 캡쳐하는 것을 고려하고 거부 할 것을 기대합니다 (카메라를 옆으로 돌리거나 무엇이든). –
불행히도 수신 컴퓨터는 블랙 박스이며 회전 된 형태로만 데이터를 받아들이는 반면 설계 프로세스는 이미지를 회전하지 않는 방식으로 뱉어냅니다. 이 둘 사이를 연결해야하며 데이터 자체에는 영향을주지 않아야합니다. – nullp01nter
나는 당신이 아마 오래 전에 풀었던 낡은 질문을 안다. 그러나 이런 종류의 일을 위해 고안된'VIPS'를 살펴볼 수는있다 ... http://www.vips.ecs.soton.ac. uk/index.php? title = VIPS –