java - 整个矩阵的 block 列表 - java

标签 java matrix block transformation

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

以下代码可以正确重建分解为 2x2 的 4x4 矩阵,但对于任何其他维度,它无法正常工作。

   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);

但是其他的都没有。谁能解释一下我做错了什么?

最佳答案

我没有彻底阅读您的matrixToBlocks(...)代码,但是所有这些计算,例如intblockSize = 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 是矩阵的大小。

构造矩阵同样容易。您需要注意的主要事情是 block 的顺序:如果您按行优先顺序创建它们(彼此下方的 block 在列表中彼此相邻),则需要以相同的方式重新创建矩阵:

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

关于java - 整个矩阵的 block 列表 - java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43629389/

相关文章:

java - Spring 设置 java.io.File 属性使用 java.lang.String bean

java - 什么是正确的单例实现以及为什么

java - 不安全的密码加密模式,如何解决?

ios - 将对象传递到 ASIHTTPRequest block

用于识别相同文件的 Java 文件哈希

c - 使用 Lapack 在 C 中求解矩阵

python - 从字符串中的字符生成像素矩阵

c++ - 转置 4x4 字节矩阵的最快方法

ios - 将完成处理程序中的值存储到变量中

Ruby 做/结束 vs 大括号