Couting the Pixels with Histograms

The distribution of pixels value across the image constitutes an important characteristic of this image. that's the concept discript as histograms.A histogram is a simple table that gives the numbeer of pixes that have a give value in an images or sometimes a set of image. 也就是一张图片中每个颜色的像素有多少的统计表。 比如gray-level. will have 256 entries (or bins),Bin 0 give the number of pixel having value 0, bin 1 number of pixes have value1 and so on. Obvisously, if you sum all of these bins of a histogram, you should get the total number of pixels. Histograms can also be normalized such that sum of the bins equals 1, each bin give the percentage of pixels haveing specific value in the image.



Calculates a histogram of a set of arrays.

C++: voidcalcHist(const Mat*images, intnimages, const int*channels, InputArraymask, OutputArrayhist, intdims, const int*histSize, const float**ranges, booluniform=true, boolaccumulate=false )

C++: voidcalcHist(const Mat*images, intnimages, const int*channels, InputArraymask, SparseMat&hist, intdims, const int*histSize, const float**ranges, booluniform=true, boolaccumulate=false )
  • images – Source arrays. They all should have the same depth,CV_8U orCV_32F , and the same size. Each of them can have an arbitrary number of channels.
  • nimages – Number of source images.

     上面两个参数很好理解因为数组参数我们是不知道size 的,所以传递 images 要加上一个 nimages 说明有多少个image, *image++ till to *image[nimages-1]

  • channels – List of the dims channels used to compute the histogram. The first array channels are numerated from 0 toimages[0].channels()-1 , the second array channels are counted fromimages[0].channels() toimages[0].channels() + images[1].channels()-1, and so on.

      Mat 本身就有channels()函数可以获得自己有多少个channel的,所以这个参数是用来指示我们用那些channels 去计算histogram, ie int chnels[]={0,1}; means we calculate each image's 0th and 1st channel, if

int channels[]={1,2};will calculate channles[1] and channels[2]


  • mask – Optional mask. If the matrix is not empty,it must be an 8-bit array of the same size asimages[i] . The non-zero mask elements mark the array elements counted in the histogram.  (need to do a experiment to get understand it ,so let it pass first)


  • hist – Output histogram, which is a dense or sparsedims -dimensional array.
  • dims – Histogram dimensionality that must be positive and not greater thanCV_MAX_DIMS (equal to 32 in the current OpenCV version).只计算一个channel 就是 1D, 如果是2个channel就是2D ,

  

  • histSize – Array of histogram sizes in each dimension. 比如我们计算HSV H,S 两个channel,H channel 最大去到30也就是Bins (Bar)  数目是30, but S channel can till to 32 Bins.  我们想象MAT 里面看到直方图,那里是gray -level 的,也就是一个channel 的,把这个想个一个unit,1 channel on unit,他的水平轴就是hitsSize 的每个值。

      


  • ranges – Array of the dims arrays of the histogram bin boundaries in each dimension. When the histogram is uniform (uniform =true), then for each dimensioni it is enough to specify the lower (inclusive) boundaryL_0 of the 0-th histogram bin and the upper (exclusive) boundaryU_{\texttt{histSize}[i]-1} for the last histogram binhistSize[i]-1 . That is, in case of a uniform histogram each ofranges[i] is an array of 2 elements. When the histogram is not uniform (uniform=false ), then each ofranges[i] containshistSize[i]+1 elements:L_0, U_0=L_1, U_1=L_2, ..., U_{\texttt{histSize[i]}-2}=L_{\texttt{histSize[i]}-1}, U_{\texttt{histSize[i]}-1} . The array elements, that are not between L_0 andU_{\texttt{histSize[i]}-1} , are not counted in the histogram.

      ranges[0] to rangs[dims-1] 也就是每一个channel 都有自己的范围,比如H is from 0 -179 ,S from 0-255 . 因此

     ranges[i] 的每一个元素也是一个数组,一个二维数组,指明每一个channel 的范围。



  • uniform – Flag indicating whether the histogram is uniform or not (see above).
  • accumulate – Accumulation flag. If it is set, the histogram is not cleared in the beginning when it is allocated. This feature enables you to compute a single histogram from several sets of arrays, or to update the histogram in time.

#include <cv.h>
#include <highgui.h>

using namespace cv;

