MATLAB和Intislim,matlab灰阶变换函数imadjust和stretchlim的c++实现

article/2025/8/19 3:09:27

灰阶变换

首先介绍一下灰阶变换,一幅图像数据本身在存储的数据结构上为一个二维的矩阵,即一幅图像为m*n个密密麻麻的像素点构成。

AAffA0nNPuCLAAAAAElFTkSuQmCC

image.png

然后,这些像素点有着一个值,这个值成为灰度值或者亮度值,值的范围为[0,255],一共256级的亮度,也有成灰度级或灰阶的说法。那么如果把像素点的坐标(x, y)看作自变量,那么像素点的灰度值就可以看作它的函数值。

AAffA0nNPuCLAAAAAElFTkSuQmCC

image.png

然后灰阶变换就是函数值f(x,y)的变换了。就是一副像素点的灰度值按照某种规则或者关系从一个灰度级变换到另一个灰度级,变换的表达式如下。

AAffA0nNPuCLAAAAAElFTkSuQmCC

image.png

在matlab中,灰阶变换的两个工具函数,imadjust和stretchlim,接下来我们就用c++实现它。

imadjust

要实现imadjust函数,就先了解一下它,不知所以然就没法实现。这我们换看百度百科的介绍。imadjust是一个计算机函数,该函数用于调节灰度图像的亮度或彩色图像的颜色矩阵。在matlab的命令窗口中键入: doc imadjust或者help imadjust即可获得该函数的帮助信息, 键入type imadjust可以查看函数的源代码。

再看看其函数原型J = imadjust(I)

J = imadjust(I,[low_in; high_in],[low_out; high_out])

J = imadjust(I,[low_in; high_in],[low_out; high_out],gamma)

