将RGB IplImage转换为3个数组

时间:2009-10-14 19:12:10

标签: c++ performance arrays opencv iplimage

我需要一些C ++ /指针帮助。当我创建RGB IplImage并且我想访问i时,我使用以下C ++类:http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.html

template<class T> class Image
{
private:
    IplImage* imgp;

public:
    Image(IplImage* img=0) {imgp=img;}
    ~Image(){imgp=0;}
    void operator=(IplImage* img) {imgp=img;}
    inline T* operator[](const int rowIndx) {
        return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));}
};

typedef struct{
  unsigned char b,g,r;
} RgbPixel;

typedef struct{
  float b,g,r;
} RgbPixelFloat;

typedef Image<RgbPixel>       RgbImage;
typedef Image<RgbPixelFloat>  RgbImageFloat;
typedef Image<unsigned char>  BwImage;
typedef Image<float>          BwImageFloat;

我一直在使用CUDA,所以有时我必须将所有数据放入一个数组中,我喜欢将每个通道保存在自己的数组中,这样看起来更容易处理数据。所以我通常会做这样的事情:

IplImage *image = cvLoadImage("whatever.tif");
RgbImageFloat img(image);
for(int i = 0; i < exrIn->height; i++)
{
    for(int j = 0; j < exrIn->width; j++)
    {
        hostr[j*data->height+i] = img[i][j].r;
        hostg[j*data->height+i] = img[i][j].g;
        hostb[j*data->height+i] = img[i][j].b;
    }
}

然后我会将我的数据复制到设备上,用它做一些事情,把它拿回主机然后再循环,然后通过数组将数据分配回IplImage并保存我的结果。

似乎我已经循环到很多,必须有一个更快的方法用指针做这个,但我迷路了,必须有一个更有效的方法来做到这一点。有没有办法可以简单地为每个频道使用指针?我尝试过做这样的事情,但它不起作用:

float *hostr = &img[0][0].r
float *hostg = &img[0][0].b
float *hostb = &img[0][0].g

有什么建议吗?谢谢!

编辑:  谢谢大家回答。也许我对自己的问题不太清楚。我熟悉如何访问频道及其数据。我感兴趣的是提高从IplImage到标准阵列完全复制数据的性能和效率,更多的是csl到目前为止所说的。我看到的问题是IplImage中的数据排列方式是“rgbrgbrgbrgb”。

2 个答案:

答案 0 :(得分:5)

首先,如果你对C ++感到满意,你应该考虑使用OpenCV 2.0来消除图像和矩阵的不同数据类型(IplImage*CvMat*)并使用一个结构(Mat)处理两者。除了自动内存管理和大量有用的例程来处理频道等,以及一些MATLAB特别的例程,使用它真的很有趣。

针对您的具体问题,您可以使用IplImage*访问Mat的频道,如下所示:

 IplImage *image = cvLoadImage("lena.bmp");
 Mat Lena(image);
 vector<Mat> Channels;
 split(Lena,Channels);
 namedWindow("LR",CV_WINDOW_AUTOSIZE);
 imshow("LR",Channels[0]);
 waitKey();

现在,您拥有vector Channels中每个频道的副本。

如果您想要使用OpenCV2.0并提取频道,请注意以下事项。 OpenCV以下列方式订购多通道图像:

x(1,1,1) x(1,1,2) x(1,1,3) x(1,2,1) x(1,2,2) x(1,2,3) ...

其中x(i,j,k) = an element in row i of column j in channel k

此外,OpenCV 填充它的图像..所以不要忘记用widthStep跳转行来解释这些填充空白。沿着csl said的行,在外部循环中增加行指针(使用widthStep)并增加此指针以访问行中的元素。

注意:

由于您现在使用的是2.0,因此可以使用IplImage*绕过Mat Lena = imread("Lena.bmp");

答案 1 :(得分:1)

这里有改进很多的空间。这么多,您应该了解人们如何访问位图。

首先,尽可能增加内存位置。这将增加缓存命中和性能。即,不要为每个颜色通道使用三个单独的数组。将每个存储在一起,因为您可能主要使用像素。

其次,不要为每个像素进行y *宽度计算。在内循环中完成时,它会消耗很多周期。

最后,如果你只想要一个完整的图像副本,那么你可以简单地做一个memcpy(),这非常快。我无法推断你是否从浮点数转换为整数,但如果没有,则将memcpy()用于非重叠区域。

如果您想知道如何使用指针(伪代码,还有未经过测试)来实现这一点:

float *dst = &hostg[0][0];
RgbPixelFloat *src = &img[0][0];
RgbPixelFloat *end = &img[HEIGHT][WIDTH] + 1;

// copy green channel of whole image
while ( src != end )  {
    *dst = src->g;
    ++dst;
    ++src;
}