int main( int argc, char** argv )
{
    Mat src, hsv;
    if( argc != 2 || !(src=imread(argv[1], 1)).data )
        return -1;

    cvtColor(src, hsv, CV_BGR2HSV);

    // Quantize the hue to 30 levels
    // and the saturation to 32 levels
    int hbins = 30, sbins = 32;
    int histSize[] = {hbins, sbins};
    // hue varies from 0 to 179, see cvtColor
    float hranges[] = { 0, 180 };//Note need to plus +1 for the max rangs
    // saturation varies from 0 (black-gray-white) to
    // 255 (pure spectrum color)
    float sranges[] = { 0, 256 };
    const float* ranges[] = { hranges, sranges };
    MatND hist;
    // we compute the histogram from the 0-th and 1-st channels
    int channels[] = {0, 1};

显然这里30 个 Bin 去表达180 个value的intensity. ie:Bin0 就是0-5 的H value.

 calcHist( &hsv, 1, channels, Mat(), // do not use mask
             hist, 2, histSize, ranges,
             true, // the histogram is uniform
             false );
    double maxVal=0;
    minMaxLoc(hist, 0, &maxVal, 0, 0);

    int scale = 10;
    Mat histImg = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);

    for( int h = 0; h < hbins; h++ )
        for( int s = 0; s < sbins; s++ )
        {
            float binVal = hist.at<float>(h, s); //Note that the value stored as float in the histogram
            int intensity = cvRound(binVal*255/maxVal);
            rectangle( histImg, Point(h*scale, s*scale),
                        Point( (h+1)*scale - 1, (s+1)*scale - 1),
                        Scalar::all(intensity),
                        CV_FILLED );
        }

    namedWindow( "Source", 1 );
    imshow( "Source", src );

    namedWindow( "H-S Histogram", 1 );
    imshow( "H-S Histogram", histImg );
    waitKey();
}



 



=======My Test version

#include "openCV.h"
int main()

{
    const string imagePath="c://image//test.png";
    cv::Mat image(3,4,CV_8UC3,Scalar(50,100,150));
    const string sourceImageWindowName="Source Image";
//    namedWindow(sourceImageWindowName,CV_WINDOW_AUTOSIZE);
     imshow(sourceImageWindowName,image);
//    imwrite(imagePath,image);


    int channels[3]={0,1,2};
    int hSize[3]={256,256,256};
    float range[2]={0,255};
    const float * hRange[3]={range,range,range};

    MatND hist;
    calcHist(&image,1,channels,Mat(),hist,2,hSize,hRange,true,false);
    cout<<hist.rows<<" "<<hist.cols<<endl;
    
    for(int r=0;r<hist.rows;++r)
    {
       for(int c=0;c<hist.cols;++c)
       {
           float histValue=hist.at<float>(r,c);
           if(histValue>0)
           cout<<r<<" "<<c<<" "<< histValue<<endl;
       }
    
    }

//可以看到打印出来的结果:50 100 12,也就是 channel[0]=50 &channel[1]=100 的pixel 有12 个,

2 demension Mat 有256*256 ,calcHist will calculate each possible 组合,然后算出这些组合有多少个像素。 注意我用的是像素而不是channel,calcHist 不是bye channel去计算,比如channel[0] 0-255 每一个value有多少个,从而得到

256*2 的Mat 结果,,之前的这个想法是错的。 同理3 dimension will calculate 256*256*256 个组合所有的像素个数

所以会得出很多0 , as follow show:

    MatND hist3D;
    calcHist(&image,1,channels,Mat(),hist3D,3,hSize,hRange,true,false);

    cout<<"total:"<<hist3D.total()<<endl;
    float histValu=hist3D.at<float>(50,100,150);// get 50,100,150出的value,因为我理解这个计算,So I do it jus at here.
    cout<<"hValue"<<histValu<<endl; //print 12

//because will generate lot's of zero, that will wast memroy. we use sparseMat

    SparseMat sparsemat(3,hSize,CV_32FC1);
    calcHist(&image,1,channels,Mat(),sparsemat,3,hSize,hRange);
    cout<<"sparseMat size"<<sparsemat.size()[0]<<" "<<sparsemat.size()[1]<<" "<< sparsemat.size()[2]<<endl;
    //ptrdiff_t pDiff;.

    int dims=sparsemat.dims();
    SparseMatConstIterator
        it=sparsemat.begin(),
        itEnd=sparsemat.end();
   for(;it!=itEnd;++it)
   {
      const SparseMat::Node * node=it.node();
       cout<<"(";
       for(size_t i=0;i<dims;i++)
           cout<<node->idx[i]<<",";
       cout<<")";
       cout<<it.value<float>()<<endl;
  ///   (50,100,150,)12,虽然SparseMat 不存0,但他的order 不边,so 12 will store at 50 100 150
      // cout<<(*it)<<endl;
   }
        


    waitKey(0);
return 0;
}