[newmap](https://baike.baidu.com/item/newmap) = imadjust(map,[low_in; high_in],[low_out;high_out],gamma)RGB2 = imadjust(RGB1,...)

对应的要实现的c++函数原型是这样的void imadjust(cv::Mat& input, cv::Mat& output, double low_in = 0.0, double high_in  = 1.0, double low_out = 0.0, double high_out = 1.0, double gamma = 1);//matlab,像素区间[0,1]void imadjust(cv::Mat& input, cv::Mat& output, std::vector in = { 0.0, 1.0 }, double low_out = 0.0, double high_out = 1.0, double gamma = 1);void imadjust2(cv::Mat& input, cv::Mat& output, int low_in, int high_in, int low_out, int high_out, double gamma = 1);//opencv,像素区间[0,255]

接着是函数的功能

该函数用于调节灰度图像的亮度或彩色图像的颜色矩阵

来自官方帮助文档的使用示例I = imread('pout.tif');J = imadjust(I);imshow(I), figure, imshow(J)

K = imadjust(I,[0.3 0.7],[]);figure, imshow(K)

RGB1 = imread('football.jpg');RGB2 = imadjust(RGB1,[.2 .3 0; .6 .7 1],[]);

imshow(RGB1), figure, imshow(RGB2)

附上解释J = imadjust(I)

将灰度图像 I 中的亮度值映射到 J 中的新值,使得图像中 1% 的数据饱和至最低和最高亮度,这可以增加输出图像 J 的对比度值。此用法相当于 imadjust(I,stretchlim(I))J = imadjust(I,[low_in; high_in],[low_out; high_out])

将图像I中的亮度值映射到J中的新值,即将low_in至high_in之间的值映射到low_out至high_out之间的值。low_in 以下与 high_in 以上的值被剪切掉了,也就是说,low_in 以下的值映射到 low_out,high_in 以上的值映射到high_out。它们都可以使用空的矩阵[],默认值是[0 1]。

J = imadjust(I,[low_in; high_in],[low_out; high_out],gamma)

将图像 I 中的亮度值映射到 J 中的新值,其中 gamma指定描述值I和值J关系的曲线形状。如果gamma小于1,此映射偏重更高数值(明亮)输出,如果gamma大于1,此映射偏重更低数值(灰暗)输出,如果省略此参数,默认为(线性映射)。 《Simulink与信号处理》

newmap = imadjust(map,[low_in; high_in],[low_out; high_out],gamma)

调整索引色图像的调色板map。如果low_in, high_in, low_out, high_out 和 gamma 都是标量,那么对 r,g,b 分量同时都做此映射。对于每个颜色分量都有唯一的映射,当 low_in 和 high_in 同时为1*3向量或者 low_out 和 high_out 同时为1*3向量或者 gamma 为1*3向量时。调整后的颜色矩阵 [newmap](https://baike.baidu.com/item/newmap) 和 map 有相同的大小。

RGB2 = imadjust(RGB1,...)

对 RGB 图像 RGB1 的红、绿、蓝调色板分别进行调整。随着颜色矩阵的调整,每一个调色板都有唯一的映射值。

这里我们着重理解一下行数原型的几个参数J = imadjust(I,[low_in; high_in],[low_out; high_out],gamma)

I为输入的图像,函数的功能就是把输入图像在[low_in; high_in]灰度级中的像素点,映射为[low_out; high_out]区间的灰度级,gamma为一个可选参数,gamma = 1为线性变换,gamma != 1为伽马变换。

AAffA0nNPuCLAAAAAElFTkSuQmCC

image.png

AAffA0nNPuCLAAAAAElFTkSuQmCC

image.png

AAffA0nNPuCLAAAAAElFTkSuQmCC

image.png

下面来讲一下伽马变换。伽马变换又称幂次变换,变换公式为

AAffA0nNPuCLAAAAAElFTkSuQmCC

gamma.gif

AAffA0nNPuCLAAAAAElFTkSuQmCC

image.png

好,下面开始代码的实现。

先用一张表储存伽马变换的值,这样就不需要在每次变量像素点的时候都调用gamma变换公式计算std::vector gammaLut(const double gamma, const double c)

{    std::vector lut(256);    for (int i = 0; i 

lut[i] =  static_cast(c * std::pow((double)(i / 255.0), gamma) * 255.0);    return lut;

}

然后遍历图像,对每个像素点进行灰阶变换操作for (int i = 0; i 

{                double result = 0;                if (input.at(i, j) <= low_in)//灰度值小于low_in的像素点

{

result = low_out;//结果为low_out

}                else if (low_in (i, j) && input.at(i, j) 

{

result = k * (input.at(i, j) - low_in) + high_in;//灰度值线性变换

result = gamma_lut[static_cast(result)];//灰度值gamma变换

}

else

{

result = high_out;//灰度值大于high_in的像素点,结果为high_out

}

output.at(i, j) = static_cast(result) % 255;

}

下面放出完整代码//imadjust函数的实现#include#include#include#includevoid imadjust(cv::Mat& input, cv::Mat& output, double low_in = 0.0, double high_in  = 1.0, double low_out = 0.0, double high_out = 1.0, double gamma = 1);//matlab,像素区间[0,1]void imadjust(cv::Mat& input, cv::Mat& output, std::vector in = { 0.0, 1.0 }, double low_out = 0.0, double high_out = 1.0, double gamma = 1);void imadjust2(cv::Mat& input, cv::Mat& output, int low_in, int high_in, int low_out, int high_out, double gamma = 1);//opencv,像素区间[0,255]std::vector gammaLut(const double gamma, const double c = 1.0);//灰度值的伽马变换结果表lutbool is0to1(const double var);int main(){

cv::Mat src_img = cv::imread("Fig0304(a)(breast_digital_Xray).tif");    if(src_img.empty()) return -1;

cv::Mat dst_img;

imadjust(src_img, dst_img, 0, 1, 0, 1, 2);

cv::imshow("src_img", src_img);

cv::imshow("dst_img", dst_img);

cv::waitKey(0);    return 0;

}//mainvoid imadjust(cv::Mat& input, cv::Mat& output, double low_in, double high_in, double low_out, double high_out, double gamma){

assert(low_in 

high_in *= 255; high_out *= 255; low_in *= 255; low_out *= 255;

imadjust2(input, output, low_in, high_in, low_out, high_out, gamma);

}void imadjust(cv::Mat& input, cv::Mat& output, std::vector in, double low_out, double high_out, double gamma){

assert(2 == in.size());    double low_in = in[0];    double high_in = in[1];

imadjust(input, output, low_in, high_in, low_out, high_out, gamma);

}void imadjust2(cv::Mat& input, cv::Mat& output, int low_in, int high_in, int low_out, int high_out, double gamma )//opencv,像素区间[0,255]{

output = input.clone();    int rows = input.rows;//行

int cols = input.cols;//列

double k = (static_cast(high_out) - low_out) / (high_in - low_in);    std::vector gamma_lut = gammaLut(gamma);    switch(input.channels())

{    case 1://灰度图

for (int i = 0; i 

{                double result = 0;                if (input.at(i, j) <= low_in)//灰度值小于low_in的像素点

{

result = low_out;//结果为low_out

}                else if (low_in (i, j) && input.at(i, j) 

{

result = k * (input.at(i, j) - low_in) + high_in;//灰度值线性变换

result = gamma_lut[static_cast(result)];//灰度值gamma变换

}

else

{

result = high_out;//灰度值大于high_in的像素点,结果为high_out

}

output.at(i, j) = static_cast(result) % 255;

}        break;        //彩色图片

case 3:        for (int i = 0; i 

{                    double result = 0;                    if (input.at<:vec3b>(i, j)[k] <= low_in)

result = low_out;                    else if (low_in (i, j)[k] && input.at<:vec3b>(i, j)[k] 

{

result = k * (input.at<:vec3b>(i, j)[k] - low_in) + high_in;

result = gamma_lut[static_cast(result)];

}                    else

{

result = high_out;

}

output.at<:vec3b>(i, j)[k] = static_cast(result) % 255;

}

break;    default:        break;

}

}bool is0to1(const double var){    return 0 <= var && var <= 1;

}std::vector gammaLut(const double gamma, const double c)

{    std::vector lut(256);    for (int i = 0; i 

lut[i] =  static_cast(c * std::pow((double)(i / 255.0), gamma) * 255.0);    return lut;

}

测试效果

AAffA0nNPuCLAAAAAElFTkSuQmCC

image.png

stretchlim

同样的,先看看这个函数有什么作用,stretchlim函数要用于自适应找到一个分割阈值向量来改变一幅图像的对比度。就是自动找到imadjust函数中[low_in; high_in]的合适值,所以说stretchlim是为imadjust函数服务的。

接着来看一下stretchlim函数的原型lowhigh = stretchlim(I)

lowhigh = stretchlim(I,Tol)

对应到我们要实现的c++函数原型是这样的std::vector strecthlim(cv::Mat img, double tol_low = 0.01, double tol_high = 0.99);

至于函数的实现原理和过程,看到这篇文章Matlab中的stretchlim函数详解,解释的非常清楚。我就不详细说明了,代码中也给了较多的注释。

下面贴上代码

头文件#pragma once#include#include#includestd::vector calcGrayLevel(cv::Mat& img);//计算灰度级,即算出从0到255区间的任意一个灰度值i,在图像img中有多少个像素点的灰度值为istd::vector pdf(std::vector gray_level, cv::Mat& img);//计算概率密度pdfstd::vector cdf(std::vector pdf);//计算概率分布cdfdouble findLow(double input_low, std::vector cdf);double findHihg(double input_high, std::vector cdf);std::vector strecthlim(cv::Mat img, double tol_low = 0.01, double tol_high = 0.99);

cpp文件//2-2-1//stretchlim函数#include"stretchlim.h"#includeint main(){

cv::Mat img = cv::imread("./Fig0304(a)(breast_digital_Xray).tif", 0);    if (img.empty()) return -1;    std::vector v = strecthlim(img);    for (auto& i : v)        std::cout <

system("pause");    return 0;

}std::vector calcGrayLevel(cv::Mat& img)//计算灰度级,即算出从0到255区间的任意一个灰度值i,在图像img中有多少个像素点的灰度值为i{

assert(img.channels() == 1);//只计算灰度图像的

std::vector res(256);    int rows = img.rows;//行

int cols = img.cols;//列

for(int i = 0; i 

{            int val = img.at(i, j);

res[val] += 1;

}    return res;

}std::vector pdf(std::vector gray_level, cv::Mat& img)//计算概率密度{

assert(gray_level.size() == 256);

int N = img.rows * img.cols;//像素点总数

std::vector res(256);    for (int i = 0; i 

res[i] =static_cast(gray_level[i]) / N;    return res;

}std::vector cdf(std::vector pdf)//计算概率分布cdf{

assert(pdf.size() == 256);    std::vector res(256);

res[0] = pdf[0];    for (int i = 1; i 

res[i] = pdf[i] + res[i - 1];    return res;

}double findLow(double input_low, std::vector cdf){

assert(cdf.size() == 256);    //找到分布概率大于我们的输入值input_low处最接近的灰度值,并以此作为最佳分割阈值的最小值

for (int i = 0; i  input_low)            return cdf[i];    return 0.0;

}double findHihg(double input_high, std::vector cdf){

assert(256 == cdf.size());    //找到分布概率大于或等于我们的输入值input_high处最接近的灰度值,并以此作为最佳分割阈值的最大值

for(int i = 0; i = input_high)            return cdf[i];    return 0.0;

}std::vector strecthlim(cv::Mat img, double tol_low, double tol_high)

{    std::vector v(2);    if (img.empty()) return v;    //计算灰度值

std::vector gray_level = calcGrayLevel(img);    //计算概率密度pdf

std::vector p = pdf(gray_level, img);    //计算概率分布cdf

std::vector c = cdf(p);    //寻找tol_low, tol_high

tol_low = findLow(tol_low, c);

tol_high = findHihg(tol_high, c);

if (tol_low == tol_high)

v = { 0.0, 1.0 };    else

v = { tol_low, tol_high };    return v;

}

作者:芒果浩明

链接:https://www.jianshu.com/p/0d984223fa84


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

相关文章

一个app开发周期是多久?快速开发才是主流

app的出现&#xff0c;极大的方便了人们的生活、社交和工作&#xff0c;各种各样的app为人们提供了各种便利的服务&#xff0c;真正让移动互联网服务大众。许多行业看到在app上爆发出的巨大潜能&#xff0c;都纷纷主动进行app制作来迎接移动互联网浪潮。 开发app一个很重的问题…

如何开发app软件?程序员揭秘你还没听过的1种方法

如何开发app软件&#xff1f;app软件开发需要多少钱&#xff1f;现在手机app这么火&#xff0c;很多企业都想开发一个app软件开拓市场。但是在开发app的时候往往会感觉力不从心&#xff0c;因为app开发门槛比较高&#xff0c;大家对app软件开发需要的技术、成本并不了解。 现…

商城APP软件开发要素有哪些

商城APP软件体系是当今电商行业经常会运用的商城体系&#xff0c;既支撑企业对企业的运营形式&#xff0c;也支撑卖家对消费者的运营形式&#xff0c;便是现在常见的B2C&#xff0c;B2B的电商形式APP&#xff0c;跟着现在的互联网的遍及现在这些电商都是成为了电商商家开展的不…

app软件怎么开发 盘点3种app制作方式

现在智能手机给大家的生活带来了很多便利&#xff0c;利用手机&#xff0c;随时随地看新闻、手机打车提前预定、网上订餐不用等、商家服务提前预约、学习内容随时看、购物更是随时买。各式各样的手机App&#xff0c;让生活方式方式了重大改变。 1、组建团队开发APP 自己有团队…

app应用软件开发流程是怎样的?

从入职这行业到创业已有 7 载&#xff0c;对 APP 产品开发的流程已经再熟悉不过了&#xff0c;现在把这几年积累的一些经验和大家分享一下&#xff0c;一个产品是怎么从想法一步一步落地为具体成品的&#xff0c;这个过程中会经历一些怎样的必要流程呢&#xff0c;下面大致说一…

三阶魔方傻瓜指南

三阶魔方20分钟完全自救指南——包学包会 前言 寒假宅在家里&#xff0c;闲来无事&#xff0c;偶得一个三阶魔方&#xff0c;便从网上找公式摸索。发现了很多版本&#xff0c;但是大多局部最优&#xff0c;缺少易于小白理解的全局最优方法。所以做次总结&#xff0c;集各家所…

C/C++FPS实战CSGO矩阵方框透视骨骼自瞄实战教程

C/CFPS实战CSGO矩阵方框透视骨骼自瞄实战教程

基于yolo5制作的csgo,ai自瞄

研究了几天&#xff0c;终于肝出来了&#xff0c;基本功能完美运行&#xff0c;晚点在训练一个专用模型。

警惕AI,我搭建了一个“枪枪爆头”的视觉AI自瞄程序,却引发了一场“山雨欲来”

前言 前段时间在网上看到《警惕AI外挂&#xff01;我写了一个枪枪爆头的视觉AI&#xff0c;又亲手“杀死”了它》 这个视频&#xff0c;引起了我极大的兴趣。 视频中提到&#xff0c;在国外有人给使命召唤做了个AI程序来实现自动瞄准功能。它跟传统外挂不一样&#xff0c;该程…

理解FPS游戏中的矩阵方框透视自瞄

​ 初识矩阵 其实矩阵是线性代数里面的说法 矩阵&#xff08;Matrix&#xff09;是一个按照长方阵列排列的复数或实数集合 [1] &#xff0c;最早来自于方程组的系数及常数所构成的方阵。这一概念由19世纪英国数学家凯利首先提出。 类似&#xff1a; 矩阵的乘法&#xff1a; …

手把手教你如何0基础编写基于AI机器视觉的--王者荣耀百里守约的自瞄程序,我家村头的傻X都能学会的教程!

先看看我在B站的效果视频 王者荣耀-百里守约-AI辅助自瞄研究 摘要&#xff1a;YoLo目标检测框架 PaddleDetection机器学习框架 不介绍上面的框架了&#xff0c;直入主题&#xff1a; 以下教程基于Windows10系统环境&#xff0c;Win7应该不太行。 考虑到大多数学生比较穷&a…

yolov5实现机器视觉ai自瞄,本人跑代码训练时总结下来的坑(参数设置,服务器使用,自动打标签,训练速度,显存使用率...)

想到啥些啥&#xff0c;都是些我遇到的&#xff0c;很坑&#xff0c;但偏偏又有点蠢的问题。 路过进来的朋友可以 ctrlF 搜一下有没有自己苦恼的问题。 1&#xff0c;训练的模型使用越小&#xff08;最小是yolov5n&#xff09;&#xff0c;帧数越高&#xff0c;自瞄间隔越短。…

[原创]FPS网络游戏自动瞄准自瞄外挂漏洞分析以及实现

0x0. 前言 来到论坛已经有一段时间了,目前大三学生,乐于分享知识,看到论坛招聘讲师的帖子,于是想发点文字,分享知识,不知道能不能申请精华。 新年刚刚过去,不知道大家亲戚走没走完,新的一年里,祝大家财源广进,身体健康,万事如意,一切都会好起来的! 0x1. 了解FPS…

基于yolov7的FPS游戏(csgo,cf,cfhd)自瞄开发

1.训练yolo识别人物导出pt文件 链接: yolov7训练自己的数据集-gpu版 2.使用win32进行屏幕截图和鼠标移动 3.使用导出的pt文件进行推理(pt文件将在完善后发出) 屏幕截图获取屏幕->检测目标的坐标->取中心点->计算距离获取最近的敌人坐标->移动鼠标到中心点 数据集…

穿越火线(CF) AI 自瞄 代码 权重 数据集 亲测可用(结尾有资源)

初衷 本人热衷玩CF&#xff0c;同时为一名程序员&#xff0c;近期听说AI霸占FPS游戏&#xff0c;本着学习的态度&#xff0c;特来测试 不喜欢看过程的小伙伴直接看最下面 模型 采用yolov5模型架构 对过程感兴趣的小伙伴下文自行学习 https://zhuanlan.zhihu.com/p/17212138…

通过YOLOV5实现:王者荣耀百里守约自瞄

前期提要&#xff1a; 本文章仅供技术讨论使用。 关于如何通过YOLOV5去检测到王者中的敌方人物&#xff0c;在网上有很多相关的文章和教学视频我在这里就不过多的阐述&#xff0c;本篇文章主要讲的是在实现中比较难处理的一些技术点&#xff1a;如何获取高刷新率的手机屏幕、…

Ai实现FPS游戏自动瞄准 yolov5fps自瞄

大家好 我是毕加锁 (锁!) 今天来分享一个Yolov5 FPS跟枪的源码解析和原理讲解。代码比较粗糙 各位有什么优化的方式可以留言指出&#xff0c;可以一起交流学习。 需要了解的东西和可能会遇到的问题1.xy坐标点与当前鼠标的xy坐标点距离计算 2.获取窗口句柄&#xff0c;本文使…

[CPU+目标检测] openvino实现Robomaster自瞄

这篇文章为大连理工大学Robomaster凌Bug战队的李乐恒同学成果&#xff01; 他在CPU上利用openvino这样的深度学习算法实现了Robomaster的自瞄&#xff0c;大大提高了robomaster自瞄的上界&#xff0c;且达到了良好的检测效果。所有代码全部开源&#xff0c; github主页如下&am…

基于C++的车辆装甲板检测自瞄系统

资源下载地址&#xff1a;https://download.csdn.net/download/sheziqiong/85773209 资源下载地址&#xff1a;https://download.csdn.net/download/sheziqiong/85773209 装甲板检测 由于在比赛过程中操作手是第一视角&#xff0c;很难用手动瞄准。通过装甲板检测就是自瞄系统…

CFAIyolo5自瞄源码分享

比市面上强的多 阿里云盘分享