问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

OpenCV线性灰度变换详解:原理、实现与代码示例

创作时间:
作者:
@小白创作中心

OpenCV线性灰度变换详解:原理、实现与代码示例

引用
CSDN
1.
https://m.blog.csdn.net/weixin_45794330/article/details/141782221

实验原理

在OpenCV中,线性灰度变换是一种常见的图像处理技术,用于调整图像的对比度和亮度。这种变换通过简单的线性函数来调整图像中的像素值,从而达到增强或减弱图像对比度的效果。线性灰度变换的基本形式可以表示为:

g(x) = αf(x) + β

其中:

  • f(x) 是输入图像中的像素值。
  • g(x) 是输出图像中的像素值。
  • α 是缩放因子,用于控制对比度。
  • β 是偏移量,用于控制亮度。

线性灰度变换的目的

线性灰度变换主要用于以下几个方面:

  1. 调整对比度:通过调整 α 的值,可以使图像的对比度变强或变弱。
  2. 调整亮度:通过调整 β 的值,可以使图像整体变得更亮或更暗。

OpenCV中的实现方法

在OpenCV中,可以使用多种方法来实现线性变换,以下是两种常用的方法:

方法一:使用 convertTo 函数

convertTo 函数可以直接应用于矩阵,对每个像素值进行线性变换。

// 读取图像
cv::Mat src = cv::imread("input_image.jpg", cv::IMREAD_GRAYSCALE);
// 定义线性变换参数
double alpha = 1.5; // 对比度因子
double beta = 50;   // 亮度偏移量
// 创建输出图像
cv::Mat dst;
// 应用线性变换
src.convertTo(dst, -1, alpha, beta);

方法二:手动遍历每个像素

如果需要更多的控制,可以手动遍历每个像素并应用线性变换。

// 读取图像
cv::Mat src = cv::imread("input_image.jpg", cv::IMREAD_GRAYSCALE);
// 定义线性变换参数
double alpha = 1.5; // 对比度因子
double beta = 50;   // 亮度偏移量
// 创建输出图像
cv::Mat dst = cv::Mat::zeros(src.size(), src.type());
// 遍历每个像素并应用线性变换
for (int y = 0; y < src.rows; y++) {
    for (int x = 0; x < src.cols; x++) {
        dst.at<uchar>(y, x) = std::min(255, std::max(0, (int)(alpha * src.at<uchar>(y, x) + beta)));
    }
}

实现细节:

  1. 数据类型:在进行线性变换时需要注意数据类型。通常情况下,灰度图像的像素值类型为 uchar(无符号8位整数),因此需要确保变换后的值在 [0, 255] 范围内。
  2. 饱和操作:在手动实现时,需要使用 std::minstd::max 函数来确保像素值不会超出有效范围。

实验代码

方法二:灰度图像线性变换

#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

cv::Mat linearTransform(cv::Mat srcImage, float a, int b) {
    if (srcImage.empty()) {
        std::cout << "No data!" << std::endl;
    }
    const int nRows = srcImage.rows;
    const int nCols = srcImage.cols;
    cv::Mat resultImage = cv::Mat::zeros(srcImage.size(), srcImage.type());
    // 图像元素遍历
    for (int i = 0; i < nRows; i++) {
        for (int j = 0; j < nCols; j++) {
            resultImage.at<uchar>(i, j) = saturate_cast<uchar>(a * (srcImage.at<uchar>(i, j)) + b);
        }
    }
    return resultImage;
}

int main() {
    // 图像获取及验证
    cv::Mat srcImage = cv::imread("123.jpg", cv::IMREAD_GRAYSCALE);
    if (!srcImage.data)
        return -1;
    cv::imshow("原图", srcImage);
    cv::waitKey(2000);
    // 线性变换
    float a = 1.2;
    int b = 50;
    cv::Mat new_image = linearTransform(srcImage, a, b);
    cv::imshow("效果图", new_image);
    cv::waitKey(0);
    return 0;
}

saturate_cast 函数在 OpenCV 中被用来进行类型转换,同时确保转换后的值不会超出目标类型的表示范围。这个函数特别适用于图像处理中的像素值转换,以避免溢出或下溢(underflow)的问题。

方法二:彩色图像线性变换

#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

cv::Mat linearTransform(cv::Mat srcImage, float a, int b) {
    if (srcImage.empty()) {
        std::cout << "No data!" << std::endl;
    }
    const int nRows = srcImage.rows;
    const int nCols = srcImage.cols;
    cv::Mat resultImage = cv::Mat::zeros(srcImage.size(), srcImage.type());
    // 图像元素遍历
    for (int i = 0; i < nRows; i++) {
        for (int j = 0; j < nCols; j++) {
            for (int c = 0; c < 3; c++) {
                resultImage.at<Vec3b>(i, j)[c] = saturate_cast<uchar>(a * (srcImage.at<Vec3b>(i, j)[c]) + b);
            }
        }
    }
    return resultImage;
}

