什么是从cv垫中删除行或col的最佳方法

时间:2015-04-17 10:32:45

标签: c++ algorithm opencv

假设我有一个mat对象,例如follow:

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 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,然后将它们相互合并,但有没有更好的方法?

2 个答案:

答案 0 :(得分:6)

我测试了两种方法:

  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;
        }
    }
    
  3. 第一种方法的时间测试表明:

    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以验证此测试的结果。

答案 1 :(得分:1)

删除第N行:

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

删除col 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。