Opencv计算机视觉编程攻略-第四节 图直方图统计像素

发布于:2025-04-01 ⋅ 阅读:(22) ⋅ 点赞:(0)

1.计算图像直方图

图像统计直方图的概念
图像统计直方图是一种用于描述图像中像素分布情况的工具。具体来说,灰度直方图是一个关于灰度级别的函数,它记录了图像中每种灰度级别对应的像素数量。这种分布反映了图像亮度的整体特性。

对于彩色图像(如RGB),可以通过将每个颜色通道分别映射到特定索引来构建其直方图,并利用核密度估计的方法来累积权重,从而得到更精确的颜色分布信息。

统计直方图主要基于opencv 的calcHist函数实现,其具体配置如下

		calcHist(&image, 
			1,			// histogram of 1 image only
			channels,	// the channel used
			Mat(),	// no mask is used
			hist,		// the resulting histogram
			1,			// it is a 1D histogram
			histSize,	// number of bins
			ranges		// pixel value range
		);

学习文中给出的手绘统计直方图,基于统计的频数,绘制线高 line

    // Create an image representing a histogram
    static Mat getImageOfHistogram(const Mat &hist, int zoom) {
        // Get min and max bin values
        double maxVal = 0;
        double minVal = 0;
        minMaxLoc(hist, &minVal, &maxVal, 0, 0);
        // get histogram size
        int histSize = hist.rows;
        // Square image on which to display histogram
        Mat histImg(histSize*zoom, histSize*zoom, CV_8U, Scalar(255));
        // set highest point at 90% of nbins (i.e. image height)
        int hpt = static_cast<int>(0.9*histSize);

        // Draw vertical line for each bin
        for (int h = 0; h < histSize; h++) {
            float binVal = hist.at<float>(h);
            if (binVal>0) {
                int intensity = static_cast<int>(binVal*hpt / maxVal);
                line(histImg, Point(h*zoom, histSize*zoom),
                    Point(h*zoom, (histSize - intensity)*zoom), Scalar(0), zoom);
            }
        }
        return histImg;
    }

在这里插入图片描述

2.基于查找表修改图像

所谓的查找表,相当于是一个数组,每个数组对应i值的原像素值映射为目标像素值
人工构建查找表

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

通过opencv的LUT函数一键映射查找表,进行取反操作

 Mat result;
 // apply lookup table
 LUT(image,lookup,result);

在这里插入图片描述
在这里插入图片描述

3.直方图均衡化

上文了解了统计直方图和查找表,基于直方图统计结果构建均衡化的查找表,从而全局修改图像整体颜色

equalizeHist(image,result); // 直接使用opencv函数实现均衡化

在这里插入图片描述
在这里插入图片描述
统计直方图的原理一般是值选择一定像素值范围,将该范围的像素映射的一个更大范围的像素值范围中,从而使得整体图像显得更均匀,手动实现代码如下:

    Mat stretch(const Mat &image, float percentile) {
        // number of pixels in percentile
        float number= image.total()*percentile;
        // Compute histogram first
        Mat hist = getHistogram(image);
        // find left extremity of the histogram
        int imin = 0;
        for (float count=0.0; imin < 256; imin++) {
            // number of pixel at imin and below must be > number
            if ((count+=hist.at<float>(imin)) >= number)
                break;
        }
        // find right extremity of the histogram
        int imax = 255;
        for (float count=0.0; imax >= 0; imax--) {
            // number of pixel at imax and below must be > number
            if ((count += hist.at<float>(imax)) >= number)
                break;
        }
        // Create lookup table
        int dims[1] = { 256 };
        Mat lookup(1, dims, CV_8U);
        for (int i = 0; i<256; i++) {
            if (i < imin) lookup.at<uchar>(i) = 0;
            else if (i > imax) lookup.at<uchar>(i) = 255;
            else lookup.at<uchar>(i) = cvRound(255.0*(i - imin) / (imax - imin));
        }
        // Apply lookup table
        Mat result;
        result = applyLookUp(image, lookup);
        return result;
    }

在这里插入图片描述

4.直方图反向投影进行内容查找

区域内图像的统计直方图某种程度表示了整体颜色分布特征,因而可以使用区域的统计直方图作为特征进行相似内容查找,以区域内白云的颜色为例进行统计
在这里插入图片描述
在这里插入图片描述

calcBackProject(&image,
                      1,            // we only use one image at a time
                      channels,     // vector specifying what histogram dimensions belong to what image channels
                      shistogram,   // the histogram we are using
                      result,       // the resulting back projection image
                      ranges,       // the range of values, for each dimension
                      255.0         // the scaling factor is chosen such that a histogram value of 1 maps to 255
		   );

在这里插入图片描述
在这里插入图片描述
在灰度图内进行统计分析,难以分割出较好的效果,使用rgb往往可以获得不错的效果,彩色图使用同一个函数
在这里插入图片描述

5.用均值平移法查找目标

在这里插入图片描述
以这个猩猩的脸部特征生成统计特征图

   // 颜色转为hsv 如上一节所说,hsv分辨皮肤更清晰
	cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
	// Get back-projection of hue histogram
	int ch[1]={0};
	finder.setThreshold(-1.0f); // no thresholding
	cv::Mat result= finder.find(hsv,0.0f,180.0f,ch);
	// 使用反向统计直方图获得图像上和目标区域的相似性概率图

	// search objet with mean shift 使用均值漂移算法在概率图中查找,最后在一张有偏移的图像上准确找到目标
	cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS,
		10,     // iterate max 10 times
		1);     // or until the change in centroid position is less than 1px

在这里插入图片描述

6.比较直方图搜索相似图像

在传统数字图像处理领域,使用统计直方图进行图像相似度对比,是常用的方法,简单高效

	double compare(const cv::Mat& image) {

		inputH= hist.getHistogram(image);
		// histogram comparison using intersection
		return cv::compareHist(refH,inputH, cv::HISTCMP_INTERSECT);
	}

在这里插入图片描述
waves vs dog: 26535
waves vs marais: 12149
waves vs bear: 18353
waves vs beach: 33032 相似度最高的图像
waves vs polar: 20768
waves vs moose: 15225
waves vs lake: 15486
waves vs fundy: 14309

在这里插入图片描述

7.用积分图统计图像

积分图统计图像,本质就是数组的前缀和算法,通过一次性求解前缀,后续每个位置的要素数量就可以直接查询得到,避免每次的查找,这个在区域内进行搜索直方图特征中有较好的应用,实际操作中,将颜色维度从256压缩到更小空间从而实现加速:

	double maxSimilarity=0.0;
	int xbest, ybest;
	// loop over a horizontal strip around girl location in initial image
	for (int y=110; y<120; y++) {
		for (int x=0; x<secondImage.cols-width; x++) {

			// compute histogram of 16 bins using integral image
			histogram= intHistogram(x,y,width,height);
			// compute distance with reference histogram
			double distance= cv::compareHist(refHistogram,histogram, cv::HISTCMP_INTERSECT);
			// find position of most similar histogram
			if (distance>maxSimilarity) {

				xbest= x;
				ybest= y;
				maxSimilarity= distance;
			}

			std::cout << "Distance(" << x << "," << y << ")=" << distance << std::endl;
		}
	}

在这里插入图片描述
如果看到这里,麻烦点一个赞再走,谢谢!相关代码同样上传代码库链接: 点击下载