如何将 8 位 OpenCV IplImage* 转换为 32 位 IplImage*?
Posted
技术标签:
【中文标题】如何将 8 位 OpenCV IplImage* 转换为 32 位 IplImage*?【英文标题】:How to convert an 8-bit OpenCV IplImage* to a 32-bit IplImage*? 【发布时间】:2010-09-28 12:18:17 【问题描述】:我需要将 8 位 IplImage 转换为 32 位 IplImage。使用来自整个网络的文档,我尝试了以下方法:
// general code
img2 = cvCreateImage(cvSize(img->width, img->height), 32, 3);
int height = img->height;
int width = img->width;
int channels = img->nChannels;
int step1 = img->widthStep;
int step2 = img2->widthStep;
int depth1 = img->depth;
int depth2 = img2->depth;
uchar *data1 = (uchar *)img->imageData;
uchar *data2 = (uchar *)img2->imageData;
for(h=0;h<height;h++) for(w=0;w<width;w++) for(c=0;c<channels;c++)
// attempt code...
// attempt one
// result: white image, two red spots which appear in the original image too.
// this is the closest result, what's going wrong?!
// see: http://files.dazjorz.com/cache/conversion.png
((float*)data2+h*step2+w*channels+c)[0] = data1[h*step1+w*channels+c];
// attempt two
// when I change float to unsigned long in both previous examples, I get a black screen.
// attempt three
// result: seemingly random data to the top of the screen.
data2[h*step2+w*channels*3+c] = data1[h*step1+w*channels+c];
data2[h*step2+w*channels*3+c+1] = 0x00;
data2[h*step2+w*channels*3+c+2] = 0x00;
// and then some other things. Nothing did what I wanted. I couldn't get an output
// image which looked the same as the input image.
如你所见,我真的不知道自己在做什么。我很想知道,但如果我能正确完成这项工作,我会更喜欢它。 感谢您为我提供的任何帮助!
【问题讨论】:
【参考方案1】:您正在寻找的函数是 cvConvertScale()。它会自动为您进行任何类型转换。您只需指定要按 1/255 的因子进行缩放(将范围 [0...255] 映射到 [0...1])。
例子:
IplImage *im8 = cvLoadImage(argv[1]);
IplImage *im32 = cvCreateImage(cvSize(im8->width, im8->height), 32, 3);
cvConvertScale(im8, im32, 1/255.);
注意1/255.
中的点 - 强制双除。没有它,你得到的比例是 0。
【讨论】:
我试过了,但它不接受输出或输入比例。或者我只是用错了。 传递一个双倍作为比例因子很重要(这就是为什么在 255 后面有 '.')。 1/255 将评估为整数除法并导致比例因子为 0。您的代码到底是什么不适用于 cvConvertScale() ? 我希望我能投更多的赞成票,我也赞成你的评论和你的回答。我已经为此苦苦挣扎了至少 8 个小时! 对于使用 C++ API 的人:im8.convertTo(im32, CV_32FC1); 用cvGetSize(im8)
代替cvSize(im8->width, im8->height)
【参考方案2】:
也许这个link可以帮助你?
编辑响应OP的第二次编辑和评论
你试过了吗
float value = 0.5
而不是
float value = 0x0000001;
我认为浮点颜色值的范围是从 0.0 到 1.0,其中 1.0 是白色。
【讨论】:
该页面上有一些有趣的信息,解释了我已经尝试过的代码片段。然而,结果是一样的。请参阅以下链接以获取始终出错的示例:files.dazjorz.com/cache/conversion.png 哇,是的,这是一个很好的,你是对的!所以这给出了以下线索:对于红色斑点,R 是 1.0,GB 是 0.0,对于白色,这三个都是 1.0。所以在转换时,RGB 值应该从 0 到 255 到 0.0 到 1.0 转换。将值更改为 b / 255 会使图像变成黑色+红色。 知道了! int b = ((uchar )(img->imageData + himg->widthStep))[wimg->nChannels + 0]; // B ((float *)(img2->imageData + himg2->widthStep))[w*img2->nChannels + 0] = ((float)b) / 255.0;【参考方案3】:浮点颜色从 0.0 到 1.0,uchars 从 0 到 255。以下代码修复它:
// h is height, w is width, c is current channel (0 to 2)
int b = ((uchar *)(img->imageData + h*img->widthStep))[w*img->nChannels + c];
((float *)(img2->imageData + h*img2->widthStep))[w*img2->nChannels + c] = ((float)b) / 255.0;
非常感谢 Stefan Schmidt 帮助我解决这个问题!
【讨论】:
【参考方案4】:如果你不放点 (.),一些编译器会将它理解为 int 除法,给你一个 int 结果(在这种情况下为零)。
【讨论】:
【参考方案5】:您可以使用 boost::shared_ptr 和模板元编程来创建 IplImage 包装器。我已经这样做了,我得到了自动垃圾收集,以及从一个深度到另一个深度或从一个通道到多通道图像的自动图像转换。
我已经调用了 API blImageAPI,它可以在这里找到: http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/
速度非常快,代码可读性强,(有利于算法维护)
它也可以用来代替opencv算法中的IplImage而不需要改变任何东西。
祝你好运,写算法玩得开心!!!
【讨论】:
【参考方案6】:IplImage *img8,*img32; img8 =cvLoadImage("a.jpg",1);
cvNamedWindow("Convert",1);
img32 = cvCreateImage(cvGetSize(img8),IPL_DEPTH_32F,3);
cvConvertScale(img8,img32,1.0/255.0,0.0);
//用于确认检查像素值(0-1之间)
for(int row = 0; row < img32->height; row++ )
float* pt = (float*) (img32->imageData + row * img32->widthStep);
for ( int col = 0; col < width; col++ )
printf("\n %3.3f , %3.3f , %3.3f ",pt[3*col],pt[3*col+1],pt[3*col+2]);
cvShowImage("Convert",img32);
cvWaitKey(0);
cvReleaseImage(&img8);
cvReleaseImage(&img32);
cvDestroyWindow("Convert");
【讨论】:
以上是关于如何将 8 位 OpenCV IplImage* 转换为 32 位 IplImage*?的主要内容,如果未能解决你的问题,请参考以下文章