什么是在c ++内的最小和最大矩阵中搜索不同行或列的最快方法

时间:2015-04-15 15:24:22

标签: c++ algorithm opencv

假设我需要在行和列的矩阵内搜索以找到最小值,这是最好的方法吗?

目前我能想到的是有两个嵌套的矢量如下:

std::vector<std::vector<float>> myData;

以这种方式搜索:

// row search on row say 10
int index= std::min_element(myData[10].begin(), myData[10].end()) - myData[10].begin();

但是为了搜索cols,我需要编写一个for循环来进行搜索。

 // col search say on col 20
 float min_value=10000000;  / assuming values in table are less than this value
 int min_index=-1;
 for(int i=0;i<myData.size();++i)
 {
       if(myData[i][20] <min_value)
       {
            min_value=myData[i][20];
            min_index=i;
        }
  }

有没有更好的方法呢?我也可以访问OpenCV。

5 个答案:

答案 0 :(得分:2)

由于您的结构元素将会发生变化,您最好的选择是使用RMQ(a.k.a Fenwick树)实现范围最小查询(binary index trees)。我建议你为每一行和每一列保留一棵这样的树。如果要支持对原始矩阵的子矩阵的查询,也可以实现此类树的树。我提出的解决方案将需要O(N * M )额外的内存,其中N和M是矩阵的维度。它还支持复杂O(log(N) + log(M))的查询和更新。

答案 1 :(得分:2)

如果您有OpenCV Mat,可以使用minMaxLoc

void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, 
    Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray())

返回值minVal/maxVal包含实际值,而minLoc/maxLoc是最小值/最大值的坐标(如果有多个则为第一次出现)。

显然,如果你传递整个矩阵,你将得到全局最小值/最大值,但你也可以只传递一行或一列。

对于矩阵C,您可以使用Mat::col找到列n的最小值/最大值

minMaxLoc(C.col(n), &minVal, &maxVal, &minLoc, &maxLoc);

或使用Mat::row

的行m
minMaxLoc(C.row(m), &minVal, &maxVal, &minLoc, &maxLoc);

Mat::colMat::row都是O(1)次操作,因为它们不会复制任何数据,但我没有做任何基准来确定其列迭代的速度。< / p>

答案 2 :(得分:1)

我们可以使用minMaxLoc1)来获取行/列的最小值/最大值,而不是cv::reduce和range / roi。以下示例。

unsigned char data[4][2] = { 1,2,3,4,5,6,7,8 };
Mat img(4, 2, CV_8UC1, data) ;

Mat rowMinImg;
int singleCoumnResult = 1;
cv::reduce(img, rowMinImg, singleCoumnResult, CV_REDUCE_MIN );

//Mat colMinImg;
//int singleRowResult = 0;
//cv::reduce(img, colMinImg, singleRowResult, CV_REDUCE_MIN );

快速了解cv :: reduce(2)的实现,表明它是一个简单的for循环来查找最小/最大值。因此,如果您已将数据存储在OpenCV Mat中,我认为这是可行的方法。

答案 3 :(得分:0)

虽然这可能比您想要的更复杂,但可以继承iterator base class。那里有一个简单的例子。您将重新定义运算符以遍历列。这样,您可以像行迭代器一样将它们传递给min_element。

答案 4 :(得分:0)

