整个矩阵的块列表 - java

时间:2017-04-26 08:55:08

标签: java matrix block transformation

所以我遇到了以下问题:我有一种方法可以将大矩阵分解成相同大小的较小块。在对块执行某些操作之后,我想以正确的顺序重建大矩阵,但我在某种程度上会出错。

以下代码正确地重建了一个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);

但其他任何事情都没有。谁能解释我做错了什么?

1 个答案:

答案 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;
}