OpenCV(十八):图像直方图

news2024/11/17 21:35:56

目录

1.直方图统计

2.直方图均衡化

3.直方图匹配


1.直方图统计

       直方图统计是一种用于分析图像或数据的统计方法,它通过统计每个数值或像素值的频率分布来了解数据的分布情况。

在OpenCV中,可以使用函数cv::calcHist()来计算图像的直方图。

calcHist() 函数的原型如下:

void calcHist(const Mat* images, int nimages, const int* channels,

InputArray mask, OutputArray hist, int dims,

const int* histSize, const float** ranges,

bool uniform = true, bool accumulate = false);

参数说明:

  • images: 输入图像数组,可以是单张图像或多张图像的数组。

  • nimages: 输入图像的数量。

  • channels: 要计算直方图的通道索引数组。例如,对于灰度图像,只有一个通道,因此 channels 设置为 {0};而对于彩色图像,可以指定 {0, 1, 2} 对应于 B、G、R 三个通道。

  • mask: 掩码图像,用于指定计算直方图的区域。如果不需要使用掩码,可以传入空的 Mat()。

  • hist: 输出的直方图,用于存储计算结果。

  • dims: 直方图的维度,通常为 1。

  • histSize: 直方图的大小,即每个维度的条目数量。

  • ranges: 直方图的范围,可以使用 {0, 256} 表示像素值范围为 [0, 256)。

  • uniform: 指示直方图条目是否均匀分布,默认为 true。

  • accumulate: 指示是否累积直方图,默认为 false。

下面是一个示例代码,展示如何使用cv::calcHist()函数计算图像的直方图:

#include <opencv2/opencv.hpp>
void hist(Mat image){
// 定义直方图参数
int histSize = 256; // 直方图条目数量
const int channels[1]={0};//通道索引
float range[] = { 0, 256 }; // 像素值范围
const float* histRange = { range };
bool uniform = true; // 直方图条目是否均匀分布
bool accumulate = false; // 直方图是否累积
// 计算直方图
cv::Mat hist;
cv::calcHist(&image, 1, channels, cv::Mat(), hist, 1, &histSize, &histRange, uniform, accumulate);

// 绘制直方图
int histWidth = 512;
int histHeight = 400;
int binWidth = cvRound((double)histWidth / histSize);
cv::Mat histImage(histHeight, histWidth, CV_8UC4, cv::Scalar(0, 0, 0));
cv::normalize(hist, hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());
for (int i = 1; i < histSize; ++i){
cv::line(histImage, cv::Point(binWidth * (i - 1), histHeight - cvRound(hist.at<float>(i - 1))),
cv::Point(binWidth * (i), histHeight - cvRound(hist.at<float>(i))),
cv::Scalar(255, 255, 255), 2, 8, 0);
}
// 显示直方图
cv::imwrite("/sdcard/DCIM/histImage.jpg", histImage);
}

示例代码中将原图像image转换为单通道灰度图像。然后定义了直方图的参数,包括直方图条目数量、像素值范围、均匀性和累积性。接下来使用 cv::calcHist() 函数计算了图像的直方图,存储在 hist 中。最后,通过绘制直方图数据到 histImage 中,实现了直方图的可视化。

2.直方图均衡化

        直方图均衡化是一种用于增强图像对比度的图像处理技术。它通过重新分布图像像素值的频率分布来增强图像的亮度和细节。

在OpenCV中,可以使用cv::equalizeHist()函数来进行直方图均衡化。该函数的原型如下:

void equalizeHist(InputArray src, OutputArray dst);

参数说明:

  • src:需要直方图均衡化的CV 8UC1图像。

  • dst: 直方图均衡化后的输出图像,与src具有相同尺寸和数据类型

下面是一个示例代码,展示如何使用cv::equalizeHist()函数来进行直方图均衡化:

