如何找到与特定像素数对应的像素值?

时间:2015-11-20 15:21:31

标签: c++ opencv image-processing opencv3.0

假设我在OpenCV中有一个灰度图像。

我想找一个值,以便图片中5%像素的值大于它。

我可以迭代像素并查找具有相同值的像素数,然后从结果中找到像素的%5高于我的值的值,但我正在寻找更快的方法来执行此操作。 OpenCV中有没有这样的技术?

我认为直方图会有所帮助,但我不确定如何使用它。

2 个答案:

答案 0 :(得分:2)

你需要:

  1. 计算像素值的累积直方图
  2. 找到其值大于总像素数的95%(100 - 5)的bin。
  3. 如果生成的图像均匀随机,则会得到如下的直方图:

    enter image description here

    和累积直方图一样(你需要找到其值超过蓝线的第一个bin):

    enter image description here

    然后你需要找到合适的垃圾箱。您可以使用std::lower_bound函数查找正确的值,并使用std::distance查找相应的bin编号(也就是您要查找的值)。 (请注意,使用lower_bound,您将找到值为greater or equal的元素到给定值。您可以使用upper_bound来查找值严格的元素更大然后是给定值)

    在这种情况下,结果为242,从0到255的均匀分布是有意义的,因为255*0.95 = 242.25

    检查完整代码:

    #include <opencv2\opencv.hpp>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    using namespace cv;
    
    void drawHist(const vector<int>& data, Mat3b& dst, int binSize = 3, int height = 0, int ref_value = -1)
    {
        int max_value = *max_element(data.begin(), data.end());
        int rows = 0;
        int cols = 0;
        float scale = 1;
        if (height == 0) {
            rows = max_value + 10;
        }
        else {
            rows = height; 
            scale = float(height) / (max_value + 10);
        }
        cols = data.size() * binSize;
        dst = Mat3b(rows, cols, Vec3b(0, 0, 0));
        for (int i = 0; i < data.size(); ++i)
        {
            int h = rows - int(scale * data[i]);
            rectangle(dst, Point(i*binSize, h), Point((i + 1)*binSize - 1, rows), (i % 2) ? Scalar(0, 100, 255) : Scalar(0, 0, 255), CV_FILLED);
        }
    
        if (ref_value >= 0)
        {
            int h = rows - int(scale * ref_value);
            line(dst, Point(0, h), Point(cols, h), Scalar(255,0,0));
        }
    }
    
    int main()
    {
    
        Mat1b src(100, 100);
        randu(src, Scalar(0), Scalar(255));
    
        int percent = 5; // percent % of pixel values are above a val
        int val;  // I need to find this value
    
    
        int n = src.rows * src.cols; // Total number of pixels
        int th = cvRound((100 - percent) / 100.f * n);  // Number of pixels below val
    
        // Histogram
        vector<int> hist(256, 0);
        for (int r = 0; r < src.rows; ++r) {
            for (int c = 0; c < src.cols; ++c) {
                hist[src(r, c)]++;
            }
        }
    
        // Cumulative histogram
        vector<int> cum = hist;
        for (int i = 1; i < hist.size(); ++i) {
            cum[i] = cum[i - 1] + hist[i];
        }
    
        // lower_bound returns an iterator pointing to the first element
        // that is not less than (i.e. greater or equal to) th.
        val =  distance(cum.begin(), lower_bound(cum.begin(), cum.end(), th));
    
    
        // Plot histograms
        Mat3b plotHist, plotCum;
        drawHist(hist, plotHist, 3, 300);
        drawHist(cum, plotCum, 3, 300, *lower_bound(cum.begin(), cum.end(), th));
    
        cout << "Value: " << val;
    
        imshow("Hist", plotHist);
        imshow("Cum", plotCum);
        waitKey();
    
        return 0;
    }
    

    注意

    • 直方图绘制功能是我发布的here
    • 的旧版本的升级版
    • 您可以使用calcHist来计算直方图,但我个人觉得更容易使用上述方法进行一维直方图。

答案 1 :(得分:0)

1)确定图像的高度和宽度hw

2)确定像素总数的5%是(X)...

X = int(h * w * 0.05)

3)从直方图中最亮的bin开始。设置总计T = 0。

4)将此bin中的像素数添加到总T。如果T大于X,则表示您已完成,所需的值是当前直方图区间范围的下限。

3)移动直方图中的下一个较暗的bin。转到4。