OpenCv - 从直方图数组中获取值

时间:2013-04-27 12:00:16

标签: arrays search opencv

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

有什么想法吗?

1 个答案:

答案 0 :(得分: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:将类包装在函数