交换2个记忆位置

时间:2010-04-01 07:34:49

标签: c++ qt optimization opencv

我正在使用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 个答案:

答案 0 :(得分:5)

我们目前正在Qt应用程序中处理此问题。我们发现英特尔性能基元是最快的方法。他们有极其优化的代码。在Intel ippiSwapChannels Documentation的html帮助文件中,他们提供了您正在寻找的确切示例。

有几个缺点

  1. 是库的大小,但您可以链接静态链接,只需要您需要的库例程。
  2. 在AMD cpus上运行。默认情况下,Intel libs运行速度非常慢。有关如何解决的详细信息,请访问www.agner.org/optimize/asmlib.zip。

答案 1 :(得分:4)

我认为这看起来非常好。代码很简单不是否定。如果您想缩短它,可以使用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 :(得分:2)

cvConvertImage在一行中完成整个事情,但我怀疑它是否更快。

答案 3 :(得分:2)

您是否可以使用以下方法之一?

void QImage::invertPixels ( InvertMode mode = InvertRgb )

QImage QImage::rgbSwapped () const

希望这有点帮助!

答案 4 :(得分:1)

我倾向于做类似以下的事情,根据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;
}

我怀疑它是否“更快”但是在一天结束时,你只需逐个像素地浏览整个图像。

答案 5 :(得分:1)

您可以随时执行此操作:

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进行此转换。如果你真的很幸运,那么可以在图形硬件中完成。

答案 6 :(得分:0)

我讨厌破坏任何人的一天,但是如果你不想去IPP路线(见photo_tom)或拉入一个优化的库,你可能会从以下方面获得更好的表现(修改Andreas答案):

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,那么,它是愚蠢的,我会因为浪费你的时间而道歉。

答案 7 :(得分:0)

cvCvtColor(iplImage, iplImage, CV_BGR2RGB);