将 RGB IplImage 转换为 3 个数组
我需要一些 C++/指针帮助。当我创建 RGB IplImage 并且想要访问 i,j 时,我使用以下 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”。
I need some C++/pointer help. When I create an RGB IplImage and I want to access i,j I use the following C++ class taken from: 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;
I've been working with CUDA so sometimes I have to put all the data into an array, I like to keep every channel in its own array, seems easier to handle the data that way. So I would usually do something like this:
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;
}
}
I would then copy my data to the device, do some stuff with it, get it back to the host and then loop, yet again, through the array assigning the data back to the IplImage and saving my results.
It seems like I'm looping to much there has to be a faster way to do this with pointers but I'm lost, there has to be a more efficient way to do it. Is there a way I can simply use a pointer for every channel? I tried doing something like this but it didn't work:
float *hostr = &img[0][0].r
float *hostg = &img[0][0].b
float *hostb = &img[0][0].g
Any suggestions? Thanks!
EDIT:
Thanks everyone for answering. Maybe I wasn't very clear on my question. I am familiar on how to access channels and their data. What I am interested is in increasing the performance and efficiency of completely copying data off the IplImage to a standard array, more along the lines of what csl said so far. The problem I see is that the way data in an IplImage is arranged is "rgbrgbrgbrgb".
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,如果您熟悉 C++,您应该考虑使用 OpenCV 2.0,它消除了不同的图像和矩阵的数据类型(
IplImage*
和CvMat*
),并使用一种结构 (Mat
) 来处理两者。除了自动内存管理和大量用于处理通道等的有用例程以及一些 MATLAB 风格的例程之外,它使用起来非常有趣。对于您的具体问题,您可以使用
Mat
访问IplImage*
的通道,如下所示:现在您拥有
vector
中每个通道的副本>渠道
。如果您不想使用
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) = 通道 k 中 j 列 i 行的元素
另外,OpenCV 填充它是图像..所以不要忘记使用
widthStep
跳转行,它会解释这些填充间隙。按照 csl 所说的,增加行数外循环中的指针(使用widthStep
)并递增该指针以访问行中的元素。注意:
由于您现在使用的是 2.0,因此您可以使用
Mat Lena = imread("Lena.bmp");
绕过IplImage*
。Firstly, if you're comfortable with C++, you should consider using OpenCV 2.0 which does away with different data types for images and matrices (
IplImage*
andCvMat*
) and uses one structure (Mat
) to handle both. Apart from automatic memory management and a truckload of useful routines to handle channels, etc. and some MATLAB-esque ones as well, it's really fun to use.For your specific problem, you access the channels of an
IplImage*
withMat
, like this:Now you have the copies of each channel in the
vector
Channels
.If you don't want to use
OpenCV2.0
and extract channels, note the following. OpenCV orders multi-channel images in the following manner:x(1,1,1) x(1,1,2) x(1,1,3) x(1,2,1) x(1,2,2) x(1,2,3) ...
where
x(i,j,k) = an element in row i of column j in channel k
Also, OpenCV pads it's images .. so don't forget to jump rows with
widthStep
which accounts for these padding gaps. And along the lines of what csl said, increase your row pointer in the outer loop (usingwidthStep
) and increment this pointer to access elements in a row.NOTE:
Since you're using 2.0 now, you can bypass
IplImage*
withMat Lena = imread("Lena.bmp");
.这里还有很多改进的空间。这么多,您应该阅读人们如何访问位图。
首先,尽可能增加内存局部性。这将增加缓存命中率和性能。即,不要为每个颜色通道使用三个单独的数组。将它们存储在一起,因为您可能主要在像素上工作。
其次,不要对每个像素进行 y*width 计算。当在内循环中完成时,它会消耗很多周期。
最后,如果您只想要图像的完整副本,那么您可以简单地执行 memcpy(),这非常快。我无法推断您是否从浮点数转换为整数,但如果没有,请对非重叠区域使用 memcpy() 。
如果您想知道如何使用指针来做到这一点(一种伪代码,也未经测试):
There is room for a lot of improvement here. So much, that you should read up on how people access bitmaps.
First of all, increase memory locality as much as possible. This will increase cache hits, and performance. I.e., don't use three separate arrays for each color channel. Store each together, since you probably will be working mostly on pixels.
Secondly, don't do that y*width calculation for every pixel. When done in an inner loop, it consumes a lot of cycles.
Lastly, if you just want a complete copy of the image, then you could simply do a memcpy(), which is very fast. I couldn't deduce if you converted from floats to integers, but if not, use memcpy() for non-overlapping regions.
If you wonder how you can do this with pointers (kind of pseudo-code, and also not tested):