C#描述-计算机视觉OpenCV(5):直方图算法

news2025/4/4 5:46:37

C#描述-计算机视觉OpenCV(5):直方图算法

    • 前文链接
    • 图像直方图
    • 灰度直方图的计算
    • 灰度直方图的绘制
    • BGR三通道的直方图
    • 直方图的均衡化算法
    • 相似图像检测

前文链接

文中没提到的东西,很可能都在前文描述过
C#描述-计算机视觉OpenCV(1):基础操作
C#描述-计算机视觉OpenCV(2):图像处理
C#描述-计算机视觉OpenCV(3):重映射
C#描述-计算机视觉OpenCV(4):图像分割

图像直方图

图像由各种数值的像素构成。例如在单通道灰度图像中,每个像素都有一个 0(黑色)~255(白色)的整数。对于每个灰度,都有不同数量的像素分布在图像内,具体取决于图片内容。直方图是一个简单的表格,表示一幅图像(有时是一组图像)中具有某个值的像素的数量。
因此,灰度图像的直方图有 256 个项目,也叫箱子(bin)。0 号箱子提供值为 0 的像素的数量,1 号箱子提供值为 1 的像素的数量,以此类推。很明显,如果把直方图的所有箱子进行累加,得到的结果就是像素的总数。你也可以把直方图归一化,即所有箱子的累加和等于 1。这时,每个箱子的数值表示对应的像素数量占总数的百分比。
直方图或者说对色彩的统计,是很多算法的基础。本文将以此图为例,来生成在直方图:
在这里插入图片描述

灰度直方图的计算

首先,我们要把原图通过CvtColor函数转换为一个灰度图像:
在这里插入图片描述
然后我们拿着这张图,代入CalcHist函数。
这个直方图生成函数的参数为:
int histSize[1]; // 直方图中箱子的数量
float hranges[2]; // 值范围
const float* ranges[1]; // 值范围的指针,C#中,我们直接使用rangef
int channels[1]; // 要检查的通道数量
以及一个转换为Mat[] 的Mat灰度图像,以及一个hist作为结果输出
对于这张图,由于是一个0-255的单通道灰度图像,hist是一个Mat一维数组,大小为256,值域根据原图像素,心里也可以有个估计,每个色块的总数大约占比多少,然后可以直接输出出来检视结果。

public void GetHistogram(Mat img)
        {
            Mat hist = new Mat();
            Mat grayImg = new Mat();
            
            Cv2.CvtColor(img, grayImg, ColorConversionCodes.BGR2GRAY);
            Mat[] vimg = new Mat[] { grayImg };
            int[] channels = new int[] { 0 };// 要检查的通道数量
            Rangef[] ranges = new Rangef[] { new Rangef(0, 256) };// 值范围与指针
            int[] histSize = new int[] { 256 };// 直方图中箱子的数量
            int dims = 1; //需要统计的特征数目(只统计灰度图单通道)
            Cv2.CalcHist(vimg, channels, new Mat(), hist, dims,histSize, ranges);
            Cv2.ImShow("grayImg", grayImg);
            for(int i=0;i<256;i++)
            {
                float h = hist.At<float>(i);
                textBox1.Text +="value "+Convert.ToString(i)+" : " +Convert.ToString(h) + "\r\n";//打印结果来检视下
            }
            GetImageOfHistogram(hist);//用计算结果去生成直方图
        }

到这一步,我们得到了统计数组,然后就开始写直方图绘制函数

灰度直方图的绘制

我们可以同时生成一个直方图和一个Winform自带的Chart函数来进行结果比对

public void GetImageOfHistogram(Mat hist)
        {
            for (int i = 0; i < 256; i++)
            {
                XList1.Add(i);
                YList1.Add(Convert.ToInt32(hist.At<float>(i)));
                chart1.Series["Hist"].Points.DataBindXY(XList1, YList1);
            }
            double maxVal = 0;
            double minVal = 0;
            Cv2.MinMaxLoc(hist, out minVal, out maxVal);
            int histSize = hist.Rows;
            Mat histImg = new Mat(histSize, histSize, MatType.CV_8UC1);
            int hpt = Convert.ToInt32(0.9 * histSize);
            for (int h = 0; h < histSize; h++)
            {
                float binVal = hist.At<float>(h);
                if (binVal > 0)
                {
                    int intensity = Convert.ToInt32(binVal * hpt / maxVal);
                    Cv2.Line(histImg, h, histSize, h, histSize - intensity, 255, 1);
                        }
            }
            Cv2.ImShow("histImg", histImg);
            }

结果:
在这里插入图片描述
大多数情况下,直方图是单个的单通道或三通道图像,但也可以在这个函数中指定一个分布在多幅图像(即多个 Mat)上的多通道图像。这也是把输入图像数组作为函数第一个参数的原因。参数 dims 指明了直方图的维数,例如 1 表示一维直方图。在分析多通道图像时,可以只把它的部分通道用于计算直方图,将需要处理的通道放在维数确定的数组 channel 中。
在这个类的实现中只有一个通道,默认为 0。直方图用每个维度上的箱子数量(即整数数组histSize)以及每个维度(由 ranges 数组提供,数组中每个元素又是一个二元素数组)上的最小值(含)和最大值(不含)来描述。

BGR三通道的直方图

针对彩色图像,我们通过修改函数参数,来执行三通道的统计:
histSize[0]= histSize[1]= histSize[2]= 256;
hranges[0]= 0.0; // BGR 范围为 0~256
hranges[1]= 256.0;
ranges[0]= hranges; // 这个类中
ranges[1]= hranges; // 所有通道的范围都相等
ranges[2]= hranges;
channels[0]= 0; // 三个通道:B
channels[1]= 1; // G
channels[2]= 2; // R
对于执行结果,由于三维直方图很难画,我们可以生成三个单独的通道直方图。

直方图的均衡化算法

很多时候,图像的视觉缺陷并不因为它使用的强度值范围太窄,而是因为部分强度值的使用频率远高于其他强度值。有时候图像中等灰度的强度值非常多,而较暗和较亮的像素值则非常稀少,而均衡对所有像素强度值的使用频率可以作为提高图像质量的一种手段。这正是直方图均衡化这一概念背后的思想,也就是让图像的直方图尽可能地平稳。
对于直方图的均衡化,我们可以运用自带函数:

Mat res = new Mat();
Cv2.EqualizeHist(grayImg, res);
Cv2.ImShow("res", res);

效果图:
在这里插入图片描述
经常P图的小伙伴能看出来,这种算法增强了图像的对比度,也增加了图像的清晰度与细节呈现。
直方图均衡化后的统计结果:
在这里插入图片描述

相似图像检测

基于内容的图像检索是计算机视觉的一个重要课题。它包括根据一个已有的基准图像,找出一批内容相似的图像。直方图是标识图像内容的一种有效方式,因此值得研究一下能否用它来解决基于内容的图像检索问题。
这里的关键是,要仅靠比较它们的直方图就测量出两幅图像的相似度。我们需要定义一个测量函数,来评估两个直方图之间的差异程度或相似程度。人们已经提出了很多测量方法,OpenCV中compareHist 函数的实现过程中使用了其中的一些方法,在C#中,该函数调用方法为:

CompareHist(InputArray h1, InputArray h2, HistCompMethods method);

写个Demo测试下

public void HistCompTest(Mat img1, Mat img2)
        {

            Mat hist1 = new Mat();
            Mat hist2 = new Mat();
            Mat grayImg1 = new Mat();
            Mat grayImg2 = new Mat();
            Cv2.CvtColor(img1, grayImg1, ColorConversionCodes.BGR2GRAY);
            Cv2.CvtColor(img2, grayImg2, ColorConversionCodes.BGR2GRAY);
            Mat[] vimg1 = new Mat[] { grayImg1 };
            Mat[] vimg2 = new Mat[] { grayImg2 };
            int[] channels = new int[] { 0 };
            Rangef[] ranges = new Rangef[] { new Rangef(0, 256) };
            int[] histSize = new int[] { 256 };
            int dims = 1;
            Cv2.CalcHist(vimg1, channels, new Mat(), hist1, dims, histSize, ranges);
            Cv2.CalcHist(vimg2, channels, new Mat(), hist2, dims, histSize, ranges);
            for (int i = 0; i < 256; i++)
            {
                XList1.Add(i);
                YList1.Add(Convert.ToInt32(hist1.At<float>(i)));
                chart1.Series["Green"].Points.DataBindXY(XList1, YList1);
            }
            for (int i = 0; i < 256; i++)
            {
                XList2.Add(i);
                YList2.Add(Convert.ToInt32(hist2.At<float>(i)));
                chart2.Series["Green"].Points.DataBindXY(XList2, YList2);
            }
            hist1.ConvertTo(hist1, MatType.CV_32FC1);
            hist2.ConvertTo(hist2, MatType.CV_32FC1);
            Cv2.Normalize(hist1, hist1, 0, 1, NormTypes.MinMax, -1, null);
            Cv2.Normalize(hist2, hist2, 0, 1, NormTypes.MinMax, -1, null);//将两张图片统一格式,避免报错
            double x;
            x = Cv2.CompareHist(hist1, hist2, HistCompMethods.Correl);
            textBox1.Text = Convert.ToString(x);
        }

在这里插入图片描述
输出的结果相似度越靠近1,也就越相似,越靠近0,差别越大。由于是直方图对比,所以图像的旋转并不会影响对比的结果。暂时这是一个很初级的算法测试,实际工程意义不大,所以不做更多测试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1905871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[AI 大模型] OpenAI ChatGPT

文章目录 ChatGPT 简介ChatGPT 的模型架构ChatGPT的发展历史节点爆发元年AI伦理和安全 ChatGPT 新技术1. 技术进步2. 应用领域3. 代码示例4. 对话示例 ChatGPT 简介 ChatGPT 是由 OpenAI 开发的一个大型语言模型&#xff0c;基于GPT-4架构。它能够理解和生成自然语言文本&…

CentOS7安装、CentOS7修改root密码

目录 1 下载镜像 2 使用VMware新建一个虚拟机 3 centos7修改root密码 1 下载镜像 开源镜像站-阿里云centos-7.9.2009-isos-x86_64安装包是阿里云官方提供的开源镜像免费下载服务,每天下载量过亿,阿里巴巴开源镜像站为包含centos-7.9.2009-isos-x86_64安装包的几百个操作系统…

移动校园(2):express构建服务器,小程序调用接口,展示数据

express做服务器框架&#xff0c;mssql连接数据库&#xff0c;uni-request调用接口 这是文件夹目录 然后是index.js内容 const expressrequire(express) const appexpress() const uniRouterrequire("./uniRouter") const config{user:sa,password:123456,server:l…

汉中茗茶小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;基础数据管理&#xff0c;茶叶管理&#xff0c;论坛管理&#xff0c;公告管理&#xff0c;茗茶历史管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;茗茶信息&#xf…

正则表达式 先行断言 \S {} 示例

目录 数据准备一. 先行断言1.1 正向先行断言1.2 负向先行断言 二. 配合 {} 和 \S 使用2.1 匹配一个任意非空白字符2.2 匹配任意多个非空白字符2.3 匹配3个非空白字符2.4 匹配至少3个非空白字符2.5 匹配0~3个非空白字符 数据准备 ⏹文件1 0561-10 AAA 123 dfg 345 sss 0561-2…

2008-2021年各省份高技术产业科研与发展(RD)活动情况数据

R&D&#xff08;研究与发展&#xff09;活动是推动国家和公司技术创新和经济增长的关键因素。以下是对各省份高技术产业科研与发展&#xff08;R&D&#xff09;活动情况数据的介绍&#xff1a; 数据简介 定义&#xff1a;R&D指在产品开发、工艺设计、生产技术改进…

阿尔泰科技与西安交通大学陕西省某技术重点实验室共谋未来!

近日&#xff0c;阿尔泰科技的电子工程师&#xff08;熊工&#xff09;应邀前往西安交通大学陕西省某技术重点实验室&#xff0c;参与课题组项目的测试与调试工作。此次合作不仅成功推动了项目的进展&#xff0c;还为未来的深入合作奠定了坚实基础。 阿尔泰科技作为领先的测控技…

Flink SQL kafka连接器

