5.4分段线性灰度变换

2024-09-03 04:52
文章标签 分段 线性 5.4 灰度变换

本文主要是介绍5.4分段线性灰度变换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

实验原理

分段线性灰度变换的概念

变换函数的形式

示例代码1

示例结果1

示例代码2

示例结果2

示例代码3

运行结果3

示例代码4

运行结果4


实验原理

在OpenCV中,分段线性灰度变换(Piecewise Linear Gray Level Transformation)是一种更复杂的图像处理技术,它允许对图像的不同灰度区间应用不同的线性变换。这种方法可以更有针对性地调整图像的对比度和亮度,从而突出特定区域的信息。

分段线性灰度变换的概念

分段线性灰度变换的基本思想是在图像的灰度级范围内划分多个区间,并对每个区间内的像素值应用不同的线性变换。这种变换可以更好地控制图像不同部分的对比度,特别是在图像的某些区域对比度较低的情况下,从而增强特定区域的细节。

变换函数的形式

分段线性灰度变换通常可以表示为一系列线性变换的组合,每个变换适用于不同的灰度区间。假设图像的灰度级范围是从 0 到 255,我们可以将这个范围划分为若干个子区间,并对每个子区间内的像素值应用不同的线性函数。

例如,对于两个子区间 [0, t1] 和 (t1, 255],可以定义如下变换函数:

OpenCV中的实现方法
虽然OpenCV没有直接提供分段线性灰度变换的函数,但可以通过组合基本的数学运算和条件语句来实现这一功能。具体来说,可以使用OpenCV中的基本操作(如乘法、加法等)以及条件选择函数来实现分段线性变换。

示例代码1

下面是一个使用OpenCV实现分段线性灰度变换的例子:


#include "pch.h"
#include <opencv2/opencv.hpp>  //头文件using namespace cv;
using namespace std;int main() 
{// 读取图像Mat ser = imread("020.jpeg", IMREAD_COLOR);if (ser.empty()) {cout << "无法加载图像,请检查文件路径是否正确。" << endl;return -1;}// 定义目标矩阵Mat gray,dst;cvtColor(ser, gray, COLOR_BGR2GRAY);//转化为灰度图像dst = gray.clone();//深拷贝// 设置分段线性变换的参数double alpha1 = 1.5; // 第一个区间的斜率double beta1 = 0;    // 第一个区间的偏移量double alpha2 = 0.5; // 第二个区间的斜率double beta2 = 50;   // 第二个区间的偏移量int threshold = 128; // 阈值,用于分割两个区间// 应用分段线性灰度变换dst.forEach<uchar>([&](uchar& pixel, const int* position) -> void {if (pixel <= threshold) {pixel = saturate_cast<uchar>(alpha1 * pixel + beta1);}else{pixel = saturate_cast<uchar>(alpha2 * pixel + beta2);}});// 显示原始图像和变换后的图像namedWindow("源图像", WINDOW_NORMAL);imshow("源图像", ser);namedWindow("灰度图像", WINDOW_NORMAL);imshow("灰度图像", gray);namedWindow("分段线性变换图像", WINDOW_NORMAL);imshow("分段线性变换图像", dst);waitKey(0); // 等待按键退出return 0;
}代码说明
1.读取图像:使用 imread 函数读取图像,并确保图像路径正确。
2.定义目标矩阵:创建一个目标矩阵 imgTransformed,它将存储变换后的图像。
3.设置分段线性变换的参数:定义两个区间的线性变换参数 alpha1, beta1, alpha2, beta2 以及阈值 threshold。
4.应用分段线性灰度变换:使用 forEach 方法遍历图像中的每个像素,并根据像素值所在的区间应用不同的线性变换。
5.显示结果:使用 imshow 函数显示原始图像和变换后的图像,并等待用户按键退出。总结
分段线性灰度变换是一种强大的图像处理技术,它可以针对图像的不同灰度区间应用不同的线性变换,从而增强特定区域的对比度。通过在OpenCV中组合基本的数学运算和条件选择,可以灵活地实现这一变换。这种方法非常适合于需要精细调整图像对比度的应用场景。

示例结果1

示例代码2

