簡體   English   中英

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

[英]what is the fastest way to search inside a matrix for min and max alongside of different rows or cols in c++

假設我需要在行和列的矩陣內搜索以找到最小值,這是最好的方法嗎?

我現在能想到的是有兩個嵌套向量如下:

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。

隨着結構元素的變化,最好的選擇是使用二進制索引樹 (又名Fenwick樹)實現Range最小查詢( RMQ )。 我建議你為每一行和每一列保留一棵這樣的樹。 如果要支持對原始矩陣的子矩陣的查詢,也可以實現此類樹的樹。 我提出的解決方案將需要O(N * M )附加存儲器,其中N和M是矩陣的維度。 它還將支持復雜度為O(log(N) + log(M))查詢和更新。

如果您有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是min / max的坐標(如果有多個,則為第一次出現)。

顯然,如果你傳遞整個矩陣,你將得到全局最小值/最大值,但你也可以只傳遞一行或一列。

對於矩陣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)操作,因為它們不復制任何數據,但我沒有做任何基准來確定它們的列迭代速度。

我們可以使用cv::reduce1 )作為行/列方式的最小值/最大值,而不是使用范圍/ roi的minMaxLoc 以下示例。

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循環來查找min / max值。 所以,如果你的數據已經存在於OpenCV Mat ,我認為這是要走的路。

雖然這可能比您想要的更復雜,但可以繼承迭代器基類 那里有一個簡單的例子。 您將重新定義運算符以遍歷列。 這樣,您可以像行迭代器一樣將它們傳遞給min_element。

如果我理解正確,您希望能夠找到給定矩陣的最小值和最大值(和位置):

  1. 全球
  2. 在一行,和,
  3. 在一列中

然后以下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;
}

也許我提出的解決方案不是最好的方式 (你明確要求的),但它很簡單。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM