OpenCV 学习笔记(颜色直方图计算 calcHist)

article/2025/9/28 12:22:21

OpenCV 学习笔记(颜色直方图计算 calcHist)

最近在看一本OpenCV 的书,书名是 《OpenCV 3 Computer Vision Application Programming Cookbook (third edition)》,里面给了很多很实用的代码片段。最近这几篇学习笔记都是从这个书里摘出的代码。有些代码我又做了些小的修改。

直方图计算是个很常见的需求,OpenCV 当然也提供了相应的函数。不过OpenCV 里的函数搞的有点复杂。函数原型如下:

void calcHist( InputArrayOfArrays images,const std::vector<int>& channels,InputArray mask, OutputArray hist,const std::vector<int>& histSize,const std::vector<float>& ranges,bool accumulate = false );

这个 calcHist 可以同时计算许多个图像的直方图,也支持多个通道图像。通常我们用不到这么复杂的功能。所以可以再进一步封装一下。下面是封装后的代码:

#ifndef HISTOGRAM_H
#define HISTOGRAM_H#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>class Histogram1D
{
public:Histogram1D(){// Prepare arguments for 1D histogramhistSize[0] = 256;hranges[0] = 0.0;hranges[1] = 256.0;ranges[0] = hranges;channels[0] = 0; // by default, we look at channel 0}~Histogram1D();// Computes the 1D histogram and returns an image of it.cv::Mat getHistogramImage(const cv::Mat &image);// Computes the 1D histogram.cv::MatND getHistogram(const cv::Mat &image);/*** @brief stretch 拉伸图像的灰度直方图以增强图像的对比度* @param image 输入图像,必须是8 bits 灰度图像* @param percent 直方图两侧各舍弃百分之 percent 的点,将剩下的拉伸到 0 - 255* @return 返回一个新的图像*/cv::Mat stretch(const cv::Mat &image, double percent);cv::Mat stretch(const cv::Mat &image, double percent1, double percent2);//直方图正规化,将图像图像最亮的地方线性拉伸到 255,最暗的地方线性拉伸到 0cv::Mat normalize(const cv::Mat &image);
private:int histSize[1]; // number of binsfloat hranges[2]; // min and max pixel valueconst float* ranges[1];int channels[1]; // only 1 channel used here};class ColorHistogram
{
public:ColorHistogram(){// Prepare arguments for a color histogramhistSize[0] = histSize[1] = histSize[2] = 256;hranges[0] = 0.0; // BRG rangehranges[1] = 256.0;ranges[0] = hranges; // all channels have the same rangeranges[1] = hranges;ranges[2] = hranges;channels[0] = 0; // the three channelschannels[1] = 1;channels[2] = 2;}cv::MatND getHistogram(const cv::Mat &image) ;cv::SparseMat getSparseHistogram(const cv::Mat &image) ;
private:int histSize[3];float hranges[2];const float* ranges[3];int channels[3];
};#endif // HISTOGRAM_H
#include "histogram.h"
#include <QDebug>
#include <random>Histogram1D::~Histogram1D()
{}// Computes the 1D histogram.
cv::MatND Histogram1D::getHistogram(const cv::Mat &image)
{cv::MatND hist;// Compute histogramcv::calcHist(&image,1, // histogram from 1 image onlychannels, // the channel usedcv::Mat(), // no mask is usedhist, // the resulting histogram1, // it is a 1D histogramhistSize, // number of binsranges // pixel value range);return hist;
}cv::Mat Histogram1D::stretch(const cv::Mat &image, double percent)
{return stretch(image, percent, percent);
}cv::Mat Histogram1D::stretch(const cv::Mat &image, double percent1, double percent2)
{cv::MatND hist = getHistogram(image);int imin, imax;if(percent1 < 0.0) percent1 = 0.0;if(percent1 > 1.0) percent1 = 1.0;percent1 = image.rows * image.cols * percent1;double value = 0;for(imin = 0; imin < histSize[0]; imin++){value += hist.at<float>(imin);if(value > percent1) break;}value = 0;if(percent2 < 0.0) percent2 = 0.0;if(percent2 > 1.0) percent2 = 1.0;percent2 = image.rows * image.cols * percent2;for(imax = histSize[0] - 1; imax >= 0; imax--){value += hist.at<float>(imax);if(value > percent2) break;}//int dim = 256;cv::Mat lookup(1, 256, 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{double v = 255.0 * (i - imin) / (imax - imin);lookup.at<uchar>(i) = static_cast<uchar>(v);}}cv::Mat ret;cv::LUT(image, lookup, ret);return ret;
}cv::Mat Histogram1D::normalize(const cv::Mat &image)
{// Compute histogram firstcv::MatND hist = getHistogram(image);int imin, imax;for(imin = 0; imin < histSize[0]; imin++){if(hist.at<float>(imin) > 0) break;}for(imax = histSize[0] - 1; imax >= 0; imax--){if(hist.at<float>(imax) > 0) break;}cv::Mat lookup(1, 256, 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{int v = 255 * (i - imin) / (imax - imin);lookup.at<uchar>(i) = static_cast<uchar>(v);}}cv::Mat ret;cv::LUT(image, lookup, ret);return ret;
}// Computes the 1D histogram and returns an image of it.
cv::Mat Histogram1D::getHistogramImage(const cv::Mat &image)
{// Compute histogram firstcv::MatND hist = getHistogram(image);// Get min and max bin valuesdouble maxVal = 0;double minVal = 0;cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);// Image on which to display histogramcv::Mat histImg(histSize[0], histSize[0], CV_8U, cv::Scalar(255));// set highest point at 90% of nbinsint hpt = static_cast<int>(0.9 * histSize[0]);// Draw a vertical line for each binfor( int h = 0; h < histSize[0]; h++ ){float binVal = hist.at<float>(h);int intensity = static_cast<int>(binVal * hpt / maxVal);// This function draws a line between 2 pointscv::line(histImg, cv::Point(h, histSize[0]),cv::Point(h,histSize[0]-intensity), cv::Scalar::all(0));}return histImg;
}cv::MatND ColorHistogram::getHistogram(const cv::Mat &image)
{cv::MatND hist;// Compute histogramcv::calcHist(&image,1, // histogram of 1 image onlychannels, // the channel usedcv::Mat(), // no mask is usedhist, // the resulting histogram3, // it is a 3D histogramhistSize, // number of binsranges // pixel value range);return hist;
}cv::SparseMat ColorHistogram::getSparseHistogram(const cv::Mat &image)
{cv::SparseMat hist(3,histSize,CV_32F);// Compute histogramcv::calcHist(&image,1, // histogram of 1 image onlychannels, // the channel usedcv::Mat(), // no mask is usedhist, // the resulting histogram3, // it is a 3D histogramhistSize, // number of binsranges // pixel value range);return hist;
}

下面给个简单的例子:

    cv::Mat image = cv::imread("D:\\向日葵.jpg");cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);cv::imshow("origin", image);Histogram1D hist;cv::Mat h = hist.getHistogramImage(image);cv::Mat his1 = hist.getHistogram(image);cv::imshow("hist", h);image = hist.stretch(image, 0, 0.150);cv::imshow("2", image);cv::Mat h2 = hist.getHistogramImage(image);cv::Mat his2 = hist.getHistogram(image);cv::imshow("hist2", h2);

这个例子很简单,加载一幅图像,先变成灰度图,然后计算直方图。再对图像的直方图拉伸一下,之后在重新计算直方图。输出结果如下图:
在这里插入图片描述

上面的例子是针对灰度图像的,对于彩色图像要用 ColorHistogram 这个类。彩色图像通常具有的颜色非常多,直接计算得到的结果会非常大。通常我们要先对颜色进行缩减操作。这个缩减操作可以用下面这个函数:

void colorReduceIO(const cv::Mat &image, // input imagecv::Mat &result,      // output imageint div)
{int nl = image.rows; // number of linesint nc = image.cols; // number of columnsint nchannels = image.channels(); // number of channels// allocate output image if necessaryresult.create(image.rows, image.cols, image.type());for (int j = 0; j < nl; j++){// get the addresses of input and output row jconst uchar* data_in = image.ptr<uchar>(j);uchar* data_out = result.ptr<uchar>(j);for (int i = 0; i < nc * nchannels; i++){// process each pixel ---------------------data_out[i] = data_in[i] / div*div + div / 2;// end of pixel processing ----------------} // end of line}
}

通常我们把图像数据最低2位去掉是不影响显示效果的。去掉最低的 4 位也不影响大多数的后续处理。下面给个简单的例子:

    cv::Mat image = cv::imread("D:\\向日葵.jpg");cv::pyrDown(image, image);cv::Mat image4, image16, image8;colorReduceIO(image, image4, 4);colorReduceIO(image, image8, 8);colorReduceIO(image, image16, 16);cv::imshow("origin", image); cv::imshow("image4", image4);cv::imshow("image16", image16);cv::imshow("image8", image8);

结果如下图:
在这里插入图片描述所以缩减一下颜色数量再做颜色直方图会减少大量内存消耗。对后续其他的处理也有帮助。


http://chatgpt.dhexx.cn/article/pnVKK6xG.shtml

相关文章

Opencv绘制HSV颜色直方图

一. 使用Opencv绘制HSV颜色直方图 所用的函数 cvCvtColor 可在&#xff1a; 使用Opencv将RGB颜色空间转换到HSV颜色空间/灰度图 文章中查找相关介绍 所使用的结构体&#xff1a; CvHistogram 以及函数&#xff1a; cvCalcHist CvCreateHist cvGetMinMaxHistValue cv…

基于颜色直方图优化的图像增强方法

最近改图像颜色迁移的论文&#xff0c;审稿人要求补充基于直方图优化的方法细节。趁此机会&#xff0c;我重新下载了相关文献&#xff0c;决定重新学习下该类方法&#xff0c;并把一些细节记录在本篇博客中&#xff0c;供交流学习。 目录 1. 前言 2. 背景知识 3. 颜色变换 4. 颜…

[OpenCV实战]52 在OpenCV中使用颜色直方图

颜色直方图是一种常见的图像特征&#xff0c;顾名思义颜色直方图就是用来反映图像颜色组成分布的直方图。颜色直方图的横轴表示像素值或像素值范围&#xff0c;纵轴表示该像素值范围内像素点的个数或出现频率。颜色直方图属于计算机视觉中的基础概念&#xff0c;其常常被应用于…

关于颜色直方图

一、颜色距 转自&#xff1a;https://blog.csdn.net/jaych/article/details/51137341 1、颜色距离 颜色距离指的是两个颜色之间的差距&#xff0c;通常距离越大&#xff0c;两个颜色相差越大&#xff0c;反之&#xff0c;两个颜色越相近。在计算颜色距离时&#xff0c;有类似…

图像特征分析---颜色特征描述---颜色距和颜色直方图

一、颜色距 转自&#xff1a;https://blog.csdn.net/jaych/article/details/51137341 1、颜色距离颜色距离指的是两个颜色之间的差距&#xff0c;通常距离越大&#xff0c;两个颜色相差越大&#xff0c;反之&#xff0c;两个颜色越相近。在计算颜色距离时&#xff0c;有类似计算…

颜色特征提取(一)——颜色直方图(opencv实现)

直方图——再讲颜色直方图之前&#xff0c;先简单介绍一下直方图。 直方图作为一种简单有效的基于统计特性的特征描述子&#xff0c;在计算机视觉领域广泛使用。它的优点主要体现在两个方面:一是对于任意一个图像区域&#xff0c;直方图特征的提取简单方便;其二&#xff0c;直…

一般颜色直方图

颜色直方图是一种用于图像处理和分析的图表&#xff0c;它可以显示图像中不同颜色的数量。通常&#xff0c;颜色直方图会将颜色分成几个色调区间&#xff0c;每个区间对应一个条形图&#xff0c;其中条形图的高度表示该色调区间中的像素数量。通过颜色直方图&#xff0c;你可以…

网络爬虫Jsoup

简介 网络爬虫&#xff08;又称为网页蜘蛛&#xff0c;网络机器人&#xff0c;在FOAF社区中间&#xff0c;更经常的称为网页追逐者&#xff09;&#xff0c;是一种按照一定的规则&#xff0c;自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、…

【Java】Jsoup爬虫快速入门案例

1、前言 该技术博客是根据B站狂神说Java教程的笔记总结&#xff0c;希望能为大家带来帮助&#xff01; 2、Jsoup实战案例 爬虫可以理解为爬取数据&#xff0c;所谓爬取数据就是&#xff1a; 获取请求返回的页面信息&#xff0c;筛选出我们想要的数据 如果想要爬取数据&#…

android爬虫框架jsoup,Android笔记之JSoup爬虫入门

前言 闲扯一些没用的&#xff0c;写这篇文章之前是有点私心的&#xff0c;因为之前评论某简书大v的文章是鸡汤&#xff0c;瞬间被拉黑&#xff0c;连个解释和说明的机会都没有&#xff0c;文章语言干涩&#xff0c;内容平平&#xff0c;于是就好奇到底是些什么样的人喜欢和吹捧…

Java的Jsoup爬虫

Java的Jsoup爬虫&#xff0c;爬携程酒店评分&#xff0c;保存数据库中 前言一、Jsoup爬虫pom二、逻辑代码部分1.首先我们要先确定爬取的东西&#xff0c;这边我就以携程的酒店评分为例子。2.Jsoup进行解析具体要求爬的内容3.接下来我们就是将爬取的数据存入数据库中 总结 前言 …

使用Jsoup爬虫爬取相关图片

一、Jsoup概述 jsoup 是一款Java 的HTML解析器&#xff0c;可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API&#xff0c;可通过DOM&#xff0c;CSS以及类似于jQuery的操作方法来取出和操作数据。 主要功能&#xff1a; 1. 从一个URL&#xff0c;文件或字符串…

jsoup爬虫实战详解之新浪

** jsoup爬虫实战详解之新浪 ** 今天分享一个之前困扰了一段时间的关于jsoup爬取新浪网页信息的踩坑总结。 在实现以上功能的之前我门首先要了解两个重点&#xff1a;1.关于jsoup的爬取细节以及教程&#xff0c;爬取时所要了解jsoup的相关标签&#xff1a;具体的自己大家感兴…

Java JSOUP爬虫学习分享

昨天从狂神大佬那学习了如何用jsoup爬去网站数据&#xff0c;现在整理了一下给大家分享一下。 先创建一个名叫JsoupPojo的实体类用来装入数据。 Data public class JsoupPojo {private String src;private String name; } 下面是将用来爬取的方法封装成了一个工具类 Compon…

java jsoup爬虫

前言&#xff1a;在日常开发中&#xff0c;我们必定是与我们的数据源打交道&#xff0c;我们的数据源无非就那么几个 1.数据库2.爬虫数据 3.第三方系统交互&#xff0c;这里介绍java 中网页版的爬虫jsoup的使用 1.首先导入我们的jar包 maven坐标如下 org.jsoup jsoup 1.13.1 c…

Jsoup爬虫并解析网页

Jsoup爬虫并解析网页 京东搜索 java&#xff0c;爬取有关java的商品信息 1、获取请求 String url"https://search.jd.com/Search?keywordjava";2、解析网页。&#xff08;Jsoup返回的Document对象就是浏览器的Document对象&#xff09; 所有js中操作Document对象的…

Jsoup爬虫入门实战

一、Jsoup介绍 jsoup 是一款基于 Java 的HTML解析器&#xff0c;它提供了一套非常省力的API&#xff0c;不但能直接解析某个URL地址、HTML文本内容&#xff0c;而且还能通过类似于DOM、CSS或者jQuery的方法来操作数据&#xff0c;所以 jsoup 也可以被当做爬虫工具使用。 相关…

Jsoup爬虫实例

一、简介 jsoup 是一款Java 的HTML解析器&#xff0c;可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API&#xff0c;可通过DOM&#xff0c;CSS以及类似于jQuery的操作方法来取出和操作数据。&#xff08;来源百度&#xff09; 二、准备 首先你需要找到一个你…

使用Jsoup实现网络爬虫

一、什么是Jsoup&#xff1f; jsoup是一款Java的HTML解析器、可以通过URL获取DOM元素并解析&#xff0c;也可对HTML文本内容进行解析&#xff0c;jsoup提供了一套非常简单的方法&#xff0c;类似于CSS、JQuery的操作方法对元素或者是数据进行操作。 二、Jsoup的特点及作用 从…

Java学习笔记:爬虫-用Jsoup解析网页

什么是爬虫 1、爬虫&#xff1a;程序代替人的人工操作&#xff0c;自动获取网页内容&#xff0c;并且从其中提取出来有价值信息。 2、原始&#xff1a;调用Http的类向服务器发出请求&#xff0c;获得HTML&#xff0c;然后用正则表达式等去分析。缺点&#xff1a;难度高。 3、…