我有8UC1 Mat图像。我正在尝试使用[x] [y]坐标将其转换为Java 2D字节数组。 这是我到目前为止所做的:
byte[][] arr = new byte[mat.cols()][mat.rows()];
for (int colIndex = 0; colIndex < mat.cols(); colIndex++) {
mat.get(0, colIndex, arr[colIndex]);
}
然而,这给了我完全混乱的结果。 例如,带有.dump()的垫子,例如:
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
255, 255, 255, 255, 255, 255, 255, 255, 255, 255;
255, 255, 255, 255, 255, 255, 255, 255, 255, 255;
255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
给了我这个(不介意-1,没关系):
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 0
-1 -1 -1 -1 -1 -1 -1 -1 0 0
-1 -1 -1 -1 -1 -1 -1 0 0 0
-1 -1 -1 -1 -1 -1 0 0 0 0
答案 0 :(得分:1)
它是关于Mat内部的内存布局和Mat.get的使用方式 问题中的代码是尝试构建一个二维数组,其中第一个索引索引列,第二个索引索引行 并且所述代码调用Mat.get期望在每次调用时填充一列。
内存布局。
对于单个通道的二维矩阵,就像这样,opencv按行存储其值。每行填充到一些适当的对齐方式
为了便于解释,我们假设一行占用的10个字节被填充到总共16个字节
我们的矩阵将存储如下:
Position 0 : 255,255,255,255,255,255,255,255,255,255,?,?,?,?,?,?,
Position 16 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,?,?,?,?,?,?,
Position 32 : 255,255,255,255,255,255,255,255,255,255,?,?,?,?,?,?,
Position 48 : 255,255,255,255,255,255,255,255,255,255,?,?,?,?,?,?,
Position 64 : 255,255,255,255,255,255,255,255,255,255,?,?,?,?,?,?,
位置相对于元素位置(0,0)。从该图中可以清楚地看出,最后一个元素(4,9)位于73位 ?表示未使用的值。所以我们不能对那里的价值做出任何保证 Mat也可以使用大小为0的填充,并且在我所做的测试中就是这种情况。然后布局就像这样(布局2)
Position 0 : 255,255,255,255,255,255,255,255,255,255
Position 10 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Position 20 : 255,255,255,255,255,255,255,255,255,255
Position 30 : 255,255,255,255,255,255,255,255,255,255
Position 40 : 255,255,255,255,255,255,255,255,255,255
<强> Mat.get 强>
这实际上是猜测因为documentation不完整。我必须检查来源以确定。
Mat.get(int i, int j, byte[] arr)
使用从(i,j)处的值开始存储的值填充数组arr
,直到数组被填充。
那么,当我们使用值为9的mat.get(0, colIndex, arr[colIndex])
来调用colIndex
时会发生什么?
在上一个表中,(0,9)处的元素位于第9位。arr[colIndex]
是一个大小为5的数组,因此它将填充从第9位到第13位的值,它们是:[ 255,?,?,?,? ]使用布局1并且[255,0,0,0,0]具有布局2.这就是OP程序输出的最后一列是[255,0,0,0,0]的原因。请注意,在布局2中,当您按行顺序读取行的最后一个元素并想要更多元素时,下一个元素将成为下一行的第一个元素。
arr[9]
应该包含一列,即第10列。但是对Mat.get的调用并没有用这样的列填充它,但是值为(0,9),后面是行顺序(不是列顺序),由于填充(布局1)而未指定这些值或者是下一行(布局2)中的那些。
丑陋的解决方案,将第一个索引保留为列,第二个保留为行:
class SimpleSample
{
static
{
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void printArr( byte[][] arr )
{
for ( int y=0; y<arr[0].length; ++y )
{
for ( int x=0; x<arr.length; ++x )
System.out.print( arr[x][y] + ", " );
System.out.println("");
}
}
public static void main(String[] args)
{
Mat mat = new Mat(5, 10, CvType.CV_8UC1, new Scalar(255));
mat.row(1).setTo(new Scalar(0));
System.out.println( mat.dump() );
byte[][] arr = new byte[mat.cols()][mat.rows()];
byte[] tmp = new byte[1];
for ( int i=0; i<mat.rows(); ++i )
{
for ( int j=0; j<mat.cols(); ++j )
{
mat.get(i, j, tmp);
arr[j][i] = tmp[0];
}
}
printArr(arr);
}
}
我们得到预期的输出:
[255,255,255,255,255,255,255,255,255,255;
0,0,0,0,0,0,0,0,0,0;
255,255,255,255,255,255,255,255,255,255;
255,255,255,255,255,255,255,255,255,255;
255,255,255,255,255,255,255,255,255,255]
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0,0,0,0,0,0,0,0,0,0,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
将arr的第一个索引更改为行,将第二个索引更改为列的解决方案。
class SimpleSample
{
static
{
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void printArr( byte[][] arr )
{
for ( int y=0; y<arr.length; ++y )
{
for ( int x=0; x<arr[y].length; ++x )
System.out.print( arr[y][x] + ", " ); // Was arr[x][y] in prev code.
System.out.println("");
}
}
public static void main(String[] args)
{
Mat mat = new Mat(5, 10, CvType.CV_8UC1, new Scalar(255));
mat.row(1).setTo(new Scalar(0));
System.out.println( mat.dump() );
byte[][] arr = new byte[mat.rows()][mat.cols()];
for ( int i=0; i<mat.rows(); ++i )
mat.get(i, 0, arr[i]);
printArr(arr);
}
}
我们得到相同的输出
请注意,虽然在这里我们必须使用arr
作为arr[y][x]
(第一行,第二列,如opencv),这可能不是OP想要的。