==========print result=======

256 256
50 100 12
total:16777216
hValue12
sparseMat size256 256 256
(50,100,150,)12



=========SparseMat study==============

The class SparseMat represents multi-dimensional sparse numerical arrays. Such a sparse array can store elements of any type thatMat can store. Sparse means that only non-zero elements are stored (though, as a result of operations on a sparse matrix, some of its stored elements can actually become 0. It is up to you to detect such elements and delete them using SparseMat::erase ). The non-zero elements are stored in a hash table that grows when it is filled so that the search time is O(1) in average (regardless of whether element is there or not). Elements can be accessed using the following methods:

  • Query operations (SparseMat::ptr and the higher-levelSparseMat::ref,SparseMat::value andSparseMat::find), for example:

    const int dims = 5;
    int size[] = {10, 10, 10, 10, 10};
    SparseMat sparse_mat(dims, size, CV_32F);//5 维,每一维是10个元素,so will have 10^5 element
    for(int i = 0; i < 1000; i++)
    {
        int idx[dims];
        for(int k = 0; k < dims; k++)
            idx[k] = rand()
  •         //idx 其实就相当于这个5维空间的坐标拉,,,
  •  sparse_mat.ref<float>(idx) += 1.f; //assign value to this point
    }
    
  • Sparse matrix iterators. They are similar toMatIterator but different fromNAryMatIterator. That is, the iteration loop is familiar to STL users:

    // prints elements of a sparse floating-point matrix
    // and the sum of elements.
    SparseMatConstIterator_<float>
        it = sparse_mat.begin<float>(),
        it_end = sparse_mat.end<float>();
    double s = 0;
    int dims = sparse_mat.dims();
    for(; it != it_end; ++it)
    {
        // print element indices and the element value
        const SparseMat::Node* n = it.node();
        printf("(");
        for(int i = 0; i < dims; i++)
            printf("%d%s", n->idx[i], i < dims-1 ? ", " : ")");
        printf(": %g\n", it.value<float>());  //打印非零元素的坐标and its value
        s += *it;
    }
    printf("Element sum is %g\n", s);
    

    If you run this loop, you will notice that elements are not enumerated in a logical order (lexicographical, and so on). They come in the same order as they are stored in the hash table (semi-randomly). You may collect pointers to the nodes and sort them to get the proper ordering. Note, however, that pointers to the nodes may become invalid when you add more elements to the matrix. This may happen due to possible buffer reallocation.

  • Combination of the above 2 methods when you need to process 2 or more sparse matrices simultaneously. For example, this is how you can compute unnormalized cross-correlation of the 2 floating-point sparse matrices:

    double cross_corr(const SparseMat& a, const SparseMat& b)
    {
        const SparseMat *_a = &a, *_b = &b;
        // if b contains less elements than a,
        // it is faster to iterate through b
        if(_a->nzcount() > _b->nzcount())
            std::swap(_a, _b);
        SparseMatConstIterator_<float> it = _a->begin<float>(),
                                       it_end = _a->end<float>();
        double ccorr = 0;
        for(; it != it_end; ++it)
        {
            // take the next element from the first matrix
            float avalue = *it;
            const Node* anode = it.node();
            // and try to find an element with the same index in the second matrix.
            // since the hash value depends only on the element index,
            // reuse the hash value stored in the node
            float bvalue = _b->value<float>(anode->idx,&anode->hashval);
            ccorr += avalue*bvalue;
        }
        return ccorr;
    }
    

Applying look-up tables to modify   image appearance


 look-up table is a  simple mapping function, to modify the pixel values of an image.

其实就是一个Array, 定义了all pixel value will map to what new value. ie. for 2 D image. we deine a

Mat (256*256),each element represent a pixel, ie (50,100)=(new value),means color channel 0,1 at value(50,100), will change to new value. 显然each pixel's position 没考虑,just focus on the pixel value itself.


A look-up table is a simple one-to-one (or many-to-one) function that defines how pixel values
are transformed into new values.




// Create an image inversion table

