目录
实验原理
分段线性灰度变换的概念
变换函数的形式
示例代码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
结果