下面是一个使用OpenCV和C++实现分段线性灰度变换的示例代码:#include "pch.h"
#include <opencv2/opencv.hpp>  //头文件
#include <iostream>using namespace cv;
using namespace std;int main(int argc, char** argv)
{// 读取图像cv::Mat img = cv::imread("019.jpeg", cv::IMREAD_GRAYSCALE);if (img.empty()){std::cout << "Error opening image" << std::endl;return -1;}// 定义分段区间和变换参数double a1 = 50, b1 = 100; // 第一个区间的边界double a2 = 150, b2 = 200; // 第二个区间的边界double alpha1 = 1.5, beta1 = 0; // 第一个区间的变换参数double alpha2 = 0.5, beta2 = 0; // 第二个区间的变换参数// 创建输出图像cv::Mat transformedImg = cv::Mat::zeros(img.size(), CV_8UC1);// 应用分段线性变换for (int y = 0; y < img.rows; ++y){for (int x = 0; x < img.cols; ++x){uchar pixelValue = img.at<uchar>(y, x);if (pixelValue >= a1 && pixelValue <= b1){transformedImg.at<uchar>(y, x) = std::min(255, std::max(0, static_cast<int>(alpha1 * pixelValue + beta1)));}else if (pixelValue >= a2 && pixelValue <= b2){transformedImg.at<uchar>(y, x) = std::min(255, std::max(0, static_cast<int>(alpha2 * pixelValue + beta2)));}else{transformedImg.at<uchar>(y, x) = pixelValue;}}}// 显示结果cv::namedWindow("源图", cv::WINDOW_NORMAL);cv::imshow("源图", img);cv::namedWindow("变化后图像", cv::WINDOW_NORMAL);cv::imshow("变化后图像", transformedImg);cv::waitKey(0);return 0;
}代码解释
1. 读取图像:使用cv::imread读取输入图像,并确保它是灰度图像。
2. 定义分段区间和变换参数:定义两个分段区间 [50, 100] 和 [150, 200],以及相应的变换参数。
3. 创建输出图像:创建一个新的图像矩阵用于存储变换后的结果。
4. 应用分段线性变换:遍历每个像素值,根据所属的区间应用相应的线性变换。
5. 显示结果:使用cv::imshow显示原始图像和变换后的图像,并等待用户按键退出。调整参数
通过调整分段区间和变换参数,可以实现不同的效果。例如,增大某个区间的对比度系数(alpha),可以增强该区域的对比度;减小对比度系数,则可以减弱该区域的对比度。
应用场景
分段线性灰度变换在图像处理中有广泛的应用,特别是在图像增强、图像分割等领域。通过合理设置分段区间和变换参数,可以显著改善图像的视觉效果。

示例结果2

示例代码3

分段变换核心算法

// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include "pch.h"
#include <opencv2/opencv.hpp>  //头文件
#include <iostream>//#pragma comment(lib, "opencv_world450d.lib")  //引用引入库 using namespace cv;  //包含cv命名空间
using namespace std;void dividedLinearStrength(cv::Mat& matInput, cv::Mat& matOutput, float fStart, float fEnd,float fSout, float fEout)
{float fK1 = fSout / fStart;float fK2 = (fEout - fSout) / (fEnd - fStart);float fC2 = fSout - fK2 * fStart;float fK3 = (255.0f - fEout) / (255.0f - fEnd);float fC3 = 255.0f - fK3 * 255.0f;std::vector<unsigned char> loolUpTable(256);for (size_t m = 0; m < 256; m++){if (m < fStart){loolUpTable[m] = static_cast<unsigned char>(m * fK1);}else if (m > fEnd){loolUpTable[m] = static_cast<unsigned char>(m * fK3 + fC3);}else{loolUpTable[m] = static_cast<unsigned char>(m * fK2 + fC2);}}matOutput = cv::Mat::zeros(matInput.rows, matInput.cols, matInput.type());for (size_t r = 0; r < matInput.rows; r++){unsigned char* pInput = matInput.data + r * matInput.step[0];unsigned char* pOutput = matOutput.data + r * matOutput.step[0];for (size_t c = 0; c < matInput.cols; c++){pOutput[c] = loolUpTable[pInput[c]];}}
}int main()
{Mat matSrc = cv::imread("026.jpeg", IMREAD_GRAYSCALE);if (matSrc.empty()){cout << "源图像读取失败!" << endl;return 0;}namedWindow("原始图", WINDOW_NORMAL);imshow("原始图", matSrc);Mat matDLS;dividedLinearStrength(matSrc, matDLS, 72, 200, 5, 240);namedWindow("分段线性拉伸", WINDOW_NORMAL);imshow("分段线性拉伸", matDLS);waitKey(0);return 0;
}

运行结果3

示例代码4

5.5分段线性变换改善图像

#include "pch.h"
#include <opencv2/opencv.hpp>  //头文件
#include <iostream>//#pragma comment(lib, "opencv_world450d.lib")  //引用引入库 using namespace cv;  //包含cv命名空间
using namespace std;int main(int argc, char ** argv)
{Mat srcImage, dstImage;float alpha = 2.0;float beta = 0;srcImage = imread("023.jpeg", 0);     if (!srcImage.data){printf("could not load image...\n");return -1;}char input_title[] = "输入源图";char output_title[] = "输出修改图";namedWindow(input_title, WINDOW_NORMAL);namedWindow(output_title, WINDOW_NORMAL);imshow(input_title, srcImage);dstImage = srcImage.clone();	 for (int r = 0; r < srcImage.rows; r++){for (int c = 0; c < srcImage.cols; c++) {uchar temp = srcImage.at<uchar>(r, c);if (temp < 50){dstImage.at<uchar>(r, c) = saturate_cast<uchar>(temp * 0.5);	 }else if (50 <= temp && temp < 150){dstImage.at<uchar>(r, c) = saturate_cast<uchar>(temp * 3.6 - 310);	 }else{dstImage.at<uchar>(r, c) = saturate_cast<uchar>(temp * 0.238 + 194);	 }}}imshow(output_title, dstImage);//imwrite("img_new.jpg", dstImage);		//保存处理后的图像 waitKey(0);return 0;
}

