How to find the pixel value that corresponds to a specific number of pixels?

大兔子大兔子 提交于 2019-12-12 02:26:21

问题


Assume that I have a grayscale image in OpenCV.

I want to find a value so that 5% of pixels in the images have a value greater than it.

I can iterate over pixels and find number of pixels with the same value and then from the result find the value that %5 of pixel are above my value, but I am looking for a faster way to do this. Is there any such technique in OpenCV?

I think histogram would help, but I am not sure how I can use it.


回答1:


You need to:

  1. Compute the cumulative histogram of your pixel values
  2. Find the bin whose value is greater than 95% (100 - 5) of the total number of pixels.

Given an image uniformly random generated, you get an histogram like:

and the cumulative histogram like (you need to find the first bin whose value is over the blue line):

Then you need to find the proper bin. You can use std::lower_bound function to find the correct value, and std::distance to find the corresponding bin number (aka the value you want to find). (Please note that with lower_bound you'll find the element whose value is greater or equal to the given value. You can use upper_bound to find the element whose value is strictly greater then the given value)

In this case it results to be 242, which make sense for an uniform distribution from 0 to 255, since 255*0.95 = 242.25.

Check the full code:

#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;
}

Note

  • The histogram drawing function is an upgrade from a former version I posted here
  • You can use calcHist to compute the histograms, but I personally find easier to use the aforementioned method for 1D histograms.



回答2:


1) Determine the height and the width of the image, h and w.

2) Determine what 5% of the total number of pixels is (X)...

X = int(h * w * 0.05)

3) Start at the brightest bin in the histogram. Set total T = 0.

4) Add the number of pixels in this bin to your total T. If T is greater than X, you are finished and the value you want is the lower limit of the range of the current histogram bin.

3) Move to the next darker bin in your histogram. Goto 4.



来源:https://stackoverflow.com/questions/33830208/how-to-find-the-pixel-value-that-corresponds-to-a-specific-number-of-pixels

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!