5.4分段线性灰度变换

news2024/11/27 18:23:01

目录

实验原理

分段线性灰度变换的概念

变换函数的形式

示例代码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.定义目标矩阵:创建一个目标矩阵 dst,它将存储变换后的图像。
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

结果

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

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

相关文章

GitLab 是什么?GitLab使用常见问题解答

GitLab 是什么 GitLab是由GitLab Inc.开发&#xff0c;使用MIT许可证的基于网络的Git仓库管理工具开源项目&#xff0c;且具有wiki和issue跟踪功能&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基础上搭建起来的web服务。 ​GitLab 是由 GitLab Inc.开发&#xff0c…

【Prometheus】Prometheus的特点、数据采集方式、架构、数据模型详解

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

vue3整合antv x6实现图编辑器快速入门

安装&#xff1a; npm install antv/x6 --save如果使用 umd 包&#xff0c;可以使用下面三个 CDN 中的任何一个&#xff0c;默认使用 X6 的最新版&#xff1a; https://unpkg.com/antv/x6/dist/index.jshttps://cdn.jsdelivr.net/npm/antv/x6/dist/index.jshttps://cdnjs.clo…

从汇编层看64位程序运行——likely提示编译器的优化案例和底层实现分析

大纲 代码分析with_attributes::powno_attributes::pow分析 我们在《Modern C——使用分支预测优化代码性能》一文中介绍了likely提示编译器进行编译优化&#xff0c;但是我们又讲了最终优化不是对分支顺序的调换&#xff0c;那么它到底做了什么样的优化&#xff0c;让整体性能…

个人旅游网(5)——功能详解——购物车功能

文章目录 一、设计购物车二、购物车对redis的一系列操作三、购物车3.1、接口详解3.1.1、addCart&#xff08;将当前旅游路线加入到购物车中&#xff09;3.1.2、showCartItem&#xff08;显示刚刚加入购物车的商品&#xff09;3.1.3、findAll&#xff08;将购物车里的所有旅游路…

骨灵冷火!Solon Cloud Gateway 照面发布

骨灵冷火&#xff0c;是练药的好火哟。极冷&#xff0c;又极热。在冰冻中被烧死&#xff1a;&#xff09; 1、认识 Solon Cloud Gateway Solon Cloud Gateway 是基于 Solon Cloud、Vert.X 和 Solon Rx(reactive-streams) 接口实现。小特点&#xff1a; 纯响应式的接口体验流…

KAN学习Day1——模型框架解析及HelloKAN

说明 最近了解到了一个新东西——KAN&#xff0c;我的毕设导师给推荐的船新框架。我看过很多剖析其原理的文章&#xff0c;发现大家对其持有的观点都各不相同&#xff0c;有的说可以颠覆传统MLP&#xff0c;有的说可以和Transformer同等地位&#xff0c;但是也有人说它训练速度…

YoloV8改进策略:IoU改进|Unified-IoU用于高质量对象检测

摘要 Unified-Unified-IoU&#xff08;UIoU&#xff09;是一种新的边界框回归损失函数&#xff0c;旨在改进目标检测任务中的预测框质量&#xff0c;特别是在高IoU阈值和IoU&#xff08;UIoU&#xff09;是一种新的边界框回归损失函数&#xff0c;旨在改进目标检测任务中的预测…

nginx的基本使用示例(负载均衡,虚拟主机,动静分离)的详细配置过程

文章目录 前言前置工作httpd主机tomcat主机 nginx主机配置负载均衡配置过程效果展示 虚拟主机配置过程效果展示 动静分离配置过程 排除思路 前言 本篇博客展示nginx的基本使用案例&#xff0c;后端由httpdtomcat组成&#xff0c;linux版本: rocky9.2 虚拟机ipnginx192.168.10…

安防监控视频打手机检测算法核心技术打手机检测算法源码、模型简介

在数字化的今天&#xff0c;智能手机几乎已成为人们生活中不可或缺的一部分。然而&#xff0c;手机的广泛使用也带来了一些挑战&#xff0c;比如在公共场所、教育机构和工作环境中的手机干扰。为了解决这些问题&#xff0c;打手机检测算法应运而生&#xff0c;成为管理人员和机…