#include <opencv2/opencv.hpp>
void drawHist(Mat &hist,string name){//归一化并绘制直方图函数
    int histSize = 256;  // 直方图条目数量
    // 绘制直方图
    int histWidth = 512;
    int histHeight = 400;
    int binWidth = cvRound((double)histWidth / histSize);
    cv::Mat histImage(histHeight, histWidth, CV_8UC4, cv::Scalar(0, 0, 0));
    cv::normalize(hist, hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());

    for (int i = 1; i < histSize; ++i)
    {
        cv::line(histImage, cv::Point(binWidth * (i - 1), histHeight - cvRound(hist.at<float>(i - 1))),
                 cv::Point(binWidth * (i), histHeight - cvRound(hist.at<float>(i))),
                 cv::Scalar(255, 255, 255), 2, 8, 0);
    }
    // 显示直方图
    cv::imwrite("/sdcard/DCIM/"+name+".jpg", histImage);

}
void EqualImage(Mat image){
    //灰度化
    Mat gray;
    cvtColor(image,gray,COLOR_BGR2GRAY);
    //将灰度图进行直方图均衡化
    Mat equalImg;
    equalizeHist(gray,equalImg);
    cv::imwrite("/sdcard/DCIM/equalImg.jpg", equalImg);
    // 定义直方图参数
    int histSize = 256;  // 直方图条目数量
    const int channels[1]={0};//通道索引
    float range[] = { 0, 256 };  // 像素值范围
    const float* histRange = { range };
    bool uniform = true;  // 直方图条目是否均匀分布
    bool accumulate = false;  // 直方图是否累积

    // 计算直方图
    cv::Mat hist;
    cv::calcHist(&equalImg, 1, channels, cv::Mat(), hist, 1, &histSize, &histRange, uniform, accumulate);

    drawHist(hist,"hist1");

}

示例代码中将原图像image转换为单通道灰度图像,然后将灰度图进行直方图均衡化,之后定义了直方图的参数,包括直方图条目数量、像素值范围、均匀性和累积性。接下来使用 cv::calcHist() 函数计算了图像的直方图,存储在 hist 中。最后,通过绘制直方图数据到 histImage 中,实现了直方图的可视化。

3.直方图匹配

       直方图匹配(Histogram Matching)是一种图像处理技术,用于将一副图像的直方图映射到另一副图像上,从而使它们的亮度分布或颜色分布相似。该技术常用于图像增强、风格转换、颜色校正等应用中。

以下是一个使用OpenCV实现直方图匹配的示例代码:


#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

void drawHist(Mat &hist,string name){//归一化并绘制直方图函数
    int histSize = 256;  // 直方图条目数量
    // 绘制直方图
    int histWidth = 512;
    int histHeight = 400;
    int binWidth = cvRound((double)histWidth / histSize);
    cv::Mat histImage(histHeight, histWidth, CV_8UC4, cv::Scalar(0, 0, 0));
    cv::normalize(hist, hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());

    for (int i = 1; i < histSize; ++i)
    {
        cv::line(histImage, cv::Point(binWidth * (i - 1), histHeight - cvRound(hist.at<float>(i - 1))),
                 cv::Point(binWidth * (i), histHeight - cvRound(hist.at<float>(i))),
                 cv::Scalar(255, 255, 255), 2, 8, 0);
    }
    // 显示直方图
    cv::imwrite("/sdcard/DCIM/"+name+".jpg", histImage);

}
void  Histogram_matching(Mat img1,Mat img2){
    Mat hist1,hist2;
    //计算两张图像直方图
    const int channels[1]={0};
    float inRanges[2]={0,255};
    const float *ranges[1]={inRanges};
    const int bins[1]={256};
    calcHist(&img1,1,channels,Mat(),hist1,1,bins,ranges);
    calcHist(&img2,1,channels,Mat(),hist2,1,bins,ranges);
    //归一化两张图像的直方图
    drawHist(hist1,"hist1");
    drawHist(hist2,"hist2");
    //计算两张图像直方图的累计概率
    float hist1_cdf[256]={hist1.at<float>(0)};
    float hist2_cdf[256]={hist2.at<float>(0)};
    for(int i=1;i<256;i++){
        hist1_cdf[i]=hist1_cdf[i-1]+hist1.at<float>(i);
        hist2_cdf[i]=hist2_cdf[i-1]+hist1.at<float>(i);
    }
    //构建累积概率误差矩阵
    float diff_cdf[256][256];
    for(int i=0; i<256; i++){
        for(int j=0; j<256; j++){
            diff_cdf[i][j] = fabs(hist1_cdf[i] - hist2_cdf[j]);
        }
    }
    uchar lutone[256];
    for(int i=0;i<256;i++){
        //查找源灰度级为i的映射灰度
        //和i的累积概率差值最小的规定化灰度
        float min=diff_cdf[i][0];
        int index=0;
        //寻找累积概率误差矩阵中每一行中的最小值
        for(int j=1;j<256;j++){
            if(min>diff_cdf[i][j]){
                min=diff_cdf[i][j];
                index=j;
            }
        }
        lutone[i]=index;
    }
    //生成LUT映射表
    Mat lut(1,256,CV_8UC1,lutone);
    Mat result,hist3;
    LUT(img1,lut,result);
    imwrite("/sdcard/DCIM/result.png",result);
    calcHist(&result,1,channels,Mat(),hist3,1,bins,ranges);
    drawHist(hist3,"hist3");

}

