2016-02-11 74 views
2

我知道有找Mat的平均OpenCV中的一個選項:我想知道,如果在OpenCV中也有發現,平均無選項查找平均W/O極值

cv::mean(mat); 

極端值(例如,僅爲10%至90%之間的值)。

回答

1

我不知道OpenCV,但我懷疑它已準備好使用此功能。然而,天真的實現可能是這樣的:

double m = cv::mean(mat); 
Mat temp = mat; 
... set all elements in temp to 0, where abs(temp[i][j] - m) > tolerance 
... and count those elements in count 
int N = mat.total(); // total number of elements 
m = cv::sum(temp)/(N-count) 

編輯:其實這不是什麼問題被要求。但是,如果可以假設值的高斯分佈,則可以基於標準偏差(必須計算)來估計值tolerance以排除數據的上限/下限10%。

+0

cv :: mean也認爲是零值。所以平均值會很低。 – Bschs

+0

@Bschs這就是爲什麼最後一行糾正了規範化 – user463035818

+0

@ tobi303這不適用於一般矩陣,其中值可以是例如小於0.但是,這種方法適用於圖像,因爲你有'容差「,這是不能修復的,但對每張圖像都要重新計算。所以這不能回答這個問題,因爲你錯過了如何計算閾值。剩下的就好了,Bschs是錯誤的:D – Miki

0

不,沒有OpenCV功能來做到這一點。但是,你可以實現你自己的。


最棘手的部分是計算與您的百分比相對應的值。這可以很容易地實現計算圖像的累積直方圖。

但是,要使該方法一般,您無法知道矩陣中的哪些值,因此您需要依賴maps

請注意,如果您僅在CV_8U圖片上工作,則可以優化知道最多隻能有256個不同的值。要實現這一點,您可以提示here

所以這是一個可能的實現,它可以在最多4個通道(如cv::mean)的Mat上工作,並且不需要先驗知道可能數量的不同值。您可以查看評論/ decommenting在例如矩陣intialization部分,它正確地執行:

#include <opencv2/opencv.hpp> 
#include <vector> 
#include <numeric> 
#include <map> 
#include <iostream> 
using namespace cv; 
using namespace std; 

double robustMeanC1(const Mat1d& src, Vec2d bounds) 
{ 
    // Compute histogram (with no predefined range) 
    map<double, int> hist; 
    for (int r = 0; r < src.rows; ++r) 
    { 
     for (int c = 0; c < src.cols; ++c) 
     { 
      double key = src(r,c); 
      if (hist.count(key) == 0) { 
       hist.insert(make_pair(key, 1)); 
      } 
      else { 
       hist[key]++; 
      } 
     } 
    } 

    // Get vectors from map 
    vector<double> vals; 
    vector<int> sums; 
    vals.reserve(hist.size()); 
    sums.reserve(hist.size()); 
    for (auto kv : hist) 
    { 
     vals.push_back(kv.first); 
     sums.push_back(kv.second); 
    } 

    // Compute cumulative histogram 
    vector<int> cumhist(sums); 
    for (int i=1; i<sums.size(); ++i) 
    { 
     cumhist[i] = cumhist[i - 1] + sums[i]; 
    } 

    // Compute bounds 
    int total = src.rows * src.cols; 
    double low_bound = (total * bounds[0])/100.0; 
    double upp_bound = (total * bounds[1])/100.0; 
    int low_index = distance(cumhist.begin(), upper_bound(cumhist.begin(), cumhist.end(), low_bound)); 
    int upp_index = distance(cumhist.begin(), upper_bound(cumhist.begin(), cumhist.end(), upp_bound)); 

    if (low_index == upp_index) {upp_index++;} 

    // Compute mean 
    double mean = 0.0; 
    int count = 0; 
    for (int i = low_index; i < upp_index; ++i) 
    { 
     mean += vals[i] * sums[i]; 
     count += sums[i]; 
    } 
    mean /= count; 

    return mean; 
} 

Scalar robustMean(const Mat& src, Vec2d bounds) 
{ 
    Mat m; 
    src.convertTo(m, CV_64F); 

    Scalar res(0.0, 0.0, 0.0, 0.0); 

    if (m.channels() == 1) 
    { 
     res[0] = robustMeanC1(m, bounds); 
    } 
    else 
    { 
     vector<Mat1d> planes; 
     split(m, planes); 

     if (planes.size() > 4) 
     { 
      // Error, at most 4 channels 
      return Scalar(0,0,0,0); 
     } 

     for (int i = 0; i < planes.size(); ++i) 
     { 
      res[i] = robustMeanC1(planes[i], bounds); 
     } 
    } 
    return res; 
} 



int main() 
{ 
    Mat1d m(10,10, 5.f); 
    m(Range(0,1), Range::all()) = 2.0; 
    //m(Range(1, 2), Range::all()) = 80.0; 
    //randu(m, Scalar(0), Scalar(1)); 

    //Mat3b m = imread("path_to_image"); 

    Scalar rs = robustMean(m, Vec2d(10, 90)); 
    Scalar s = mean(m); 

    cout << "Robust Mean: " << rs << endl; 
    cout << "  Mean: " << s << endl; 

    return 0; 
} 
0

我就簡單的Mat元素進行排序,並採取截斷矢量的平均

#include <algorithm> 
#include <vector> 
// c in [0,1] the portion of middvalues added to the mean 
template<class _T> _T avg(std::vector<_T> & vec, double c) 
{ 
    if (c < 0.0) 
     c = 0.0; 
    else if (c > 1.0) 
     c = 1.0; 
    const size_t len = (size_t)(c * (double)vec.size()); 
    if (len == 0) 
     return 0.0; 
    std::vector<_T>::iterator beg = vec.begin(); 
    std::vector<_T>::iterator end = vec.end(); 
    if (len < vec.size()) 
    {  
     beg += (vec.size() - len)/2; 
     end = beg + len; 
     std::nth_element(vec.begin(), beg, vec.end()); 
     std::nth_element(beg, end, vec.end()); 
    } 
    double sum = 0.0, d = 0.0; 
    for (std::vector<_T>::iterator it = beg; it!=end; ++it, d+=1.0) 
     sum += *it; 
    return sum/d; 
} 
// fill the vector and compute for each channel separately. 

這裏的尾巴和頭爲簡單起見,相同的部分。