3#include "../_cexports/c_light_meter.h"
5#include "../global.hpp"
7#include "../exception.hpp"
9#include "../area_2d.hpp"
53 , standardDeviation_(0.0)
59 Histogram(CExports::LMH lmHandle,
int plane)
67 , standardDeviation_(0.0)
71 size_t numEntries = 0;
72 CVB_CALL_CAPI_CHECKED(LMGetDataBufferEntries(lmHandle, plane, &numEntries));
73 values_.resize(numEntries);
74 for (
size_t i = 0; i < numEntries; ++i)
77 CVB_CALL_CAPI_CHECKED(LMGetSingleHistogramEntry(lmHandle, plane, i, &val));
83 CVB_CALL_CAPI_CHECKED(LMGetStatisticTotal(lmHandle, plane, &out));
85 CVB_CALL_CAPI_CHECKED(LMGetStatisticMean(lmHandle, plane, &mean_));
86 CVB_CALL_CAPI_CHECKED(LMGetStatisticMode(lmHandle, plane, &mode_));
87 CVB_CALL_CAPI_CHECKED(LMGetStatisticMin(lmHandle, plane, &min_));
88 CVB_CALL_CAPI_CHECKED(LMGetStatisticMax(lmHandle, plane, &max_));
89 CVB_CALL_CAPI_CHECKED(LMGetStatisticVariance(lmHandle, plane, &variance_));
90 CVB_CALL_CAPI_CHECKED(LMGetStatisticStdDev(lmHandle, plane, &standardDeviation_));
91 median_ = CalculateMedianIndex();
97 int CalculateMedianIndex()
const noexcept
100 for (uint64_t countBelow = 0; (idx < values_.size()) && (countBelow < (numPixels_ / 2)); ++idx)
102 countBelow += values_[idx];
104 return static_cast<int>(idx);
155 double Min() const noexcept
155 double Min() const noexcept {
…}
165 double Max() const noexcept
165 double Max() const noexcept {
…}
187 return standardDeviation_;
197 return static_cast<int>(values_.size());
218 if (
static_cast<std::size_t>(index) >= values_.size())
223 return values_[index];
234 double standardDeviation_;
240 typedef HandleGuard<void, CVB_CALL_CAPI(ReleaseLMVoid)> ReleaseLMGuard;
248 CExports::LMH hLM = 0;
249 CVB_CALL_CAPI_CHECKED(LMCreate(&hLM));
250 ReleaseLMGuard hLMHolder(
reinterpret_cast<void *
>(hLM));
252 CVB_CALL_CAPI_CHECKED(LMSetImage(hLM, image.
Handle()));
253 for (CExports::cvbdim_t i = 0; i < image.
PlanesCount(); ++i)
255 CVB_CALL_CAPI_CHECKED(LMSetEntireImageFlag(hLM, i,
false));
256 CVB_CALL_CAPI_CHECKED(LMSetProcessFlag(hLM, i,
true));
259 for (CExports::cvbdim_t i = 0; i < image.
PlanesCount(); ++i)
261 CVB_CALL_CAPI_CHECKED(LMSetDensity(hLM, i,
std::lround(density * 1000.0)));
262 CVB_CALL_CAPI_CHECKED(LMSetUseCSFlag(hLM, i, !ignoreImageCs));
263 CVB_CALL_CAPI_CHECKED(LMSetArea(hLM, i,
reinterpret_cast<CExports::TArea &
>(aoi)));
265 CVB_CALL_CAPI_CHECKED(LMExecute(hLM));
267 for (CExports::cvbdim_t i = 0; i < image.
PlanesCount(); ++i)
290 return Private::CreateHistograms(image,
Area2D(
static_cast<Rect<double>>(aoi)), density,
true);
306 return Private::CreateHistograms(image, aoi, density,
false);
381 inline std::vector<double> MakeBlurFilter(
int blurSize)
383 return std::vector<double>(blurSize, 1.0 / blurSize);
386 template <
class HISTVAL>
387 inline std::vector<double> MakeBorderedHistogram(
const std::vector<HISTVAL> &histogram,
size_t kernelSize)
389 std::vector<double> result(histogram.size() + kernelSize - 1);
392 auto firstValue = histogram[0];
393 for (
size_t i = 0, bckOffset = kernelSize / 2; i < bckOffset; ++i)
395 result[j++] =
static_cast<double>(firstValue);
398 for (
size_t i = 0; i < histogram.size(); ++i)
400 result[j++] =
static_cast<double>(histogram[i]);
403 auto lastValue = histogram[histogram.size() - 1];
404 for (; j < result.size(); ++j)
406 result[j] =
static_cast<double>(lastValue);
412 template <
class RANGE>
413 inline typename TypedRange<std::vector<double>, double, RANGE>::type
414 ApplyKernel(
const std::vector<double> &borderedHistogram,
const RANGE &kernel)
416 auto kernelRange = MakeRangeAdapter<double>(kernel, 1);
417 std::vector<double> result(borderedHistogram.size() - kernelRange.Size() + 1);
419 for (
size_t i = 0; i < result.size(); ++i)
422 for (
size_t k = 0; k < kernelRange.Size(); ++k)
424 val += borderedHistogram[i + k] * kernel[k];
431 inline std::vector<PeakData> FindZeroCrossings(
const std::vector<double> &blurredHistogram,
432 const std::vector<double> &derivedHistogram)
436 std::find_if(derivedHistogram.begin(), derivedHistogram.end(), [](
double val) { return val != 0.0; });
437 if (itNonZero == derivedHistogram.end())
439 return std::vector<PeakData>();
442 size_t i = std::distance(derivedHistogram.begin(), itNonZero);
444 auto sign = [](
double val) {
return (val == 0.0) ? 0 : ((val < 0.0) ? -1 : 1); };
446 std::vector<PeakData> positions;
447 auto lastStart = i++;
448 auto lastSign = sign(derivedHistogram[lastStart]);
449 for (; i < derivedHistogram.size(); i++)
453 auto thisSign = sign(derivedHistogram[i]);
456 if (thisSign != lastSign)
458 auto peakPos = (i + lastStart) / 2;
459 positions.push_back(PeakData{
static_cast<int>(peakPos), blurredHistogram[peakPos]});
468 inline std::vector<int> FilterByMinDistance(
const std::vector<PeakData> &zeroCrossings,
int minDiff)
470 std::vector<PeakData> descendingCrossings(zeroCrossings);
471 std::sort(descendingCrossings.begin(), descendingCrossings.end(),
472 [](PeakData first, PeakData second) { return first.Quality > second.Quality; });
473 std::vector<int> values(descendingCrossings.size());
474 std::transform(descendingCrossings.begin(), descendingCrossings.end(), values.begin(),
475 [](PeakData peak) { return peak.GrayValue; });
477 for (
size_t i = 0; i < values.size() - 1; ++i)
479 for (
size_t k = i + 1; k < values.size(); ++k)
481 auto diff = std::abs(values[i] - values[k]);
484 values.erase(values.begin() + k--);
503 template <
class HISTVAL,
class RANGE>
504 inline typename TypedRange<std::vector<double>, double, RANGE>::type
508 if ((kernelSize < 1) || (
static_cast<size_t>(kernelSize) > histogram.size()))
513 auto borderedHistogram = Private::MakeBorderedHistogram(histogram, kernelSize);
514 return Private::ApplyKernel(borderedHistogram, kernel);
528 if ((blurSize < 1) || (
static_cast<size_t>(blurSize) > histogram.size()) || (minDiff < 1))
533 auto blurredHistogram =
FilterHistogram(histogram, Private::MakeBlurFilter(
static_cast<int>(blurSize)));
534 auto derivedHistogram =
FilterHistogram(blurredHistogram, Private::MakeDerivationFilter());
535 auto zeroCrossings = Private::FindZeroCrossings(blurredHistogram, derivedHistogram);
536 return Private::FilterByMinDistance(zeroCrossings, minDiff);
550 if ((lowerLimit < 0) || (
static_cast<size_t>(upperLimit) >= histogram.size()))
556 for (
int i = lowerLimit; i <= upperLimit; ++i)
558 nres += histogram[i];
565 using HistogramAnalyzer::Histogram;
Structure that represents an area of interest in the image.
Definition area_2d.hpp:21
A single histogram result.
Definition histogram_analyzer.hpp:43
double Mean() const noexcept
Get the mean value of all pixels.
Definition histogram_analyzer.hpp:135
double Min() const noexcept
Get the minimum gray value of the histogram.
Definition histogram_analyzer.hpp:155
uint64_t Median() const noexcept
Get the median index (index of the histogram slot, at which roughly 50% of the pixels are darker and ...
Definition histogram_analyzer.hpp:124
int Count() const noexcept
The number of elements corresponds to the number of possible gray values.
Definition histogram_analyzer.hpp:195
std::vector< uint64_t > Values() const
The actual histogram values.
Definition histogram_analyzer.hpp:205
double Variance() const noexcept
Get the variance of the histogram.
Definition histogram_analyzer.hpp:175
uint64_t operator[](int index) const
Gets the histogram value at given index.
Definition histogram_analyzer.hpp:216
double Max() const noexcept
Get the maximum gray value of the histogram.
Definition histogram_analyzer.hpp:165
double StandardDeviation() const noexcept
Get the standard deviation of the histogram.
Definition histogram_analyzer.hpp:185
uint64_t NumPixels() const noexcept
Total number of pixels taken into account.
Definition histogram_analyzer.hpp:113
double Mode() const noexcept
Get the mode (the most common gray value) of the histogram.
Definition histogram_analyzer.hpp:145
The Common Vision Blox image.
Definition decl_image.hpp:45
int PlanesCount() const noexcept
Get the number of planes for this image.
Definition decl_image.hpp:242
Rect< int > Bounds() const noexcept
Bounding rectangle of the image in pixels.
Definition decl_image.hpp:433
void * Handle() const noexcept
Classic API image handle.
Definition decl_image.hpp:232
Image plane information container.
Definition decl_image_plane.hpp:29
std::unique_ptr< Image > Map() const
Create a map from a single image plane that shares its memory with the original plane.
Definition detail_image_plane.hpp:100
Rectangle object.
Definition rect.hpp:24
Collection of functions for analyzing the image histogram.
Definition histogram_analyzer.hpp:30
std::vector< int > FindHistogramPeaks(const std::vector< uint64_t > &histogram, int blurSize, int minDiff)
Find peaks in the histogram identified by the supplied criteria.
Definition histogram_analyzer.hpp:526
uint64_t SumHistogramBetween(const std::vector< uint64_t > &histogram, int lowerLimit, int upperLimit)
Count the number of pixels that lie between two limits in the histogram.
Definition histogram_analyzer.hpp:548
std::vector< Histogram > CreateImageHistograms(const Image &image, Rect< int > aoi, double density=1.0)
Creates a histogram for each plane of the aoi in the given image.
Definition histogram_analyzer.hpp:288
TypedRange< std::vector< double >, double, RANGE >::type FilterHistogram(const std::vector< HISTVAL > &histogram, const RANGE &kernel)
Filter a histogram array with the given kernel. At the beginning and end of the histogram,...
Definition histogram_analyzer.hpp:505
Histogram CreatePlaneHistogram(const ImagePlane &imagePlane, Rect< int > aoi, double density=1.0)
Creates a histogram for the aoi in the given plane.
Definition histogram_analyzer.hpp:333
Namespace for the Foundation package.
Definition decl_metric_aqs12_calibration_piece.hpp:11
Root namespace for the Image Manager interface.
Definition c_bayer_to_rgb.h:17
std::vector< int > Histogram(const ImagePlane &plane, Area2D aoi, double density=1.0)
Gather and return the histogram from an 8 bits per pixel unsigned image.
Definition analyze.hpp:30