1

我需要在整个数组中搜索数组(MatND 对象)以获得 MAX 值的 5%。minMaxLoc 函数返回我的最大值,但我不知道自己搜索它的热度。

有任何想法吗?

4

1 回答 1

3

如果是 uchar Mat

/**
 * @param : input image
 * @hist  : histogram
 * @nmin  : total minimum pixels number
 * @nmax  : total maximum pixels number
 * @channel : channel number
 *
 * ex : images with 1000 pixels, 50 equal to 5% of it
 */
std::pair<size_t, size_t> get_quantile_uchar(cv::Mat &input, cv::MatND &hist, size_t nmin, size_t nmax, int channel)
{
    int const hist_size = std::numeric_limits<uchar>::max() + 1;
    float const hranges[2] = {0, 255};
    float const *ranges[] = {hranges};

    //compute and cumulate the histogram
    cv::calcHist(&input, 1, &channel, cv::Mat(), hist, 1, &hist_size, ranges);
    auto *hist_ptr = hist.ptr<float>(0);
    for(size_t i = 1; i != hist_size; ++i){
        hist_ptr[i] += hist_ptr[i - 1];
    }

    // get the new min/max
    std::pair<size_t, size_t> min_max(0, hist_size - 1);
    while(min_max.first != (hist_size - 1) && hist_ptr[min_max.first] <= nmin){
        ++min_max.first; // the corresponding histogram value is the current cell position
    }

    while(min_max.second > 0 && hist_ptr[min_max.second] > nmax){
        --min_max.second; // the corresponding histogram value is the current cell position
    }

    if (min_max.second < hist_size - 2)
        ++min_max.second;

    return min_max;
}

例如,如果有一个 Mat(100 * 100) 的值在 0~255 之间,您可以像这样测量前 5% 的百分位数和最低的 3% 百分位数

auto const result = get_quantile(input, hist, input.total * 0.03, input.total * 0.95, 0); 

如果不是uchar Mat,那么可以先对要测量的通道进行排序

/**
* @brief generic algorithm for other channel types except of uchar
* @param input   the input image
* @param output  the output image
* @param smin    total number of minimum pixels
* @param smax    total number maximum pixels
* @param channel the channel used to compute the histogram
*
* This algorithm only support uchar channel and float channel by now
*/
template<typename T>
std::pair<T, T> get_quantile(cv::Mat &input, size_t smin, size_t smax, int channel)
{
    std::vector<float> temp_input = copy_to_one_dim_array_ch<float>(input, channel);
    std::sort(std::begin(temp_input), std::end(temp_input));

    return std::pair<T, T>(temp_input[smin], temp_input[temp_input.size() - 1 - smax]);
}

接下来的问题是如何实现函数copy_to_one_dim_array_ch

/*
 * experimental version for cv::Mat, try to alleviate the problem
 * of code bloat.User should make sure the space of begin point to
 * have enough of spaces.
 */
template<typename T, typename InputIter>
void copy_to_one_dim_array_ch(cv::Mat const &src, InputIter begin, int channel)
{
    int const channel_number = src.channels();
    if(channel_number <= channel || channel < 0){
        throw std::out_of_range("channel value is invalid\n" + std::string(__FUNCTION__) +
                                "\n" + std::string(__FILE__));
    }

    for(int row = 0; row != src.rows; ++row){
        auto ptr = src.ptr<T>(row) + channel;
        for(int col = 0; col != src.cols; ++col){
            *begin = *ptr;
            ++begin;
            ptr += channel_number;
        }
    }
}

template<typename T>
std::vector<T> const copy_to_one_dim_array_ch(cv::Mat const &src, int channel)
{
    std::vector<T> result(src.total());
    copy_to_one_dim_array_ch<T>(src, std::begin(result), channel);

    return result;
}

部分功能需要c++11支持,函数copy_to_one_dim_array_ch不支持非字节图像

如果你想让它变得更容易使用,你可以 1 : 将这些函数包装在一个类中。
2:在 uchar Mat 3 上应用完全专业化:将类包装在一个函数中

于 2013-04-27T14:48:00.757 回答