如果我理解正确,您希望能够找到给定矩阵的最小值和最大值(和位置):

  1. 全局
  2. 在一行中,
  3. 在一栏中
  4. 然后以下MWE可能会对您有所帮助。让我们先来看一下输出:

    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]
    
    global min =   1 @ [5, 2]
    global max =  97 @ [1, 0]
    
    Row 0 min =  15 @ [4, 0] max =  97 @ [1, 0]
    Row 1 min =  21 @ [1, 1] max =  72 @ [3, 1]
    Row 2 min =   1 @ [5, 2] max =  88 @ [2, 2]
    Row 3 min =  24 @ [5, 3] max =  95 @ [4, 3]
    Row 4 min =   9 @ [2, 4] max =  83 @ [3, 4]
    
    Col 0 min =  21 @ [0, 2] max =  75 @ [0, 0]
    Col 1 min =  21 @ [1, 1] max =  97 @ [1, 0]
    Col 2 min =   9 @ [2, 4] max =  88 @ [2, 2]
    Col 3 min =  40 @ [3, 3] max =  95 @ [3, 0]
    Col 4 min =  15 @ [4, 0] max =  95 @ [4, 3]
    Col 5 min =   1 @ [5, 2] max =  83 @ [5, 4]
    

    相应的代码(你说可以使用OpenCV):

    #include <opencv2/core/core.hpp>
    
    #include <algorithm>
    #include <iostream>
    #include <iomanip>
    
    namespace {
    
    template <typename T>
    std::pair< cv::Point, cv::Point > findMinMaxLoc( cv::Mat_<T> & mat )
    {
        double ignored1, ignored2;
        std::pair< cv::Point, cv::Point > mmloc;
        cv::minMaxLoc( mat, &ignored1, &ignored2, &(mmloc.first), &(mmloc.second) );
    
        return mmloc;
    }
    
    template <typename T>
    std::pair< cv::Point, cv::Point > minMaxLocRow( cv::Mat_<T> & mat, int row )
    {
        cv::Rect roi( 0, row, mat.size().width, 1 );
        cv::Mat_<T> matRow = mat( roi );
    
        std::pair< cv::Point, cv::Point > mmloc = findMinMaxLoc( matRow );
        mmloc.first.y  = row;
        mmloc.second.y = row;
    
        return mmloc;
    }
    
    template <typename T>
    std::pair< cv::Point, cv::Point > minMaxLocCol( cv::Mat_<T> & mat, int col )
    {
        cv::Rect roi( col, 0, 1, mat.size().height  );
        cv::Mat_<T> matCol = mat( roi );
    
        std::pair< cv::Point, cv::Point > mmloc = findMinMaxLoc( matCol );
        mmloc.first.x  = col;
        mmloc.second.x = col;
    
        return mmloc;
    }
    
    } // namespace
    
    int main( int argc, char ** argv )
    {
        // Generate a matrix filled with random data.
        cv::Size size( 6, 5 );
        cv::Mat1i mat( size ); // Or cv::Mat1b, cv::Mat3f, etc.
        cv::RNG rng( cv::getCPUTickCount() );
    
        rng.fill( mat, cv::RNG::UNIFORM, 0, 100 );
    
        std::cout << "mat = " << std::endl << mat << std::endl << std::endl;
    
        // Find the global minimum and maximum.
        std::pair< cv::Point, cv::Point > mmloc = findMinMaxLoc( mat );
    
        std::cout << "global min = " << std::setw( 3 ) << std::setfill( ' ' );
        std::cout << mat( mmloc.first )  << " @ " << mmloc.first  << std::endl;
        std::cout << "global max = " << std::setw( 3 ) << std::setfill( ' ' );
        std::cout << mat( mmloc.second ) << " @ " << mmloc.second << std::endl << std::endl;
    
        // Row-wise extrema.
        for ( int row = 0; row < size.height; ++row )
        {
            std::pair< cv::Point, cv::Point > mmloc = minMaxLocRow( mat, row );
    
            std::cout << "Row " << row;
            std::cout << " min = " << std::setw( 3 ) << std::setfill( ' ' );
            std::cout << mat( mmloc.first )  << " @ " << mmloc.first;
            std::cout << " max = " << std::setw( 3 ) << std::setfill( ' ' );
            std::cout << mat( mmloc.second ) << " @ " << mmloc.second << std::endl;
        }
        std::cout << std::endl;
    
        // Column-wise extrema.
        for ( int col = 0; col < size.width; ++col )
        {
            std::pair< cv::Point, cv::Point > mmloc = minMaxLocCol( mat, col );
    
            std::cout << "Col " << col;
            std::cout << " min = " << std::setw( 3 ) << std::setfill( ' ' );
            std::cout << mat( mmloc.first )  << " @ " << mmloc.first;
            std::cout << " max = " << std::setw( 3 ) << std::setfill( ' ' );
            std::cout << mat( mmloc.second ) << " @ " << mmloc.second << std::endl;
        }
    
        return 0;
    }
    

    也许我提出的解决方案不是 (你明确要求的),但这只是一个简单的解决方案。