int dim(256);
cv::Mat lut(1, // 1 dimension
&dim, // 256 entries
CV_8U); // uchar
for (int i=0; i<256; i++) {
lut.at<uchar>(i)= 255-i;
}


  Mat result;
       cv::LUT(image,lut,result);
  cout<<result<<endl;


(50,100,150,)12 , all the 50 100 150 change to[ 205 155 105 ] ,虽然只是定义了一个1 dimesional 的mapping table,

but all the channel on the image will apply on the LUT


[205, 155, 105, 205, 155, 105, 205, 155, 105, 205, 155, 105;
  205, 155, 105, 205, 155, 105, 205, 155, 105, 205, 155, 105;
  205, 155, 105, 205, 155, 105, 205, 155, 105, 205, 155, 105]



You can also define a look-up table that tries to improve an image's contrast.

For example, if  you observe the original histogram of the previous image shown in the first recipe, it is easy
to notice that the full range of possible intensity values is not used (in particular, for this
image, the brighter intensity values are not used in the image).
One can therefore stretch the
histogram in order to produce an image with an expanded contrast.


The procedure is designed  to detect the lowest (imin) and the highest (imax) intensity value with non-zero count in the   image histogram.(找到最小于最大像素 (数量)) The intensity values can then be remapped such that the imin value is   repositioned at intensity 0, and the imax is assigned value 255. The in-between intensities i
are simply linearly remapped as follows:
255.0*(i-imin)/(imax-imin)+0.5);


cv::Mat stretch(const cv::Mat &image, int minValue=0) {
// Compute histogram first
cv::MatND hist= getHistogram(image);
// find left extremity of the histogram
int imin= 0;
for( ; imin < histSize[0]; imin++ ) {
std::cout<<hist.at<float>(imin)<<std::endl;
if (hist.at<float>(imin) > minValue)
break;

}
// find right extremity of the histogram
int imax= histSize[0]-1;
for( ; imax >= 0; imax-- ) {
if (hist.at<float>(imax) > minValue)
break;
}
// Create lookup table
int dim(256);
cv::Mat lookup(1, // 1 dimension
&dim, // 256 entries
CV_8U); // uchar
// Build lookup table
for (int i=0; i<256; i++) {
// stretch between imin and imax
if (i < imin) lookup.at<uchar>(i)= 0;
else if (i > imax) lookup.at<uchar>(i)= 255;
// linear mapping
else lookup.at<uchar>(i)= static_cast<uchar>(
255.0*(i-imin)/(imax-imin)+0.5);
}
// Apply lookup table
cv::Mat result;
result= applyLookUp(image,lookup);
return result;
}


他的算法思想其实是这样, 在histogram image 上给定一个intensity value ie=100, then y=100  f(x1)=100. f(x2)=100

那么在[x1  x2] region curve, 进行线性拉伸到[0-255]



// ignore starting and ending bins with less than 100 pixels
cv::Mat streteched= h.stretch(image,100);// 



Equalizing the image histogram

In  fact, one can think that a good-quality image should make equal use of all available pixel
intensities. This is the idea behind the concept of histogram equalization, that is making the
image histogram as flat as possible
.


equalizeHist

Equalizes the histogram of a grayscale image.

C++: void equalizeHist(InputArray src, OutputArray dst)
C: void cvEqualizeHist(const CvArr* src, CvArr* dst)
    Parameters:    

        src – Source 8-bit single channel image.
        dst – Destination image of the same size and type as src .

The function equalizes the histogram of the input image using the following algorithm:

    Calculate the histogram H for src .

    Normalize the histogram so that the sum of histogram bins is 255.

    Compute the integral of the histogram:

    H'_i = \sum _{0 \le j < i} H(j)

    Transform the image using H' as a look-up table: \texttt{dst}(x,y) = H'(\texttt{src}(x,y))

The algorithm normalizes the brightness and increases the contrast of the image.













GRAY2BGR 时候,所有的BGR channel will just apply same gray level value

Source image [50 100 150 ]

===========convert to Gray level
[109, 109, 109, 109;
  109, 109, 109, 109;
  109, 109, 109, 109]
=========== change back to RGB
[109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109; 
  109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109;
  109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109]











       
 














1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
应用背景为变电站电力巡检,基于YOLO v4算法模型对常见电力巡检目标进行检测,并充分利用Ascend310提供的DVPP等硬件支持能力来完成流媒体的传输、处理等任务,并对系统性能做出一定的优化。.zip深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值