Changing the contrast and brightness of an image!

此为OpenCV官方教程的个人翻译

目标

在本教程中,您将学习如何:

  • 访问像素值
  • 使用零初始化矩阵
  • 了解saturate_cast以及为什么它有用
  • 获取有关像素转换的一些很酷的信息

理论

注意:下面的理论源自Richard Szeliski的《Computer Vision: Algorithms and Applications》一书。

图像处理

  • 通用图像处理运算符是输入一个或多个图像,并生成输出图像的函数
  • 图像转换可以视作:
    • Point operators (pixel transforms) (像素级别的转换) (点运算符)
    • Neighborhood (area-based) operators (区域级别的转换)(邻域运算符)

像素转换

  • 在这种图像处理变换中,每个输出像素的值仅取决于相应的输入像素值(加上一些可能全局收集的信息或参数)。
  • 此类运算符的包括亮度和对比度调整以及颜色校正和变换。

亮度和对比度调整

  • 两个常用的点过程(point process)为乘法常数加法

    \[g(x)=\alpha f(x) + \beta \]

  • 参数\(\alpha >0\),并且\(\beta\)经常被叫做增益和偏置参数(gain and bias parameters);有时这些参数分别控制对比度和亮度

  • 您可以将\(f(x)\)是做原图像像素而将\(g(x)\)视作输出图像像素,然后我们便可以将表达式改写为:

    \[g(i,j)=\alpha f(i,j)+\beta \]

    其中\(i\)\(j\)分别指出了像素的行与列.

代码

下面的代码进行了\(g(i,j)=\alpha f(i,j)+\beta\)操作:

/*
 * @LastEditors: 帝皇の惊
 * @Date: 2022-06-26 16:17:00
 * @Description: Edit Here
 * @LastEditTime: 2022-06-26 16:57:00
 */
#include <iostream>
#include "opencv.hpp"

using namespace cv;

double alpha;  //简易对比度控制
int beta;      //简易亮度控制

int main(int argc, char** argv) {
    // Read image
    Mat image = imread("E:\\Work\\Visual Studio Code\\fengmian.jpg");
    Mat new_image = Mat::zeros(image.size(), image.type());
    // "initialize values"
    std::cout << "Basic Linear Transforms" << std::endl;
    std::cout << "-----------------------" << std::endl;
    std::cout << "* Enter the alpha value [1.0 - 3.0]: ";
    std::cin >> alpha;
    std::cout << "* Enter the beta value [0 - 100]:";
    std::cin >> beta;

    // 进行操作g(i,j)=alpha*f(i,j)+beta
    for (int y = 0; y < image.rows; y++) {
        for (int x = 0; x < image.cols; x++) {
            for (int c = 0; c < 3; c++) {
                new_image.at<Vec3b>(y, x)[c] = saturate_cast<uchar>(
                    alpha * (image.at<Vec3b>(y, x)[c]) + beta);
            }
        }
    }

    // Craete Window
    namedWindow("Original Image", WINDOW_NORMAL);
    namedWindow("New Image", WINDOW_NORMAL);

    // Show Stuff
    imshow("Original Image", image);
    imshow("New Image", new_image);
    waitKey(0);
    return 0;
}

解释

  1. 我们首先创建并保存\(\alpha,\beta\),这两个都是用户输入的参数:

    double alpha;
    int beta;
    
  2. 我们使用 imread 加载图像并将其保存在 Mat 对象中:

    Mat image = imread("E:\\Work\\Visual Studio Code\\fengmian.jpg");
    
  3. 现在,由于我们将对此图像进行一些转换,因此我们需要一个新的 Mat 对象来存储它。此外,我们希望它具有以下特点:

    • 初始像素值等于零
    • 与原始图像相同的大小和类型
    Mat new_image = Mat::zeros( image.size(), image.type() );
    

    我们观察到 Mat::zeros 返回一个基于 image.size() 和 image.type() 的 Matlab 样式的零初始值设定项。

  4. 现在,要执行该操作\(g(x)=\alpha f(x) + \beta\),我们将访问图像中的每个像素。由于我们使用的是BGR图像,因此每个像素将有三个值(B,G和R),因此我们也将单独访问它们:

    for( int y = 0; y < image.rows; y++ )
       { for( int x = 0; x < image.cols; x++ )
            { for( int c = 0; c < 3; c++ )
                 { new_image.at<Vec3b>(y,x)[c] =
                             saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta ); }
       }
       }
    

    请注意以下几点:

    • 为了访问图像中的每个像素,我们使用以下语法:image.at(y,x)[c],其中y是行,x是列,c是R,G或B(0,1或2)。
    • 由于该操作的运算结果可能无效或超出范围,因此我们使用saturate_cast来确保值有效。
  5. 最后,我们创建窗口显示图像。

    namedWindow("Original Image", 1);
    namedWindow("New Image", 1);
    
    imshow("Original Image", image);
    imshow("New Image", new_image);
    
    waitKey(0);
    

注意:与其使用 for 循环来访问每个像素,不如简单地使用以下命令:

image.convertTo(new_image, -1, alpha, beta);

其中 convertTo 将有效地执行 new_image = a*image + beta。但是,我们想向您展示如何访问每个像素。无论如何,这两种方法都给出了相同的结果,但convertTo更加优化,并且工作速度更快。

结果

1.png

posted @ 2022-06-26 17:19  帝皇の惊  阅读(40)  评论(0)    收藏  举报