我注意到使用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
答案 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]);