目标
在本教程中,您将学习如何:
-
使用 OpenCV 函数 cv::split 将图像划分为其相应的平面。
-
使用 OpenCV 函数 cv::calcHist 计算图像数组的直方图
-
使用函数 cv::normalize 规范化数组
-
注意
在上一教程(直方图均衡)中,我们讨论了一种特殊的直方图,称为图像直方图。现在,我们将从更一般的概念中考虑它。请继续阅读!
什么是直方图?
-
直方图是收集到一组预定义箱中的数据计数
-
当我们说数据时,我们并没有将其限制为强度值(正如我们在前面的教程直方图均衡中看到的那样)。收集的数据可以是您认为对描述图像有用的任何特征。
-
让我们看一个例子。想象一下,矩阵包含图像的信息(即强度在 范围内):0−255
-
如果我们想以有组织的方式计算这些数据,会发生什么?由于我们知道这种情况的信息值范围是 256 个值,因此我们可以将范围划分为子部分(称为 bin),如下所示:
-
我们可以计算落在每个 bin_{i} 范围内的像素数。将其应用于上面的示例,我们得到下图(轴 x 表示条柱,轴 y 表示每个条柱中的像素数)。乙 in我
-
这只是直方图工作原理及其有用性的简单示例。直方图不仅可以计算颜色强度,还可以计算我们想要测量的任何图像特征(即渐变、方向等)。
-
让我们确定直方图的某些部分:
- dims:要收集其数据的参数数。在我们的示例中,dims = 1,因为我们只计算每个像素的强度值(在灰度图像中)。
- bins:是每个 dim 中的细分数。在我们的示例中,箱 = 16
- range:要测量的值的限值。在本例中:范围 = [0,255]
-
如果要计算两个特征怎么办?在这种情况下,生成的直方图将是一个 3D 图(其中 x 和 y 对于每个特征分别为 bin_{x} 和 bin_{y},z 将是 (bin_{x}, bin_{y}) 的每个组合的计数数。 这同样适用于更多功能(当然它会变得更加棘手)。乙 inx乙 iny(乙 inx,biny)
OpenCV 为您提供了什么
出于简单的目的,OpenCV 实现了函数 cv::calcHist ,它计算一组数组(通常是图像或图像平面)的直方图。它可以在多达 32 个维度下运行。我们将在下面的代码中看到它!
法典 C++爪哇岛蟒
-
这个程序是做什么的?
- 加载图像
- 使用函数 cv::split 将图像拆分为 R、G 和 B 平面
- 通过调用函数 cv::calcHist 计算每个 1 通道平面的直方图
- 在窗口中绘制三个直方图
-
可下载代码:点击这里
-
代码一览:
#include “opencv2/highgui.hpp”
#include“opencv2/imgcodecs.hpp”
#include“opencv2/imgproc.hpp”
#include < iostream>
使用命名空间 std;
使用命名空间 CV;
int main(int argc, char** argv)
{
CommandLineParser 解析器( argc, argv, “{@input |莉娜.jpg |输入图像}” );
Mat src = imread( samples::findFile( parser.get<String>( “@input” ) ), IMREAD_COLOR );
if( src.空() )
{
返回EXIT_FAILURE;
}
vector bgr_planes;
split( src, bgr_planes );
int histSize = 256;
浮点数范围[] = { 0, 256 };//上边界为排他性
常量浮点数* histRange[] = { 范围 };
bool uniform = true, accumulate = false;
Mat b_hist, g_hist, r_hist;
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, histRange, 均匀, 累加 );
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, histRange, uniform, accumulate );
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, histRange, uniform, accumulate );
int hist_w = 512, hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, 标量( 0,0,0) );
normalize(b_hist, b_hist, 0, histImage.行, NORM_MINMAX, -1, 垫子() );
normalize(g_hist, g_hist, 0, histImage.行, NORM_MINMAX, -1, 垫子() );
normalize(r_hist, r_hist, 0, histImage.行, NORM_MINMAX, -1, 垫子() );
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(b_hist.at(i)) ),
标量( 255, 0, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(g_hist.at(i)) ),
标量( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(r_hist.at(i)) ),
标量( 0, 0, 255), 2, 8, 0 );
}
imshow(“源图像”, src );
imshow(“calcHist 演示”, histImage );
等待键();
返回EXIT_SUCCESS;
}
解释 C++爪哇岛蟒
- 加载源图像
CommandLineParser 解析器( argc, argv, “{@input |莉娜.jpg |输入图像}” );
Mat src = imread( samples::findFile( parser.get[>( “@input” ) ), IMREAD_COLOR );
如果( src.empty() )
{
返回EXIT_FAILURE;
}
- 在三个 R、G 和 B 平面中分离源图像。为此,我们使用 OpenCV 函数 cv::split :
vector bgr_planes;
split( src, bgr_planes );
我们的输入是要分割的图像(本例中有三个通道),输出是 Mat 的向量 )
- 现在我们准备开始为每个平面配置现在我们准备开始为每个平面配置。由于我们使用的是 B、G 和 R 平面,因此我们知道我们的值将在区间内。由于我们使用的是 B、G 和 R 平面,因此我们知道我们的值将在区间 ] 范围内[0,255]
- 建立箱数(5、10…):
int histSize = 256;
- 设置值范围(正如我们所说,介于 0 和 255 之间)
浮点数范围[] = { 0, 256 };//上边界为排他性
常量浮点数* histRange[] = { 范围 };
- 我们希望我们的箱子具有相同的大小(统一),并在开始时清除直方图,因此:
bool uniform = true, accumulate = false;
- 我们继续使用 OpenCV 函数 cv::calcHist 计算直方图:
Mat b_hist, g_hist, r_hist;
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, histRange, uniform, accumulate );
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, histRange, uniform, accumulate );
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, histRange, uniform, accumulate );
- 其中参数为(C++ 代码):
- **&bgr_planes[0]:**源数组
- 1:源数组的数量(在本例中,我们使用 1.我们也可以在这里输入一个数组列表:)
- 0:要测量的通道(dim)。在这种情况下,它只是强度(每个数组都是单通道的),所以我们只写 0。
- Mat():要在源数组上使用的掩码(零表示要忽略的像素)。如果未定义,则不使用
- b_hist:将存储直方图的 Mat 对象
- 1:直方图维数。
- **histSize:**每个已用维度的条柱数
- **histRange:**每个维度要测量的值范围
- 均匀和累积:箱大小相同,直方图在开始时被清除。
- 创建图像以显示直方图:
int hist_w = 512, hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, 标量( 0,0,0) );
- 请注意,在绘制之前,我们首先对直方图进行 cv::归一化,使其值落在输入的参数所指示的范围内:
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
- 此函数接收以下参数 (C++ 代码):
- **b_hist:**输入数组
- **b_hist:**输出归一化数组(可以相同)
- 0 和 histImage.rows:在本例中,它们是规范化 r_hist 值的下限和上限
- **NORM_MINMAX:**指示规范化类型的参数(如上所述,它调整之前设置的两个限制之间的值)
- **-1:**表示输出规范化数组的类型与输入相同
- **垫子():**可选面罩
- 请注意,要访问箱(在本例中为此 1D 直方图):
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at(i-1)) ),
点( bin_w*(i), hist_h - cvRound(b_hist.at(i)) ),
标量( 255, 0, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(g_hist.at(i)) ),
标量( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(r_hist.at(i)) ),
标量( 0, 0, 255), 2, 8, 0 );
}
我们使用表达式(**C++**代码):
b_hist.at(i)
其中 其中表示尺寸。如果它是 2D 直方图,我们将使用如下内容: 表示维度。如果它是 2D 直方图,我们将使用如下内容:我
b_hist.at( i, j )
- 最后,我们显示直方图并等待用户退出:
imshow(“源图像”, src );
imshow(“calcHist 演示”, histImage );
等待键();
结果
-
使用如下所示的图像作为输入参数:
-
生成以下直方图:
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
😝有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
😝有需要的小伙伴,可以Vx扫描下方二维码免费领取==🆓