OpenCV 2.4.7 Mat :: convertTo()32位到16位截断

时间:2014-01-16 11:07:23

标签: opencv matrix

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

我想要的应用程序是掩盖值,在目标中设置值的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

2 个答案:

答案 0 :(得分:3)

这可以做到,但这需要一些有点肮脏的技巧,所以由你决定是否使用这种方法。所以这就是它的完成方式:

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

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

这就是诀窍:

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

我们在与M1相同的内存缓冲区上创建矩阵M2,但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的格式看起来很奇怪并且使代码的可读性更低,但它可以工作......如果您更喜欢split()函数:

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

答案 1 :(得分:1)

没有OpenCV函数(我知道)可以像你想要的那样进行转换,所以要么你自己编写代码,要么就像你说你先通过一个屏蔽步骤来删除16位高位。

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

您还可以提高手写代码的效率。通常,您应该在循环中避免使用OpenCV像素访问器,因为它们的性能较差。我手边没有OpenCV安装,所以这可能很简单 - 想法是直接使用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]);