版本说明 Flink和kafka的版本号有一定的匹配关系&#xff0c;操作成功的版本&#xff1a; Flink1.17.1kafka_2.12-3.3.1 添加kafka连接器依赖 将flink-sql-connector-kafka-1.17.1.jar上传到flink的lib目录下 下载flink-sql-connector-kafka连接器jar包 https://mvnreposi…

AI教你如何系统的学习Python

Python学习计划 第一阶段&#xff1a;Python基础&#xff08;1-2个月&#xff09; 目标&#xff1a;掌握Python的基本语法、数据类型、控制结构、函数、模块和包等。 学习Python基本语法&#xff1a;包括变量、数据类型&#xff08;整数、浮点数、字符串、列表、元组、字典、…

Java求解百钱买百鸡问题(课堂实例2)

目录 &#x1f495;&#x1f495;引言&#x1f495;&#x1f495; &#x1f60d;&#x1f60d;点关注编程梦想家&#xff08;大学生版&#xff09;-CSDN博客不迷路&#x1f495;&#x1f495; 一、问题背景----百鸡百钱_百度百科 (baidu.com) &#x1d465;&#x1d466;&a…

颍川韩氏始祖,归顺大汉的弓高侯

弓高侯&#xff0c;听起来十分不顺当&#xff0c;像是域外来音似的。本人的名字更另类——颓当&#xff0c;词典中甚至找不到。然而&#xff0c;弓高曾经是河北的一个县名——弓高县&#xff0c;颓当曾经是匈奴的一个城——颓当城&#xff0c;这两个地名已经不存在了&#xff0…

python - 文件 / 永久存储:pickle / 异常处理

一.文件 利用help(open)可以看到open()函数的定义&#xff1a; >>> help(open) Help on built-in function open in module _io:open(file, moder, buffering-1, encodingNone, errorsNone, newlineNone, closefdTrue, openerNone) 默认打开模式是’rt’&#xff0…

spring boot(学习笔记第十二课)

spring boot(学习笔记第十二课) Spring Security内存认证&#xff0c;自定义认证表单 学习内容&#xff1a; Spring Security内存认证自定义认证表单 1. Spring Security内存认证 首先开始最简单的模式&#xff0c;内存认证。 加入spring security的依赖。<dependency>…

edge浏览器详细解析

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 Microsoft Edge ​​​​…

InvalidVersionSpecError: Invalid version spec: =2.7解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

C++ | Leetcode C++题解之第22题完全二叉树的节点个数

题目&#xff1a; 题解&#xff1a; class Solution { public:int countNodes(TreeNode* root) {if (root nullptr) {return 0;}int level 0;TreeNode* node root;while (node->left ! nullptr) {level;node node->left;}int low 1 << level, high (1 <&…

详解Java垃圾回收(GC)机制

一、为什么需要垃圾回收 如果不进行垃圾回收&#xff0c;内存迟早都会被消耗空&#xff0c;因为我们在不断的分配内存空间而不进行回收。除非内存无限大&#xff0c;我们可以任性的分配而不回收&#xff0c;但是事实并非如此。所以&#xff0c;垃圾回收是必须的。 二、哪些内…

计算机的错误计算(二十四)

摘要 计算机的错误计算&#xff08;二十一&#xff09;就案例 展示了“两个不相等数相减&#xff0c;差为0”。本节给出新的计算过程&#xff1a;不停增加计算精度直到出现非0结果。这个过程与结果表明&#xff0c;即使是专业数学软件&#xff0c;对这个问题的处理&#xff0…

JS进阶-作用域

学习目标&#xff1a; 掌握作用域 学习内容&#xff1a; 作用域局部作用域全局作用域作用域链JS垃圾回收机制拓展-JS垃圾回收机制-算法说明闭包变量提升 作用域&#xff1a; 作用域规定了变量能够被访问的"范围"&#xff0c;离开了这个"范围"变量便不能被…

论文1:多模态人类活动识别综述

论文题目&#xff1a;A Review of Multimodal Human Activity Recognition with Special Emphasis on Classification, Applications, Challenges and Future Directions 文献偏旧-2021 1、 专业词汇&#xff1a; Human activity recognition (HAR)-人类活动识别 Wearable …