示例代码:计算原始图像和目标图像的直方图,归一化直方图,计算累计直方图,构建累积概率误差矩阵,根据最小差值构建映射表,最后将原始图像的灰度级根据映射表调整为目标图像的灰度级。下面是原始图像和直方图匹配后图片,可以看出直方图匹配后的图片使得图像中的细节更加清晰可见。

                  

              原图                                            直方图匹配的结果

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

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

相关文章

Docker使用数据卷挂载进行数据存储与共享

一、挂载和数据卷 在 Docker 中&#xff0c;挂载&#xff08;Mounting&#xff09;和数据卷&#xff08;Data Volumes&#xff09;是用于在容器和宿主机之间共享数据的机制。 挂载&#xff1a;将宿主机文件系统中的目录或文件与容器中的目录或文件进行关联的过程。数据卷&…

Linux系统--基础IO

文章目录 文件的概念 C语言 文件 IO 相关操作 系统调用接口 文件描述符 一、文件的概念 1.在系统角度上来说 文件内容属性 如果在磁盘上建立一个为0KB的文件&#xff0c;磁盘上也会存储文件的属性。(因为文件的属性也是数据). 文件的操作 1.一种是对于文件内容做操作。2.另…

Solidworks PDM二次开发---文件相关操作

本文介绍如何把文件增加到库&#xff0c;并检入。 上一篇文章简单的讲解了文件夹的创建等操作&#xff0c;这一次来讲文件相关操作&#xff0c;相对来说比较重要。界面 漂亮的界面&#xff0c;不接受反驳&#xff01; 代码 private void btnFile_Click(object sender, Even…

MASM32编程状态栏显示字符动画,按钮跑马灯

一、需求分析 由于sysInfo扫描的内容比较多&#xff0c;打算为它增加一点动画效果&#xff0c;提醒用户程序正在运行&#xff0c;耐心等待。 二、构建测试窗口 测试窗口上放置有一个按钮&#xff0c;按钮上的初始文字是“开始扫描”&#xff1b;并使用状态栏&#xff0c;状态…

喜报 | 再度中标南网项目!AR 开启电力远程运维新智慧

近日&#xff0c;中国南方电网官网发布《2023年南方电网数字平台科技 (广东)有限公司物资品控远程协助软件采购项目中标公告》&#xff0c;ALVA Systems 凭借 ALVA Rainbow 创新应用竞得此标。 随着相关技术的逐步成熟&#xff0c;基础问题远程化解决已经在工业领域广泛应用。 …

Python中的装饰器

迷途小书童的 Note 读完需要 5分钟 速读仅需 2 分钟 装饰器是一个非常有用而又常被误解的功能&#xff0c;可以让我们在不修改函数或类的源代码情况下给它们提供扩展功能。本文将通过具体示例带你深入理解 Python 装饰器的用法。 1 装饰器基础 装饰器本质上是一个函数&#xff…

SpringMVC的简介及工作流程

一.简介 Spring MVC是一个基于Java的开发框架&#xff0c;用于构建灵活且功能强大的Web应用程序。它是Spring Framework的一部分&#xff0c;提供了一种模型-视图-控制器&#xff08;Model-View-Controller&#xff0c;MVC&#xff09;的设计模式&#xff0c;用于组织和管理Web…

职责链设计模式

职责链模式又叫命令链、CoR、Chain of Command、Chain of Responsibility。 该模式允许你将请求沿着处理者链进行发送&#xff0c;使多个对象都可以处理请求&#xff0c;每个对象有权决定处理或传递给下个节点。 客户端&#xff1a;用来定义职责链条。 处理者&#xff1a;声明…

