как мне оптимизировать этот цикл дальше? - PullRequest
1 голос
/ 15 октября 2011

Ну, этот пост является причиной Почему memcpy () и memmove () быстрее, чем приращение указателя?

У меня есть пользовательская структура изображения с 4 каналами, и мне нравитсяизвлечь 3 из них (RGB) в openCV cv :: MAt strcuture с 3 каналами.

cv::Mat GetColorImgFromFrame(Image* pimg)
{
    int iHeight = pimg->m_imageInfo.m_height;
    int iWidth = pimg->m_imageInfo.m_width;

    cv::Mat cvmColorImg = cv::Mat::zeros(iHeight, iWidth, CV_8UC3);
    int iDestStep = cvmColorImg.channels(); // 3

    uchar* pucSrc = pimg->m_data;    
    uchar* pucDest = cvmColorImg.data;
    uchar* pucDestLimit = cvmColorImg.data + iHeight*iWidth*iDestStep;

    for (;pucDest < pucDestLimit;)
    {       
        *(pucDest++) = *(pucSrc++);
        *(pucDest++) = *(pucSrc++);
        *(pucDest++) = *(pucSrc++);
        pucSrc++;
    }

    return cvmColorImg;
}

Кажется не слишком полезным заменить три внутренних назначения на memcpy (pucDest, pucSrc, 3),Какие-либо предложения?

Ответы [ 3 ]

3 голосов
/ 15 октября 2011

Прежде чем перейти в режим «как ассемблер» с помощью SIMD intrinsic , вы можете попытаться сообщить компилятору, что указатель источника и назначения не имеет псевдонима, используя, например, ключевое слово __restrict__ с gcc или __restrict с визуальной студией

3 голосов
/ 15 октября 2011

На 32-битной машине вы можете попытаться скопировать 4 байта за цикл за один раз от источника к месту назначения, используя unsigned int *.Хитрость заключается в том, чтобы указатель pucDest и uchar увеличивался на 3. Вы имеете дело с последним словом в качестве особого случая, чтобы не нарушать границу массива целевого массива для последнего байта.

Поскольку копирование int обычно не медленнее, чем копирование char на большинстве машин, я подозреваю, что это даст вам увеличение скорости примерно в 3 раза.

1 голос
/ 15 октября 2011

Расширяя ответ Дока Брауна, разверните цикл так, чтобы вы писали три uint32_t целых числа для каждых четырех операций чтения (uint64_t потребует еще больших глотков, но с ними будет немного сложнее).

Чтение и запись целочисленных значений может быть проблематичным, если ваши pimg->m_data и cvmColorImg.data не начинаются с границы uint32_t. Это можно сделать, поставив элемент данных int или unsigned int перед этими элементами данных char*. Или вы можете использовать что-то похожее на устройство Даффа. Личные предпочтения: я бы просто принудил выравнивание. Это делает копию кода чище, проще и, возможно, быстрее. Несколько потраченных впустую байтов для заполнения - крошечная цена.

Как обычно для развернутых циклов, вам придется сделать что-то особенное для обработки конца. (Устройство Даффа обрабатывает странность с самого начала, поэтому не стоит останавливаться на устройстве Даффа.) Многие проблемы с обработкой конца цикла исчезнут, если вы добавите конец выходного буфера так, чтобы он занимал 4 * N байт. .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...