假设我需要在行和列的矩阵内搜索以找到最小值,这是最好的方法吗?
目前我能想到的是有两个嵌套的矢量如下:
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。
答案 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::col
和Mat::row
都是O(1)
次操作,因为它们不会复制任何数据,但我没有做任何基准来确定其列迭代的速度。< / p>
答案 2 :(得分:1)
我们可以使用minMaxLoc
(1)来获取行/列的最小值/最大值,而不是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)
如果我理解正确,您希望能够找到给定矩阵的最小值和最大值(和位置):
然后以下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;
}
也许我提出的解决方案不是 (你明确要求的),但这只是一个简单的解决方案。