hive学习(六)

一、函数 1.单行函数 特点&#xff1a;输入一行&#xff0c;输出一行&#xff08;一进一出&#xff09; 可分为日期函数&#xff0c;字符串函数&#xff0c;集合函数&#xff0c;数学函数和流程控制函数等 1&#xff09;算术运算函数 2&#xff09;数值函数 --round函数 …

机器学习如何用于音频分析?

机器学习如何用于音频分析&#xff1f; 一、说明 近十年来&#xff0c;机器学习越来越受欢迎。事实上&#xff0c;它被用于医疗保健、农业和制造业等众多行业。随着技术和计算能力的进步&#xff0c;机器学习有很多潜在的应用正在被创造出来。由于数据以多种格式大量可用&…

电赛2024年H题智能小车基于MSPM0G3507主控MCU(利用8路灰度加上MPU6050的解决方式)

一.前言 前段时间&#xff0c;激烈的电赛刚刚结束&#xff0c;很荣幸啊&#xff0c;也是十分的不甘心&#xff0c;本次的湖北赛区H题只拿到了一个省二&#xff0c;看最终的排名&#xff0c;在H题中我们离省一也就差几名。但是整个比赛已经过去了&#xff0c;现在不甘与不舍&…

浏览器按F12进入开发者模式后频繁因为异常而暂停导致无法分析页面xpath

在分析某个内部页面xpath时&#xff0c;遇到一个问题&#xff0c;因为频繁异常而自动暂停导致无法分析页面xpath&#xff0c;如下图&#xff1a; 折腾良久发现把下图右侧的两个抛出异常自动暂停的开关 取消勾选就可以了

微信小程序接入客服功能

前言 用户可使用小程序客服消息功能&#xff0c;与小程序的客服人员进行沟通。客服功能主要用于在小程序内 用户与客服直接沟通用&#xff0c;本篇介绍客服功能的基础开发以及进阶功能的使用&#xff0c;另外介绍多种客服的对接方式。 更多介绍请查看客服消息使用指南 客服视…

2.4 堆栈

&#x1f393; 微机原理考点专栏&#xff08;通篇免费&#xff09; 欢迎来到我的微机原理专栏&#xff01;我将帮助你在最短时间内掌握微机原理的核心内容&#xff0c;为你的考研或期末考试保驾护航。 为什么选择我的视频&#xff1f; 全程考点讲解&#xff1a;每一节视频都…

数据结构——排序【下】

目录 一、计数排序 二、快速排序 三、归并排序 四、八大排序时间复杂度及其稳定性 一、计数排序 计数排序是一个非基于比较的排序算法&#xff0c;元素从未排序状态变为已排序状态的过程&#xff0c;是由额外空间的辅助和元素本身的值决定的。该算法于1954年由 Harold H. S…

Github 2024-09-03 Python开源项目日报 Top10

根据Github Trendings的统计,今日(2024-09-03统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10HCL项目1JavaScript项目1Payloads All The Things - 有用的Web应用程序安全负载和绕过列表 创建周期:2639 天开发语言:Python协议…

Go语言?IDEA能支持吗?增删查走起?

序&#xff1a; 最近突然身边突然开始冒出关于go语言的只言片语&#xff0c;很好奇这个go语言是怎么样的&#xff1f;这几天有空就会去网上浏览一遍各位大咖的简介。这边主要是已学习为目的&#xff0c;关键人家都说它好这边记录一下学习过程的进坑和爬坑过程供大家娱乐一下。…

echarts3D地图:旋转、添加纹理图片(vue3)

首先安装echarts和echarts-gl依赖&#xff0c;注意的是&#xff0c;echarts-gl版本需安装低版本&#xff0c;且与echarts5版本不兼容&#xff0c;需要单独安装4版本&#xff0c;这里我安装的4.2.1版本。 $ npm install echarts4npm:echarts4.2.1 echarts-gl1.1.0npm可以安装ec…