所以我遇到了以下问题:我有一种方法可以将大矩阵分解成相同大小的较小块。在对块执行某些操作之后,我想以正确的顺序重建大矩阵,但我在某种程度上会出错。
以下代码正确地重建了一个4x4矩阵,该矩阵分为2x2,但对于任何其他维度,它都无法正常工作。
public long[][] blocksToMatrix(List<long[][]> blocks, int blockDimension, int width, int height ){
long[][] yuvMatrix = new long[height][width];
int heightPos = 0;
int widthPos = 0;
for (int i = 0; i < blocks.size(); i++) {
long[][] yuvBlock = blocks.get(i);
int heightPosTemp = heightPos;
for (int j = 0; j < blockDimension * blockDimension; j++) {
yuvMatrix[heightPos][widthPos] = yuvBlock[j / blockDimension][j % blockDimension];
widthPos++;
if (widthPos >= width){
widthPos = (i * blockDimension) % width;
heightPos++;
}
if (widthPos == ((i + 1) * blockDimension) % width){
widthPos = (i * blockDimension) % width;
heightPos++;
}
}
if (heightPos == height ){
heightPos = heightPosTemp;
}
else {
heightPos = (i * blockDimension) % height;
}
widthPos = ((i + 1) * blockDimension) % width;
}
return yuvMatrix;
}
我用来打破矩阵的方法:
public List<long[][]> matrixToBlocks(long[][] yuvMatrix, int blockDimension, int width, int height){
int blocksSize = width / blockDimension * (height / blockDimension);
List<long[][]> blocks = new ArrayList<long[][]>();
for (int i = 0; i < blocksSize; i++) {
long[][] subBlock = new long[blockDimension][blockDimension];
int heightPos = (blockDimension * (i / blockDimension)) % height;
int widthPos = (blockDimension * i) % width;
if (widthPos + blockDimension > width) {
widthPos = 0;
}
for (int row = 0; row < blockDimension; row++) {
for (int col = 0; col < blockDimension; col++) {
subBlock[row][col] = yuvMatrix[heightPos + row][col + widthPos];
}
}
blocks.add(subBlock);
}
return blocks;
}
我测试它的方式:
public static void testareMatBlo(int height, int width, int blockdim){
long[][] test = new long[height][width];
int val = 1;
for (int i = 0; i < height; i++){
for (int j = 0; j < width; j++){
test[i][j] = val;
val++;
}
}
List<long[][]> blocks = matrixToBlocks(test, blockdim, width, height);
long[][] matrix = blocksToMatrix(blocks, blockdim, width, height);
if (Arrays.deepEquals(test, matrix)){
System.out.println("YES");
}
else {
System.out.println("NO");
}
}
这有效:
testareMatBlo(4, 4, 2);
但其他任何事情都没有。谁能解释我做错了什么?
答案 0 :(得分:1)
我没有彻底阅读matrixToBlocks(...)
的代码,但所有像int blocksSize = width / blockDimension * (height / blockDimension);
这样的计算很可能会引发难以发现的错误 - 而您实际上并不需要它们:
public static List<long[][]> matrixToBlocks(long[][] yuvMatrix, int blockDimension){
//Check matrix and block dimension match
if( yuvMatrix.length == 0 || yuvMatrix.length % blockDimension != 0
|| yuvMatrix[0].length == 0 || yuvMatrix[0].length % blockDimension != 0 ) {
throw new IllegalArgumentException("whatever message you like");
}
List<long[][]> blocks = new ArrayList<long[][]>();
//Iterate over the blocks in row-major order (down first, then right)
for( int c = 0; c < yuvMatrix.length; c += blockDimension ) {
for( int r = 0; r < yuvMatrix[c].length; r += blockDimension ) {
long[][] subBlock = new long[blockDimension][blockDimension];
//Iterate over the block in row-major order
for(int bc = 0; bc < blockDimension; bc++ ) {
for(int br = 0; br < blockDimension; br++ ) {
subBlock[bc][br]=yuvMatrix[c+bc][r+br];
}
}
blocks.add(subBlock);
}
}
return blocks;
}
这种方法看起来并不简短,但它是:对你的初步检查进行折扣缺失只有8行实际代码与你代码中的13代码相比。然而,这不是重点。更重要的是逻辑更容易,因为只涉及一些计算(如c+bc
)。
您可能认为这是低效的,但事实并非如此:您只访问每个元素一次,因此即使有4个嵌套循环,整体复杂性仍为O(n),n为矩阵的大小。
构建矩阵同样容易。您需要注意的主要事项是块的排序:如果您按行主要顺序创建它们(列表中彼此相邻的块彼此相邻),您需要以相同的方式重新创建矩阵:
public static long[][] blocksToMatrix( List<long[][]> blocks, int width, int height ) {
long[][] yuvMatrix = new long[width][height];
int c = 0;
int r = 0;
for( long[][] block : blocks ) {
int blockWidth = block.length;
int blockHeight = block[0].length;
for( int bc = 0; bc < block.length; bc++ ) {
for( int br = 0; br < block[bc].length; br++ ) {
yuvMatrix[c + bc][r + br] = block[bc][br];
}
}
//calculate the next offset into the matrix
//The blocks where created in row-major order so we need to advance the offset in the same way
r += blockHeight;
if( r >= height ) {
r = 0;
c += blockWidth;
}
}
return yuvMatrix;
}