обмен 2-мя позициями в памяти - PullRequest
3 голосов
/ 01 апреля 2010

Я работаю с OpenCV и Qt, Opencv использует BGR, а Qt использует RGB, поэтому я должен поменять эти 2 байта для очень больших изображений.

Есть ли лучший способ сделать следующее? Я не могу придумать ничего быстрее, но выглядит так просто и отстойно ...

    int width = iplImage->width;
 int height = iplImage->height;

 uchar *iplImagePtr = (uchar *) iplImage->imageData;
 uchar buf;
 int limit = height * width;

 for (int y = 0; y < limit; ++y) {
  buf = iplImagePtr[2];
  iplImagePtr[2] = iplImagePtr[0];
  iplImagePtr[0] = buf;
  iplImagePtr += 3;
 }

 QImage img((uchar *) iplImage->imageData, width, height,
     QImage::Format_RGB888);

Ответы [ 8 ]

5 голосов
/ 02 апреля 2010

В настоящее время мы решаем эту проблему в приложении Qt. Мы обнаружили, что Intel Performance Primitives - это самый быстрый способ сделать это. У них чрезвычайно оптимизированный код. В html-файлах справки Документация Intel ippiSwapChannels они содержат пример того, что вы ищете.

Есть пара минусов

  1. Это размер библиотеки, но вы можете связать статическую ссылку только те библиотеки, которые вам нужны.
  2. Работает на процессоре AMD. По умолчанию процессоры Intel работают ОЧЕНЬ медленно. Посетите сайт www.agner.org/optimize/asmlib.zip, чтобы узнать, как обойти эту проблему.
4 голосов
/ 01 апреля 2010

Я думаю, это выглядит абсолютно нормально. То, что код прост, не является чем-то отрицательным . Если вы хотите сделать его короче, вы можете использовать std::swap:

std::swap(iplImagePtr[0], iplImagePtr[2]);

Вы также можете сделать следующее:

 uchar* end = iplImagePtr + height * width * 3;
 for ( ; iplImagePtr != end; iplImagePtr += 3) {
    std::swap(iplImagePtr[0], iplImagePtr[2]);
 }
2 голосов
/ 01 апреля 2010

Не могли бы вы использовать один из следующих методов?

void QImage::invertPixels ( InvertMode mode = InvertRgb )

или

QImage QImage::rgbSwapped () const

Надеюсь, это немного поможет!

2 голосов
/ 01 апреля 2010

Есть cvConvertImage , чтобы сделать все это в одну строку, но я сомневаюсь, что это тоже быстрее.

1 голос
/ 01 апреля 2010

Вы всегда можете сделать это:

int width = iplImage->width;
int height = iplImage->height;
uchar *start = (uchar *) iplImage->imageData;
uchar *end = start + width * height;

for (uchar *p = start ; p < end ; p += 3)
{
   uchar buf = *p;
   *p = *(p+2);
   *(p+2) = buf;
}

но приличный компилятор все равно сделает это.

Самыми большими издержками при подобных операциях будет пропускная способность памяти.

Если вы используете Windows, вы, вероятно, можете сделать это преобразование, используя BitBlt и два соответственно настроенных DIB. Если вам действительно повезло, это можно сделать с помощью графического оборудования.

1 голос
/ 01 апреля 2010

Я был бы склонен сделать что-то вроде следующего, работая на основе того, что данные RGB находятся в трехбайтовых блоках.

int i = 0;
int limit = (width * height); // / 3;
while(i != limit)
{
  buf = iplImagePtr[i]; // should be blue colour byte
  iplImagePtr[i] = iplImagaePtr[i + 2]; // save the red colour byte in the blue space
  iplImagePtr[i + 2] = buf; // save the blue color byte into what was the red slot
  // i++;
  i += 3;
}

Я сомневаюсь, что это «быстрее», но в конце дня вам просто нужно просмотреть все изображение, пиксель за пикселем.

0 голосов
/ 05 июня 2010
cvCvtColor(iplImage, iplImage, CV_BGR2RGB);
0 голосов
/ 02 апреля 2010

Я не хочу испортить чей-либо день, но если вы не хотите идти по пути IPP (см. Photo_tom) или использовать оптимизированную библиотеку, вы можете получить более высокую производительность из следующего (модифицируя ответ Андреаса):

uchar *iplImagePtr = (uchar *) iplImage->imageData;
uchar buf;
size_t limit = height * width;

for (size_t y = 0; y < limit; ++y) {
    std::swap(iplImagePtr[y * 3], iplImagePtr[y * 3 + 2]);
}

Теперь подождите, ребята, я слышу, как вы кричите "но все эти дополнительные умножения и добавления!" Дело в том, что эту форму цикла проще оптимизировать компилятору намного , особенно если он становится достаточно умным для многопоточности такого рода алгоритма, потому что каждый проход цикла не зависит от до или после. В другой форме значение iplImagePtr зависело от значения в предыдущем проходе. В этой форме это константа по всему циклу; изменяется только y, и это в очень, очень распространенной конструкции цикла «считать от 0 до N-1», поэтому оптимизатору легче переварить.

Или, может быть, это не имеет значения в наши дни, потому что оптимизаторы безумно умны (не так ли?). Интересно, что бы сказал тест?

P.S. Если вы действительно сравните это, я также хотел бы увидеть, насколько хорошо работает следующее:

uchar *iplImagePtr = (uchar *) iplImage->imageData;
uchar buf;
size_t limit = height * width;

for (size_t y = 0; y < limit; ++y) {
    uchar *pixel = iplImagePtr + y * 3;
    std::swap(pix[0], pix[2]);
}

Опять же, pixel определен в цикле, чтобы ограничить его область действия и не дать оптимизатору думать, что существует циклическая зависимость. Если компилятор увеличивает и уменьшает указатель стека каждый раз в цикле для «создания» и «уничтожения» pixel, что ж, это глупо, и я извинюсь за трату вашего времени.

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