【问题标题】:what is the best way to remove a row or col from a cv mat从 cv mat 中删除行或列的最佳方法是什么
【发布时间】:2015-04-17 10:32:44
【问题描述】:

假设我有一个 mat 对象,如下所示:

mat = 
   [75, 97, 66, 95, 15, 22;
    24, 21, 71, 72, 34, 66;
    21, 69, 88, 72, 64, 1;
    26, 47, 26, 40, 95, 24;
    70, 37, 9, 83, 16, 83];

我想从中删除一行,说第二行有这样的垫子:

 [75, 97, 66, 95, 15, 22;
 21, 69, 88, 72, 64, 1;
 26, 47, 26, 40, 95, 24;
 70, 37, 9, 83, 16, 83]

或删除一个 col 说 col 3:

[75, 97,  95, 15, 22;
 24, 21,  72, 34, 66;
 21, 69,  72, 64, 1;
 26, 47,  40, 95, 24;
 70, 37,  83, 16, 83]

最快的方法是什么?我可以将矩阵分解为 ROI,然后将它们相互合并,但是有没有更好的方法?

【问题讨论】:

    标签: c++ algorithm opencv


    【解决方案1】:

    我测试了两种方式:

    1. 使用cv::Rectcv::Mat::copyTo

      // Removing a row
      cv::Mat matIn;    // Matrix of which a row will be deleted.
      int row;          // Row to delete.
      int col;          // Column to delete.
      cv::Mat matOut;   // Result: matIn less that one row.
      
      if ( row > 0 ) // Copy everything above that one row.
      {
          cv::Rect rect( 0, 0, size.width, row );
          matIn( rect ).copyTo( matOut( rect ) );
      }
      
      if ( row < size.height - 1 ) // Copy everything below that one row.
      {
          cv::Rect rect1( 0, row + 1, size.width, size.height - row - 1 );
          cv::Rect rect2( 0, row, size.width, size.height - row - 1 );
          matIn( rect1 ).copyTo( matOut( rect2 ) );
      }
      
      // Removing a column
      if ( col > 0 ) // Copy everything left of that one column.
      {
          cv::Rect rect( 0, 0, col, size.height );
          matIn( rect ).copyTo( matOut( rect ) );
      }
      
      if ( col < size.width - 1 ) // Copy everything right of that one column.
      {
          cv::Rect rect1( col + 1, 0, size.width - col - 1, size.height );
          cv::Rect rect2( col,     0, size.width - col - 1, size.height );
          matIn( rect1 ).copyTo( matOut( rect2 ) );
      }
      
    2. 使用std::memcpycv::Mat::data

      // Removing a row
      int rowSizeInBytes = size.width * sizeof( T );
      
      if ( row > 0 )
      {
          int numRows  = row;
          int numBytes = rowSizeInBytes * numRows;
          std::memcpy( matOut.data, matIn.data, numBytes );
      }
      
      if ( row < size.height - 1 )
      {
          int matOutOffset = rowSizeInBytes * row;
          int matInOffset  = matOutOffset + rowSizeInBytes;
      
          int numRows  = size.height - ( row + 1 );
          int numBytes = rowSizeInBytes * numRows;
          std::memcpy( matOut.data + matOutOffset , matIn.data + matInOffset, numBytes );
      }
      
      // Removing a column
      int rowInInBytes  = size.width * sizeof( T );
      int rowOutInBytes = ( size.width - 1 ) * sizeof( T );
      
      if ( col > 0 )
      {
          int matInOffset = 0;
          int matOutOffset = 0;
          int numCols = col;
          int numBytes = numCols * sizeof( T );
      
          for ( int y = 0; y < size.height; ++y )
          {
              std::memcpy( matOut.data + matOutOffset, matIn.data + matInOffset, numBytes );
      
              matInOffset  += rowInInBytes;
              matOutOffset += rowOutInBytes;
          }
      }
      
      if ( col < size.width - 1 )
      {
          int matInOffset = ( col + 1 ) * sizeof( T );
          int matOutOffset = col * sizeof( T );
          int numCols = size.width - ( col + 1 );
          int numBytes = numCols * sizeof( T );
      
          for ( int y = 0; y < size.height; ++y )
          {
              std::memcpy( matOut.data + matOutOffset, matIn.data + matInOffset, numBytes );
      
              matInOffset  += rowInInBytes;
              matOutOffset += rowOutInBytes;
          }
      }
      

    第一种方法的时序测试显示:

    Removed:      row
    Method:       cv::Rect + cv::Mat::copyTo()
    Iterations:   10000
    Size:         [500 x 500]
    Best time:    67ms
    Worst time:   526ms
    Average time: 70.9061ms
    Median time:  70ms
    
    Removed:      column
    Method:       cv::Rect + cv::Mat::copyTo()
    Iterations:   10000
    Size:         [500 x 500]
    Best time:    64ms
    Worst time:   284ms
    Average time: 80.3893ms
    Median time:  79ms
    

    对于第二种方法:

    Removed:      row
    Method:       std::memcpy and/or for-loop
    Iterations:   10000
    Size:         [500 x 500]
    Best time:    31ms
    Worst time:   444ms
    Average time: 68.9445ms
    Median time:  68ms
    
    Removed:      column
    Method:       std::memcpy and/or for-loop
    Iterations:   10000
    Size:         [500 x 500]
    Best time:    49ms
    Worst time:   122ms
    Average time: 79.3948ms
    Median time:  78ms
    

    因此,考虑到接近的时序结果和简短的实现,第一种方法似乎更合适。 我发布了minimal working example on github 以验证此测试的结果。

    【讨论】:

      【解决方案2】:

      删除第 N 行:

      memmove(mat + N * x_size, 
              mat + (N + 1) * x_size, 
              x_size * sizeof(int) * (y_size - N - 1));
      

      删除列 N:

      for(int y = 0; y < y_size; y++)
        memmove(mat + N + y * (x_size - 1), 
        mat + N + y * x_size + 1, 
        (x_size - 1) * sizeof(int));
      

      ATTN:第二个代码(删除列)读取矩阵后面的额外行。在大多数情况下,这是可以接受的,并且算法保持简单。如果需要,修改代码以将正确的大小传递到最后一个 memmove。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-17
        • 1970-01-01
        • 2011-05-31
        • 1970-01-01
        • 2022-08-12
        相关资源
        最近更新 更多