基于Vgg-Unet模型自动驾驶场景检测

1.VGG VGG全称是Visual Geometry Group属于牛津大学科学工程系&#xff0c;其发布了一些列以VGG开头的卷积网络模型&#xff0c;可以应用在人脸识别、图像分类等方面,VGG的输入被设置为大小为224x244的RGB图像。为训练集图像上的所有图像计算平均RGB值&#xff0c;然后将该图像…

vscode上搭建go开发环境

前言 Go语言介绍&#xff1a; Go语言适合用于开发各种类型的应用程序&#xff0c;包括网络应用、分布式系统、云计算、大数据处理等。由于Go语言具有高效的并发处理能力和内置的网络库&#xff0c;它特别适合构建高并发、高性能的服务器端应用。以下是一些常见的Go语言应用开发…

静态路由配置出错记录

根据实验手册&#xff0c;配置静态路由&#xff0c;但是怎么也排除不了错误。 最后发现&#xff0c;是自己的默认网关配置错误了。但是使用模拟器抓包看到的&#xff0c;也没有提示网关信息啊。

docker desktop如何一键进入容器内部

对着对应的容器 点击 view files

电压互感器倍频感应耐压试验注意事项

注意事项 被试 PT 在三倍频耐压时呈容性&#xff0c; 对于 110kV、 220kV 互感器进行感应耐压试验时&#xff0c;应在开口 a D x D 端子间励磁&#xff0c; 可在 PT 二次绕组 ax 上接补偿电感&#xff0c; 对于 35kV 电压互感器励磁电压一般加至二次 a—x 间&#xff1b;三倍频…

测开之 Python 自动化全栈工程师 + 性能专项

功能测试基础 接口测试基础 接口的通信原理与本质 cookie、session、token 详解 接口测试的意义与测试方法 接口测试用例的设计 app 测试 app 流程测试 app 兼容性测试 app 稳定性测试 app 性能专项测试 app 抓包 UI 功能测试基础 常见功能测试方法&#xff1a;等价类&…

JVM | 垃圾回收器(GC)- Java内存管理的守护者

引言 在编程世界中&#xff0c;有效的内存管理是至关重要的。这不仅确保了应用程序的稳定运行&#xff0c;还可以大大提高性能和响应速度。作为世界上最受欢迎的编程语言之一&#xff0c;通过Java虚拟机内部的垃圾回收器组件来自动管理内存&#xff0c;是成为之一的其中一项必…

极米RS Pro 3投影参数是多少?极米投影仪RS Pro 3好用吗?

近年来&#xff0c;随着投影技术的快速发展&#xff0c;越来越多的用户开始选择投影产品来打造家庭影院&#xff0c;为生活带来新的观影体验。但要想打造一个家庭影院&#xff0c;选到一台合适的投影仪却并不是一件容易的事&#xff0c;因为家庭影院对画面的亮度、色彩和观影舒…

(18)线程的实例认识:线程的控制,暂停,继续,停止,线程相互控制,协作

一、老方式 1、这是一个老的实现方式&#xff0c;基本不推荐&#xff0c;背后控制的原理需要了解。 界面&#xff1a;三个button一个textbox 代码&#xff1a; private volatile bool isPause false;//fprivate void BtnStart_Click(object…

力扣|两数相加

先放题目&#xff1a; 给你两个非空的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c…

敏捷开发方法:快速响应需求变化的开发流程

在快速变化的技术和市场环境下&#xff0c;传统的软件开发方法可能显得笨重和不灵活。敏捷开发方法应运而生&#xff0c;以其快速响应需求变化、持续交付和团队协作的特点&#xff0c;成为现代软件开发的重要方法之一。本文将深入探讨敏捷开发方法的概念、原则、流程以及在实际…

《王道24数据结构》课后应用题——第三章 栈和队列

第三章 【3.1】 03、 假设以I和O分别表示入栈和出操作。栈的初态和终态均为空&#xff0c;入栈和出栈的操作序列可表示为仅由I和O组成的序列&#xff0c;可以操作的序列称为合法序列&#xff0c;否则称为非法序列。 如IOIIOIOO 和IIIOOIOO是合法的&#xff0c;而IOOIOIIO和II…