2015-03-03 3 views
1

Я написал небольшую функцию для масштабирования изображения до определенного размера без обрезки его (добавлением черных границ для его соответствия), и он работает, но он очень медленный, особенно при высоких разрешениях. Пожалуйста, взгляните и скажите, как я могу повысить эффективность функции. Или если есть лучший код, который я могу использовать для достижения того же результата.Быстрое масштабирование растрового изображения

static int ReScale(char* srcBuffer, int srcLen, int srcStart, int srcStride, int srcHeight, VideoInfo::ePixelFormat srcPixelFormat, 
        char* dstBuffer, int dstLen, int dstStart, int dstStride, int dstHeight, VideoInfo::ePixelFormat dstPixelFormat, bool reverseCopy) 
{ 
    int srcPixelDepth = VideoInfo::GetPixelFormatSize(srcPixelFormat); 
    int srcWidth = static_cast<int>(floor(srcStride/static_cast<float>(srcPixelDepth))); 
    int dstPixelDepth = VideoInfo::GetPixelFormatSize(dstPixelFormat); 
    int dstWidth = static_cast<int>(floor(dstStride/static_cast<float>(dstPixelDepth))); 

    float resizeRatio = min(dstWidth/static_cast<float>(srcWidth), dstHeight/static_cast<float>(srcHeight)); 
    int dstXOffset = static_cast<int>((dstWidth - (resizeRatio * srcWidth))/2.f); 
    int dstYOffset = static_cast<int>((dstHeight - (resizeRatio * srcHeight))/2.f); 
    ZeroMemory(dstBuffer + dstStart, dstLen); 

    srcBuffer += srcStart; 
    dstBuffer += dstStart; 

    dstWidth -= 2 * dstXOffset; 
    dstHeight -= 2 * dstYOffset; 

    int dstPixelOffset = 0; 
    int srcPixelOffset = 0; 
    for (int y = 0; y < dstHeight; y++) 
    { 
     dstPixelOffset = dstXOffset * dstPixelDepth + (y + dstYOffset) * dstStride; 
     for (int x = 0; x < dstWidth; x++) 
     { 
      srcPixelOffset = static_cast<int>(min(y/resizeRatio, srcHeight)); 
      if (reverseCopy) 
      { 
       srcPixelOffset = srcHeight - (srcPixelOffset + 1); 
      } 
      srcPixelOffset = static_cast<int>(min(x/resizeRatio, srcWidth)) * srcPixelDepth + srcPixelOffset * srcStride; 
      if (srcPixelOffset + srcPixelDepth < srcLen && dstPixelOffset + dstPixelDepth < dstLen) 
      { 
       memcpy(dstBuffer + dstPixelOffset, srcBuffer + srcPixelOffset, srcPixelDepth); 
      } 
      dstPixelOffset += dstPixelDepth; 
     } 
    } 
    return 0; 
} 

Опции компилятора *:

/GS /analyze- /W3 /Zc:wchar_t /I"C:\Program Files (x86)\Microsoft Visual 
/Studio 12.0\VC\include" /I"C:\Program Files (x86)\Microsoft Visual 
/Studio 12.0\VC\PlatformSDK\include" /I"C:\Program Files (x86)\Windows 
/Kits\8.1\include" /Zi /Gm- /O2 /Fd"Release\vc120.pdb" /fp:precise /D 
/"WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_WINDLL" /D 
/"_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gz /Oy-/MD 
/Fa"Release\" /EHsc /nologo /Fo"Release\" /Fp"Release\*****.pch" 

Профилирование Результат *: Profiling Result

+0

Можете ли вы добавить какие опции компилятора вы используете? Не нужно оптимизировать код, когда компилятор может сделать это за вас. –

+1

Слишком много операций деления - обычно это медленно. Попробуйте заменить все '/ resizeRatio' на' * resizeCoef' (и добавить после объявления строки resizeRatio 'const float resizeCoef = 1.0/resizeRatio'). – Ilya

+0

И вы должны сделать быстрый профиль, если сможете, чтобы определить свое узкое место. Если ваши изображения очень большие, вы также можете ограничить пропускную способность памяти. – Tafuri

ответ

0

Refactored функцию, чтобы применить ваши предложения и позволили SSE2 и FP: быстрые варианты. Производительность увеличилась на 3x:

static int ReScale(char* srcBuffer, int srcLen, int srcStart, int srcStride, int srcHeight, VideoInfo::ePixelFormat srcPixelFormat, 
        char* dstBuffer, int dstLen, int dstStart, int dstStride, int dstHeight, VideoInfo::ePixelFormat dstPixelFormat, bool reverseCopy) 
{ 
    int srcPixelDepth = VideoInfo::GetPixelFormatSize(srcPixelFormat); 
    int srcWidth = static_cast<int>(floor(srcStride/static_cast<float>(srcPixelDepth))); 
    int dstPixelDepth = VideoInfo::GetPixelFormatSize(dstPixelFormat); 
    int dstWidth = static_cast<int>(floor(dstStride/static_cast<float>(dstPixelDepth))); 

    float resizeRatio = min(dstWidth/static_cast<float>(srcWidth), dstHeight/static_cast<float>(srcHeight)); 
    int dstXOffset = static_cast<int>((dstWidth - (resizeRatio * srcWidth))/2.f); 
    int dstYOffset = static_cast<int>((dstHeight - (resizeRatio * srcHeight))/2.f); 
    ZeroMemory(dstBuffer + dstStart, dstLen); 

    srcBuffer += srcStart; 
    dstBuffer += dstStart; 

    dstWidth -= 2 * dstXOffset; 
    dstHeight -= 2 * dstYOffset; 

    int dstPixelOffset = 0; 
    int srcPixelOffset = 0; 
    int srcPixelYOffset = 0; 
    float srcPixelXOffset = 0; 
    float srcPixelXStride = 1/resizeRatio; 
    int pixelDepthSize = min(srcPixelDepth, dstPixelDepth); 
    for (int y = 0; y < dstHeight; y++) 
    { 
     dstPixelOffset = dstXOffset * dstPixelDepth + (y + dstYOffset) * dstStride; 
     srcPixelYOffset = static_cast<int>(min(y/resizeRatio, srcHeight)); 
     srcPixelYOffset = (reverseCopy ? (srcHeight - (srcPixelYOffset + 1)) : srcPixelYOffset) * srcStride; 
     srcPixelXOffset = 0; 
     for (int x = 0; x < dstWidth; x++) 
     { 
      srcPixelOffset = srcPixelYOffset + (static_cast<int>(min(srcPixelXOffset, srcWidth)) * srcPixelDepth); 
      if (srcPixelOffset + pixelDepthSize < srcLen && dstPixelOffset + pixelDepthSize < dstLen) 
      { 
       memcpy(dstBuffer + dstPixelOffset, srcBuffer + srcPixelOffset, pixelDepthSize); 
      } 
      dstPixelOffset += dstPixelDepth; 
      srcPixelXOffset += srcPixelXStride; 
     } 
    } 
    return 0; 
} 

Особая благодарность @MOehm, @Tafuri и других комментаторам

+0

Интересно, каков был эффект SSE2 и fp: быстрые варианты. Я имею в виду: «Какова производительность без этих параметров?» – simurg

+0

@simurg, я удалил результаты профилирования, но я помню, что это было как 5-4% использования ЦП на 4-3%, примерно на 20%. –

+0

Я считаю, что лучше измерить время, необходимое для выполнения задачи, но я думаю, вы не можете изолировать эту функцию от остальной части вашего кода. – simurg

Смежные вопросы