2014-01-16 38 views
3

我注意到,使用convertTo将矩阵从32位转换为16位“rounds”数字到上层。因此,源矩阵中大于0x0000FFFF的值将在目标矩阵中设置为0xFFFF。OpenCV 2.4.7 Mat :: convertTo()32位到16位截尾

我想为我的应用程序,而不是屏蔽值,设置在目标只是2 LSB的值。

下面是一个例子:

Mat mat32; 
Mat mat16; 

mat32 = Mat(2,2,CV_32SC1); 

for(int y = 0; y < 2; y++) 
    for(int x = 0; x < 2; x++) 
    mat32.at<unsigned int>(cv::Point(x,y)) = 0x0000FFFE + (y*2+x); 

mat32.convertTo(mat16, CV_16UC1); 

该矩阵具有这些值:

32 bits matrix: 
0000FFFE  0000FFFF 
00010000  00010001 

16 bits matrix: 
0000FFFE  0000FFFF 
0000FFFF  0000FFFF 

在16位矩阵的第二行我想有

00000000 00000001 

我可以通过逐个值地扫描源矩阵并掩蔽值来做到这一点,但性能很低。

有没有OpenCV功能可以做到这一点?

感谢大家!

MIX

+1

根你的问题的原因是OpenCV在cv :: Mat :: convertTo()方法中应用了cv :: saturate_cast。这在文档中有明确说明。 – sansuiso

回答

1

没有OpenCV的功能(即我所知道的)像你想它会进行转换,所以无论是你自己的代码,或像你说你去通过掩膜步骤首先要去除16高位。

可以使用C++中的bitwise_and或C中的cvAndS来应用掩码。请参阅here

你也可以让你的手写代码更有效率。一般来说,您应该避免OpenCV像素访问器出现在循环中,因为它们的性能不佳。我没有一个OpenCV的安装在眼前所以这可能是slighlty掉 - 的想法是直接使用data领域,step这是每行的字节数:

for(int y = 0; y < mat32.height; ++) { 
    int* row = (int*)((char*)mat32.data + y * mat32.step); 
    for(int x = 0; x < mat32.step/ 4) 
    row[x] &= 0xffff; 

然后,一旦掩码被应用,所有值都适合16位,并且convertTo将只截断16位高位。

另一种方案是用手工编写转换:

mat16.resize(mat32.size()); 
for(int y = 0; y < mat32.height; ++) { 
    const int* row32 = (const int*)((char*)mat32.data + y * mat32.step); 
    short*  row16 = (short*) ((char*)mat16.data + y * mat16.step); 
    for(int x = 0; x < mat32.step/ 4) 
    row16[x] = short(row32[x]); 
+0

好的,没有内置的函数...我已经创建了转换函数。使用'数据'字段似乎更有效一些(虽然可读性较差)。我没有使用它,因为我无法在Mat类中找到'widthStep'参数,就像IplImage(我迄今在OpenCV 1.x中使用的类);比我注意到'step'参数。愚蠢的我! –

+0

确实,在“Mat”类中,它被称为“step”,我会纠正我的答案。 – Antoine

2

这是可以做到,但是这需要一个有点使坏,所以它是由你来使用这种方法还是不行。所以这是如何完成的:

对于这个例子,我们可以创建1000x1000的32位矩阵,并将其所有值设置为65541(= 256 * 256 + 5)。所以在转换之后,我们希望有一个填充五个的矩阵。

Mat M1(1000, 1000, CV_32S, Scalar(65541)); 

这里是招:

Mat M2(1000, 1000, CV_16SC2, M1.data); 

我们创建的矩阵M2较上年内存缓冲区为M1,但M2“想”这是2通道16位图像的缓冲区。现在最后要做的是将你需要的频道复制到你需要的地方。这可以通过split()或mixChannels()函数完成。例如:

Mat M3(1000, 1000, CV_16S); 
int fromto[] = {0,0}; 
Mat inpu[] = {M2}, outpu[] = {M3}; 
mixChannels(inpu, 1, outpu, 1, fromto, 1); 
cout << M3.at<short>(10,10) << endl; 

烨我知道mixChannels的格式看起来怪异,使代码更少可读,但它的作品...如果你喜欢拆分()函数:

vector<Mat> v; 
split(M2,v); 
cout << v[0].at<short>(10,10) << " " << v[1].at<short>(10,10) << endl; 
+1

让我读你的帖子50多次... –

+0

我不确定你的评论是什么意思。如果您的意思不清楚,我可以尝试重新解释。 –

+0

不,没关系。这与我平常的做法相去甚远,所以我已经很多时间阅读它来了解正在发生的事情。 –