运行结果4

结果

这篇关于5.4分段线性灰度变换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1132075

相关文章

线性因子模型 - 独立分量分析(ICA)篇

序言 线性因子模型是数据分析与机器学习中的一类重要模型,它们通过引入潜变量( latent variables \text{latent variables} latent variables)来更好地表征数据。其中,独立分量分析( ICA \text{ICA} ICA)作为线性因子模型的一种,以其独特的视角和广泛的应用领域而备受关注。 ICA \text{ICA} ICA旨在将观察到的复杂信号

微积分-积分应用5.4(功)

术语“功”在日常语言中用来表示完成一项任务所需的总努力量。在物理学中,它有一个依赖于“力”概念的技术含义。直观上,你可以将力理解为对物体的推或拉——例如,一个书本在桌面上的水平推动,或者地球对球的向下拉力。一般来说,如果一个物体沿着一条直线运动,位置函数为 s ( t ) s(t) s(t),那么物体上的力 F F F(与运动方向相同)由牛顿第二运动定律给出,等于物体的质量 m m m 与其

✨机器学习笔记(二)—— 线性回归、代价函数、梯度下降

1️⃣线性回归(linear regression) f w , b ( x ) = w x + b f_{w,b}(x) = wx + b fw,b​(x)=wx+b 🎈A linear regression model predicting house prices: 如图是机器学习通过监督学习运用线性回归模型来预测房价的例子,当房屋大小为1250 f e e t 2 feet^

【高等代数笔记】线性空间(一到四)

3. 线性空间 令 K n : = { ( a 1 , a 2 , . . . , a n ) ∣ a i ∈ K , i = 1 , 2 , . . . , n } \textbf{K}^{n}:=\{(a_{1},a_{2},...,a_{n})|a_{i}\in\textbf{K},i=1,2,...,n\} Kn:={(a1​,a2​,...,an​)∣ai​∈K,i=1,2,...,n

带头结点的线性链表的基本操作

持续了好久,终于有了这篇博客,链表的操作需要借助图像模型进行反复学习,这里尽可能的整理并记录下自己的思考,以备后面复习,和大家分享。需要说明的是,我们从实际应用角度出发重新定义了线性表。 一. 定义 从上一篇文章可以看到,由于链表在空间的合理利用上和插入、删除时不需要移动等优点,因此在很多场合下,它是线性表的首选存储结构。然而,它也存在某些实现的缺点,如求线性表的长度时不如顺序存储结构的

浙大数据结构:02-线性结构4 Pop Sequence

这道题我们采用数组来模拟堆栈和队列。 简单说一下大致思路,我们用栈来存1234.....,队列来存输入的一组数据,栈与队列进行匹配,相同就pop 机翻 1、条件准备 stk是栈,que是队列。 tt指向的是栈中下标,front指向队头,rear指向队尾。 初始化栈顶为0,队头为0,队尾为-1 #include<iostream>using namespace std;#defi

深度学习与大模型第3课:线性回归模型的构建与训练

文章目录 使用Python实现线性回归:从基础到scikit-learn1. 环境准备2. 数据准备和可视化3. 使用numpy实现线性回归4. 使用模型进行预测5. 可视化预测结果6. 使用scikit-learn实现线性回归7. 梯度下降法8. 随机梯度下降和小批量梯度下降9. 比较不同的梯度下降方法总结 使用Python实现线性回归:从基础到scikit-learn 线性

C#中的各种画刷, PathGradientBrush、线性渐变(LinearGradientBrush)和径向渐变的区别

在C#中,画刷(Brush)是用来填充图形(如形状或文本)内部区域的对象。在.NET框架中,画刷是System.Drawing命名空间的一部分,通常用于GDI+绘图操作。以下是一些常用的画刷类型: SolidBrush:用于创建单色填充的画刷。HatchBrush:用于创建具有图案填充的画刷。TextureBrush:用于创建具有图像纹理填充的画刷。LinearGradientBrush:用于创

(感知机-Perceptron)—有监督学习方法、非概率模型、判别模型、线性模型、参数化模型、批量学习、核方法

定义 假设输入空间(特征空间)是 χ \chi χ ⊆ R n \subseteq R^n ⊆Rn,输出空间是y = { + 1 , − 1 } =\{+1,-1 \} ={+1,−1} 。输入 x ∈ χ x \in \chi x∈χ表示实例的特征向量,对应于输入空间(特征空间)的点;输出 y ∈ y \in y∈y表示实例的类别。由输入空间到输出空间的如下函数: f ( x ) = s

逻辑回归与线性回归的目标函数和应用场景比较

概述 逻辑回归和线性回归是两种常用的预测模型,它们在目标函数和应用场景上存在显著差异。本文将详细比较这两种回归模型,并提供相应的代码示例。 线性回归 线性回归是一种预测连续数值的模型,其目标是找到特征( X )和目标变量( Y )之间的线性关系。线性回归的目标函数是最小化预测值和实际值之间的平方差,即均方误差(MSE)。 目标函数 线性回归的损失函数是均方误差: [ J(\theta)