在openCV矩阵中查找列最大值的索引和值

Posted

技术标签:

【中文标题】在openCV矩阵中查找列最大值的索引和值【英文标题】:Find the index and value of column maximum in openCV matrix 【发布时间】:2017-08-09 08:22:39 【问题描述】:

这是原始的 MATLAB 实现

function[m, p] = max2(im)

[m1, k1] = max(im);
[m, k2] = max(m1);

x = k2;
y = k1(k2);

p = [y, x];

在这个功能中使用它

for r = 2.^linspace(log2(minR),log2(maxR),numSteps);
    itestSeek = imresize(itestBase,minR/r);    
    icorr = normxcorr2(cc,itestSeek);
    [m,p] = max2(icorr); //here
    if (m>bestm)
        bestp = p*r;
        bests = ccSize*r;
        bestm = m;        
    end;
end;

这是我的 OpenCV 3.0.0/ c++ 实现

void Utilities::Max2(cv::Mat input_image, double& m, std::vector<int>& p)

    std::vector<double> m1(input_image.cols); // the local maximum for each column
    std::vector<int> k1(input_image.cols); // the index of the local maximum
    for (int c = 0; c < input_image.cols; ++c)
    
        float temp_max = input_image.at<float>(0, c);
        int temp_index = 0;
        for (int r = 0; r < input_image.rows; ++r)
        
            if (temp_max < input_image.at<float>(r, c))
            
                temp_max = input_image.at<float>(r, c);
                temp_index = r;
            
        
        m1[c] = temp_max;
        k1[c] = temp_index;
    
    auto iter = std::max_element(m1.begin(), m1.end()); //max of all the local maximum;
    m = *iter;
    int k2 = std::distance(m1.begin(), iter);

    double y = k1[k2];
    p.push_back(y);
    p.push_back(k2);

函数的c++用法

std::vector<double> best_p;
std::vector<double> best_s;
for (double i = 0; i < linspace_vector.size(); i++)

    cv::Mat i_test_seek;
    cv::Mat i_corr;
    double r = linspace_vector[i];
    double resize_factor = min_r / r; // minR/r in matlab
    cv::resize(i_test_base, i_test_seek, cv::Size(), resize_factor, resize_factor, cv::INTER_CUBIC);
    cv::matchTemplate(i_test_seek, cc_template, i_corr, CV_TM_CCORR_NORMED);

    cv::imshow("i_corr", i_corr);
    cv::waitKey(0);
    double m;
    std::vector<int> p;

    Utilities::Max2(i_corr, m, p);
    if (m>  best_m)
    
        best_p.clear();
        best_s.clear();
        for (int i = 0; i < p.size(); ++i)
        
            best_p.push_back(p[i] * r);
        
        best_s.push_back(cc_size_height * r);
        best_s.push_back(cc_size_width * r);
        best_m = m;
    

您能建议一种更有效的方法吗? 我找到每列的局部最大值和该值的索引。

后来我找到了所有索引的全局最大值。

【问题讨论】:

更改了标题,因为“查找列的索引”有点令人困惑,恕我直言 假设这是工作代码,您的问题可能更适合codereview.stackexchange.com 如果图像在内存中按列排列,则切换内循环和外循环可能会提高性能,因为缓存未命中率较低。尽管编译器可能会为您做到这一点。 查找全局最大值应该与您遍历图像的方式无关。为什么一定要坚持matlab的做法呢? 为什么不minMaxLoc 【参考方案1】:

如果性能提高,您能否尝试以下和基准测试:

#include <limits>


void Utilities::Max2(cv::Mat input_image, double& m, std::vector<int>& p)

    m = std::numeric_limits<double>::min;
    std::pair<int, int> temp_index = 0;

    for (int r = 0; r < input_image.rows; ++r)
    
        for (int c = 0; c < input_image.cols; ++c)
        
            if (m < input_image.at<float>(r, c))
            
                m = input_image.at<float>(r, c);
                temp_index = std::make_pair(c, r);
            
        
    

    p[0] = temp_index.second;
    p[1] = temp_index.first;

【讨论】:

【参考方案2】:

如果有办法将输入作为向量获取,并且您可以获取数字 col 列,例如使用:

int cols = input_image.rows;
std::vector<double> v;
v.assign(input_image.datastart, input_image.dataend);

然后你就可以一次计算了:

std::vector<double>::iterator iter = std::max_element(v.begin(), v.end());
double m = *iter;
int k = std::distance(v.begin(), iter);
int y = (int)k / cols;
int x = k % cols;

但是,我不确定将数据作为向量获取是否是一种选择,也不确定将其转换为向量的性能。也许您可以运行并查看它与您的实现相比如何。

【讨论】:

可以直接使用Mat迭代器。它们还可以正确处理非连续矩阵【参考方案3】:

根据我的理解,第一段代码本质上是在图像中找到最大值及其索引(x 和 y)。

function[m, p] = max2(im)
    [m1, k1] = max(im); %find the max value in each col
    [m, k2] = max(m1);  %find the max value among maxes

    x = k2;             %find the "row" of the max value
    y = k1(k2);         %and its "col"
    p = [y, x];

这可以使用一些迭代来完成,但迭代几乎总是比向量运算或 Opencv 函数慢得多。

所以,如果我的理解是正确的,这个操作可以简单地通过

double minVal, maxVal;
Point minLoc, maxLoc;
minMaxLoc(im, &minVal, &maxVal, &minLoc, &maxLoc);

maxLoc.y 将给出行,maxLoc.x 将给出列。

更新:您的 Matlab 代码也可以简化(这也可能会加快速度)

[mx, ind] = max(im(:));
p = [rem(ind,size(im,1)) ceil(ind/size(im,1))];

【讨论】:

【参考方案4】:

您还可以尝试以下方法:

// creating a random matrix with 2 rows and 4 columns
Mat1d mat(2, 4); 
double low = -7000.0;  // minimum value for generating random numbers
double high = +7000.0; // maximum value for generating random numbers
randu(mat, Scalar(low), Scalar(high)); // generating random number matrix

double max_element = *std::max_element(mat.begin(),mat.end()); // get the max element in the matrix
int max_element_index = std::max_element(mat.begin(),mat.end()) - mat.begin(); // get the max_element_index from the matrix`

最大元素索引是从 0 到矩阵中的项目数的行主顺序值,在本例中为 7,

cout << mat << endl;
cout << max_element << endl;
cout << max_element_index << endl;

[以上代码参考Generate random numbers matrix in OpenCV]

【讨论】:

以上是关于在openCV矩阵中查找列最大值的索引和值的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 矩阵中查找最大元素的索引?

计算机视觉OpenCV 4高级编程与项目实战(Python版):图像像素统计

使用R查找包含最大值的行索引

Julia:找到所有最大值的索引

如何通过 Jquery 从表中查找按列指定的行的索引和值?

矩阵列的最小元素