OpenCV deep learning (8)-calcHist source code analysis

Source: Internet
Author: User

I 've been learning from the previous article for a long time. I analyzed the source code of calcHist, but I didn't quite understand it in some places. I 've been busy with graduation and have not continued, however, I always felt that something was not completed. In the past two days, I sorted out the source code of the calcHist and pasted it out to complete a task.

The source code of calcHist is divided into several situations based on the calculated Mat depth, respectively calling different static functions for implementation, where 8U is a common function, the 16U and 32F templates are used. Here we only analyze the 8U, which is to add a comment in the source code. I have learned a lot from reading the source code. Some of them are not quite clear. Please point out the mistakes and discuss them together.

The first is a general function calcHist.

/* Calculate the histogram of the given Image array */void cv: calcHist (const Mat * images, int nimages, const int * channels, InputArray _ mask, OutputArray _ hist, int dims, const int * histSize, const float ** ranges, bool uniform, bool accumulate) {/* obtain the mask matrix from the input mask agent */Mat mask = _ mask. getMat ();/* Ensure that the histogram dimension is at least one dimension, and the array with the bin size specified for the histogram is not empty */CV_Assert (dims> 0 & histSize ); /* obtain the pointer to the array storing the output histogram data from the output histogram proxy */uchar * histdata = _ hist. getMat (). data;/* Create The storage space of the output histogram. The proxy calls the creation function of the proxy object based on its proxy object. If ex: Is Mat, call Mat: create (int ndims, the const int * sizes, int type) function is used to allocate a bucket --- A 32F type storage */_ hist. create (dims, histSize, CV_32F); Mat hist = _ hist. getMat (), ihist = hist; // retrieve from the proxy or convert the proxy object to Mat;/* set the flag of the output -- pay attention to the last CV_32S, the subsequent histogram calculation uses the ihist temporary matrix. Therefore, we can see that the histogram calculation uses a 32 s depth matrix */ihist. flags = (ihist. flags &~ CV_MAT_TYPE_MASK) | CV_32S;/* The non-accumulative histogram or the pointer to the output storage starting from the acquisition is not the same as the newly allocated stored Pointer --??, Set the output to 0; otherwise, use the accumulate histogram to convert hist to ihist -- 32S [Use ihist as the temporary storage ??] */If (! Accumulate | histdata! = Hist. data) hist = Scalar (0 .); else hist. convertize (ihist, CV_32S);/* is the temporary array allocated for fast addressing when the histogram is calculated, saving some parameters */vector <uchar *> ptrs; vector <int> deltas; vector <double> uniranges; Size imsize; CV_Assert (! Mask. data | mask. type () = CV_8UC1);/* when you call the statistical histogram used after local static function compute-the first eight parameters are input, and the last four parameters are output, the first parameter is the size array of the output histogram, that is, the size of each dimension of the matrix */histPrepareImages (images, nimages, channels, mask, dims, hist. size, ranges, uniform, ptrs, deltas, imsize, uniranges);/* indicates whether the histogram is even, if yes, use the uniranges [0] pointer to initialize the constant */const double * _ uniranges = uniform? & Uniranges [0]: 0; int depth = images [0]. depth (); // obtain depth-the depth of all input images is the same. /* Depending on the depth, call the corresponding function compute histogram. When the depth is CV_8U, the local static function is called, while the other two cases call the function template; */if (depth = CV_8U)/* 8U image output histogram value ihist is 32S */calcHist_8u (ptrs, deltas, imsize, ihist, dims, ranges, _ uniranges, uniform); else if (depth = CV_16U) calcHist _ <ushort> (ptrs, deltas, imsize, ihist, dims, ranges, _ uniranges, uniform ); else if (depth = CV_32F) calcHist _ <float> (ptrs, deltas, imsize, ihist, dims, ranges, _ uniranges, uniform); else CV_Error (CV_StsUnsupportedFormat, "");/* convert ihist to hist and convert the depth to 32F. Combined with the preceding Visible data, the 32 s depth is used for computing statistics, that is, the integer format, the final output uses 32F to speed up */ihist. convertize (hist, CV_32F );}

The first call is a histPrepareImages function:

/* Calculate other parameters used to calculate the histogram Based on the given parameters, that is, convert the parameters. The first eight parameters are input, and the last four parameters are output. --- after the function returns, ptrs calculates the dims of the output histogram from 0 ~ The first address of the image data used in each dimension of dims-1; in deltas, it is the number of channels and byte offset of the corresponding image; in imsize, it is the image size. [acceleration of sequential access is performed if it is continuously stored ]; in uniranges, there is something related to the gray-scale range corresponding to each bin in the even histogram. I don't understand how it corresponds ??] */Static void histPrepareImages (const Mat * images, int nimages, const int * channels, const Mat & mask, int dims, const int * histSize, const float ** ranges, bool uniform, vector <uchar *> & ptrs, vector <int> & deltas, Size & imsize, vector <double> & uniranges) {int I, j, c; /* the dimension of the histogram is determined by channels or nimages. If channels is 0, the number of elements in the Image array must be the same as that in dims, that is, each image in the array uses a channel; if channels is not 0, channels and nimages jointly determine dims: Channels are arranged in turn. The number of channels starts from 0. The channels array specifies which channels are used to calculate the histogram, and channels indicates that the channels start from the 0th dimension of the histogram, that is, the first dimension of the histogram calculates the channel image specified by channels [0. */CV_Assert (channels! = 0 | nimages = dims);/* extract image size */imsize = images [0]. size ();/* obtain the image depth and the size of the elements in the image single channel */int depth = images [0]. depth (), esz1 = (int) images [0]. elemSize1 (); bool isContinuous = true;/* reset the size of the uchar array and the size of the int array */ptrs. resize (dims + 1); deltas. resize (dims + 1) * 2);/* process each dimension-arrange the image arrays by channel, place the first address of each channel image data in ptrs [I; deltas stores the number of channels mapped from each dimension [or each channel image] to the image in which the channel is located and the offset generated by the image byte alignment */for (I = 0; I <dims; I ++ ){/* The channel parameter is 0. Specify the channel with the dimension. For each image, only the channel 0 */if (! Channels) {j = I; c = 0; // the channel is 0 CV_Assert (images [j]. channels () = 1);} else {/* The number of channels is not 0 -- the extraction channel */c = channels [I]; CV_Assert (c> = 0 ); /* According to the channels parameter, set c to the channel image corresponding to the current dimension [dimension I]-This channel image or a single channel image in the Image array, or a channel of a multi-channel image in the array; The for loop below aims to find the channel image corresponding to channels [I] In the first few of the input array; after the loop ends, j is the image [single channel or multi channel] in the array corresponding to the current dimension (I .e. dimension I), and c points to a channel in the image; */for (j = 0; j <nimages; c-= images [j]. channels (), j ++) if (c <images [j]. channels () B Reak; CV_Assert (j <nimages);}/* Ensure that the size and depth of each image are the same */CV_Assert (images [j]. size () = imsize & images [j]. depth () = depth);/* Whether the image is continuously stored-byte alignment */if (! Images [j]. isContinuous () isContinuous = false;/* store the first data address of each channel image used to calculate the histogram in ptrs */ptrs [I] = images [j]. data + c * esz1; deltas [I * 2] = images [j]. channels (); // The number of channels each image is used to calculate the histogram./* images [j]. step/esz1 --- calculate the number of channels occupied by each row of the image, imsize. width * deltas [I * 2] --- the number of channels calculated by the number of channels for each element, --- so this sentence should be the offset caused by calculating the byte alignment-the "8U, 32F, 32S" in depth type ], 0 --- */deltas [I * 2 + 1] = (int) (images [j]. step/esz1-imsize. width * deltas [I * 2]);}/* use mask */if (mask. data) {CV_Assert (mask. size () = imsize & mask. channels () = 1); isContinuous = isContinuous & mask. isContinuous (); ptrs [dims] = mask. data; // The Last pointer is the data pointing to the mask; deltas [dims * 2] = 1; // number of channels -- the mask is 8UC1, so it is 1; // The number of elements in each row deltas [dims * 2 + 1] = (int) (mask. step/mask. elemSize1 ();}/* continuous storage, adjusting the width and height to accelerate access */if (isContinuous) {imsize. width * = imsize. height; imsize. height = 1;}/* bin The range is not specified. By default, the statistical even histogram for the 0-range must be an 8U depth image */if (! Ranges) {CV_Assert (depth = CV_8U);/* adjust the array size of the bin uniform histogram range and assign a value to */uniranges. resize (dims * 2); for (I = 0; I <dims; I ++) {uniranges [I * 2] = histSize [I]/256 .; uniranges [I * 2 + 1] = 0;} else if (uniform)/* uses a uniform histogram and specifies the number of bins in each dimension */{uniranges. resize (dims * 2); for (I = 0; I <dims; I ++) {CV_Assert (ranges [I] & ranges [I] [0] <ranges [I] [1]); /* specify the statistical range of each dimension */double low = ranges [I] [0], high = ranges [I] [1]; double t = histSize [I]/(high-low); uniranges [I * 2] = t; uniranges [I * 2 + 1] =-t * low ;}} else {/* Non-even histogram, ensure that the specified range is small-> large */for (I = 0; I <dims; I ++) {size_t j, n = histSize [I]; for (j = 0; j <n; j ++) CV_Assert (ranges [I] [j] <ranges [I] [j + 1]) ;}}

Then, calcHist calls the statistical function calcHist_8u of the 8U Deep Image for specific statistical calculation.

/* Histogram statistics function of an 8U depth image first generates a ing lookup table to speed up processing-understanding the ing relationship is the key-The ing relationship needs to be related to several input parameters ptr, deltas and the storage structure of the most important query table tab are clarified. The specific statistical calculation process is basically the same for dims> = 2, and the dims = 1 is slightly different, the statistical calculation process can be clearer only after the ing relationship is clarified. --- The parameter ptrs; deltas; imsize; is obtained through the histPrepareImages function calculation above. _ uniranges points to the first element of the uniranges array calculated by histPrepareImages; */static voidcalcHist_8u (vector <uchar *> & _ ptrs, const vector <int> & _ deltas, Size imsize, Mat & hist, int dims, const float ** _ ranges, const double * _ uniranges, bool uniform) {/* pointer to the image data used to calculate the histogram */uchar ** ptrs = & _ ptrs [0]; /* pointer to the above calculated image channels and the offset array */const int * deltas = & _ deltas [0]; ucha R * H = hist. data; // data Pointer of the output histogram -- 32 S int I, x; const uchar * mask = _ ptrs [dims]; // The Data Pointer of the mask int mstep = _ deltas [dims * 2 + 1]; // The Data Pointer of the mask moves the step vector <size_t> _ tab; /* generate a ing lookup table ----- to figure out the ing rules, you need to figure out the storage structure of several arrays or matrices: Mat, that is, hist; _ tab; ptr; delta; _ uniranges, etc. */calcHistLookupTables_8u (hist, SparseMat (), dims, _ ranges, _ uniranges, uniform, false, _ tab ); const size_t * tab = & _ tab [0];/* treat different dimensions */if (dims = 1) {/* d0 -- number of channels, s Tep0 byte alignment offset */int d0 = deltas [0], step0 = deltas [1]; int matH [256] = {0 }; // Save the statistics for each gray value. const uchar * p0 = (const uchar *) ptrs [0]; // Image Data Pointer/**/for (; imsize. height --; p0 + = step0, mask + = mstep) {/* do not use mask */if (! Mask) {/* single channel image */if (d0 = 1) {/* single channel, 4-byte alignment, statistics for each byte */for (x = 0; x <= imsize. width-4; x + = 4) {int t0 = p0 [x], t1 = p0 [x + 1]; matH [t0] ++; matH [t1] ++; t0 = p0 [x + 2]; t1 = p0 [x + 3]; matH [t0] ++; matH [t1] ++ ;} p0 + = x;} else/* multi-channel image */{/* multi-channel, only statistics on 0th channels, d0 offset */for (x = 0; x <= imsize. width-4; x + = 4) {int t0 = p0 [0], t1 = p0 [d0]; matH [t0] ++; matH [t1] ++; p0 + = d0 * 2; t0 = p0 [0]; t1 = p0 [d0 ]; MatH [t0] ++; matH [t1] ++; p0 + = d0 * 2 ;}/ * Non-4-byte alignment, process it independently */for (; x <imsize. width; x ++, p0 + = d0) matH [* p0] ++;} else/* directly collects statistics when mask is used */for (x = 0; x <imsize. width; x ++, p0 + = d0) if (mask [x]) matH [* p0] ++;}/* stores the statistical data into the histogram matrix, use the ing of gray value to bin to find the corresponding bin location */for (I = 0; I <256; I ++) {size_t hidx = tab [I]; // hidx -- that is, the position in the histogram // only count the non-exceeded value if (hidx <OUT_OF_RANGE) * (int *) (H + hidx) + = matH [I] ;}} else If (dims = 2)/* 2-Dimensional Histogram */{/* retrieves the number of channels of the image used to calculate the two-dimensional histogram, And the byte alignment offset, data Pointer, etc. */int d0 = deltas [0], step0 = deltas [1], d1 = deltas [2], step1 = deltas [3]; const uchar * p0 = (const uchar *) ptrs [0]; const uchar * p1 = (const uchar *) ptrs [1];/**/for (; imsize. height --; p0 + = step0, p1 + = step1, mask + = mstep) {if (! Mask)/* No mask */{/* calculate the position in the histogram Based on the ing table, and then accumulate */for (x = 0; x <imsize. width; x ++, p0 + = d0, p1 + = d1) {/* idx is a 0th-dimension offset [tab [* p0] + a 1st-dimension offset [tab [* p1 + 256] --- similar to the row offset of the image + column offset * /size_t idx = tab [* p0] + tab [* p1 + 256]; if (idx <OUT_OF_RANGE) ++ * (int *) (H + idx );}} when else/* mask is used */{/*, the same as above, only the mask is used to determine */for (x = 0; x <imsize. width; x ++, p0 + = d0, p1 + = d1) {size_t idx; if (mask [x] & (idx = tab [* p0] + tab [* p1 + 2 56]) <OUT_OF_RANGE) ++ * (int *) (H + idx) ;}}} else if (dims = 3) /* Three-dimensional histogram -- similar to two-dimensional histograms, only one dimension is added. The calculation of idx for finding the histogram position is complicated */{int d0 = deltas [0], step0 = deltas [1], d1 = deltas [2], step1 = deltas [3], d2 = deltas [4], step2 = deltas [5]; const uchar * p0 = (const uchar *) ptrs [0]; const uchar * p1 = (const uchar *) ptrs [1]; const uchar * p2 = (const uchar *) ptrs [2];/**/for (; imsize. height --; p0 + = step0, p1 + = step1, P2 + = step2, mask + = mstep) {if (! Mask)/**/for (x = 0; x <imsize. width; x ++, p0 + = d0, p1 + = d1, p2 + = d2) {/* 0th + 1 + 2 offset to obtain the total offset */size_t idx = tab [* p0] + tab [* p1 + 256] + tab [* p2 + 512]; if (idx <OUT_OF_RANGE) + + * (int *) (H + idx);} else/**/for (x = 0; x <imsize. width; x ++, p0 + = d0, p1 + = d1, p2 + = d2) {size_t idx; if (mask [x] & amp; (idx = tab [* p0] + tab [* p1 + 256] + tab [* p2 + 512]) <OUT_OF_RANGE) ++ * (int *) (H + idx );}}} Else/* high-dimensional histogram (> 3-dimensional) */{for (; imsize. height --; mask + = mstep) {if (! Mask)/* mask-free image computing */for (x = 0; x <imsize. width; x ++) {uchar * Hptr = H; for (I = 0; I <dims; I ++) {size_t idx = tab [* ptrs [I] + I * 256]; if (idx> = OUT_OF_RANGE) break; Hptr + = idx; ptrs [I] + = deltas [I * 2];}/* determines whether there is an exceeded value. That is, the previously set value outside the ranges range is OUT_OF_RANGE, these values must be crossed during Statistics */if (I = dims) ++ * (int *) Hptr); else for (; I <dims; I ++) ptrs [I] + = deltas [I * 2];} else/* use a masking image */for (x = 0; x <imsize. width; x ++) {uchar * Hptr = H; int I = 0; if (mask [x]) for (; I <dims; I ++) {size_t idx = tab [* ptrs [I] + I * 256]; if (idx> = OUT_OF_RANGE) break; Hptr + = idx; ptrs [I] + = deltas [I * 2];} if (I = dims) + + * (int *) Hptr); else for (; I <dims; I ++) ptrs [I] + = deltas [I * 2];}/* byte alignment offset */for (I = 0; I <dims; I ++) ptrs [I] + = deltas [I * 2 + 1] ;}}

 

A query table is used in calcHist_8u to speed up processing. The function for generating a query table is as follows:

Static const size_t OUT_OF_RANGE = (size_t) 1 <(sizeof (size_t) * 8-2);/* Create a search table -- that is, ing each gray value of 8 U to the corresponding bin value to speed up the calculation of the statistical histogram. _ tab is a ing from each one-dimensional value of the histogram to the position in the output histogram, that is, the index in the tab is 0 ~ 0th dimension ~ 255, 1st dimension 0 ~ 255... dimension dims-1 0 ~ 255; while value is every 0 ~ The value of 255 is mapped to the offset of dimension I in the final histogram, that is, the offset relative to the first address of the dimension data ]. Set OUT_OF_RANGE */static values (const Mat & hist, const SparseMat & shist, int dims, const float ** ranges, const double * uniranges, bool uniform, bool issparse, vector <size_t> & _ tab) {/* upper/lower limit? */Const int low = 0, high = 256; int I, j;/* resize */_ tab. resize (high-low) * dims); size_t * tab = & _ tab [0];/* even histogram */if (uniform) {/**/for (I = 0; I <dims; I ++) {/* the value of uniranges in the histPrepareImages function is double _ low = ranges [I] [0], _ high = ranges [I] [1]; double t = histSize [I]/(_ high-_ low); uniranges [I * 2] = t; uniranges [I * 2 + 1] =-t * _ low; */double a = uniranges [I * 2]; double B = uniranges [I * 2 + 1]; /* Whether it is sparse or straight Graph */int sz =! Issparse? Hist. size [I]: shist. size (I); size_t step =! Issparse? Hist. step [I]: 1; // step indicates the step of the I dimension of the output histogram/* assigns a value to the tab */for (j = low; j 

The histogram statistics for images of 8 U depth involve these functions. I hope you will not give me any comments!

This is the end of calcHist learning.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.