int main() {
    // 图像获取及验证
    cv::Mat srcImage = cv::imread("123.jpg");
    if (!srcImage.data)
        return -1;
    cv::imshow("原图", srcImage);
    //cv::waitKey(0);
    // 线性变换
    float a = 1.2;
    int b = 50;
    cv::Mat new_image = linearTransform(srcImage, a, b);
    cv::imshow("效果图", new_image);
    cv::waitKey(0);
    return 0;
}

运行结果

方法一:Mat::convertTo

此外利用 Mat::convertTo 函数进行数据类型转换和简单的线性变换。

在OpenCV中,Mat::convertTo 函数用于将一个矩阵(通常是图像)的数据类型转换为另一种数据类型,并且可以选择性地对矩阵中的每个元素进行缩放和偏移。这个函数非常有用,特别是在需要改变图像数据类型、调整像素值范围或进行线性变换的时候。

函数原型
void Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0) const;
参数说明
OutputArray m:目标矩阵。如果在调用该函数之前目标矩阵的尺寸或类型不合适,那么该矩阵会被重新分配内存。
int rtype:期望的目标矩阵类型或深度。这里“深度”指的是每个元素的数据类型(如 CV_8U、CV_32F 等)。通道数保持不变。如果 rtype 是负数,则目标矩阵将具有与源矩阵相同的类型。
double alpha:可选的比例因子,默认值为 1。该参数用于缩放矩阵中的每个元素。
double beta:可选的偏移量,默认值为 0。该参数用于给缩放后的每个元素加上一个常数值。
工作原理
Mat::convertTo 方法根据提供的参数对矩阵中的每个元素执行以下操作:
1. 每个元素先乘以 alpha。
2. 然后加上 beta。
3. 最后,将结果转换为目标类型 rtype,并且使用 saturate_cast<> 函数确保结果值不会超出目标类型的有效范围。
转换公式:
m(x,y) = saturate_cast<rType>(α⋅src(x,y)+β)
这里的 saturate_cast<> 函数的作用是将结果裁剪到目标类型能够表示的最小值和最大值之间,以避免溢出。

例题

下面是一个简单的示例,演示如何使用OpenCV和C++实现灰度图像的线性变换。我们将实现以下功能:

  1. 读取灰度图像。
  2. 应用线性变换:通过增加亮度和调整对比度。
  3. 显示和保存变换后的图像。
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int main() {
    // 图像获取及验证
    cv::Mat srcImage = cv::imread("09011913.jpeg", cv::IMREAD_GRAYSCALE);
    if (!srcImage.data)
        return -1;
    //显示变换前的原图
    namedWindow("原图", WINDOW_NORMAL);
    cv::imshow("原图", srcImage);

    // 定义线性变换的参数
    double alpha = 1.5; // 对比度因子
    double beta = 50;   // 亮度偏移量

    // 创建输出图像
    cv::Mat dst_image;
    // 应用线性变换
    srcImage.convertTo(dst_image, -1, alpha, beta);
    // 显示变换后的图像
    namedWindow("效果图", WINDOW_NORMAL);
    cv::imshow("效果图", dst_image);
    cv::waitKey(0);
    return 0;
}

代码解释:

  1. 读取图像:使用 cv::imread 函数读取输入图像,并将其转换为灰度图像(IMREAD_GRAYSCALE)。
  2. 定义线性变换参数:
  • alpha:对比度因子,用于调整图像的对比度。alpha > 1 会使图像更亮,alpha < 1 会使图像更暗。
  • beta:亮度偏移量,用于增加图像的亮度。beta > 0 会使图像更亮,beta < 0 会使图像更暗。
  1. 创建输出图像:创建一个新的 cv::Mat 对象来存储变换后的图像。
  2. 应用线性变换:使用 convertTo 函数来应用线性变换。convertTo 函数的第一个参数是输出图像,第二个参数是深度(-1 表示保持源图像的深度不变),第三个参数是对比度因子(alpha),第四个参数是亮度偏移量(beta)。
  3. 显示图像:使用 cv::imshow 函数显示原始图像和变换后的图像。
  4. 保存图像:使用 cv::imwrite 函数保存变换后的图像到磁盘。

在OpenCV中,线性灰度变换是一种常见的图像处理技术,用于调整图像的对比度和亮度。这种变换通过简单的线性函数来调整图像中的像素值,从而达到增强或减弱图像对比度的效果。通过调整 alpha 和 beta 的值,可以改变图像的对比度和亮度,从而实现不同的线性变换效果。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号