OpenCV改變圖像的對比度和亮度

2018-08-29 14:27 更新

目標(biāo)

在本教程中,您將學(xué)習(xí)如何:

  • 訪問像素值
  • 用零初始化矩陣
  • 了解cv :: saturate_cast是什么,為什么它是有用的
  • 獲取有關(guān)像素變換的一些很酷的信息
  • 在一個實際的例子中提高圖像的亮度

理論

注意
下面的解釋屬于Richard Szeliski 的“ 計算機視覺:算法與應(yīng)用 ”一書

圖像處理

  • 一般的圖像處理算子是采用一個或多個輸入圖像并產(chǎn)生輸出圖像的函數(shù)。
  • 圖像變換可以看作:點運算符(像素變換)鄰里(區(qū)域)運營商

像素變換

  • 在這種圖像處理變換中,每個輸出像素的值僅取決于相應(yīng)的輸入像素值(可能是一些全局采集的信息或參數(shù))。
  • 這些操作者的示例包括亮度和對比度調(diào)整以及顏色校正和變換。

亮度和對比度調(diào)整

  • 兩個常用的點處理是乘法和加法:

QQ圖片20170829141242

  • 參數(shù)和\ beta通常稱為增益和偏置參數(shù); 有時這些參數(shù)被分別控制對比度和亮度。α>0β
  • 您可以將視為源圖像像素,g(x)作為輸出圖像像素。然后,我們可以更方便地將表達(dá)式寫成:f(x)g(x)

QQ圖片20170829141310

其中和j表示像素位于第i行和第j列。ij

Code

以下代碼執(zhí)行:g(i,j)=α?f(i,j)+β


#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main( int argc, char** argv )
{
    double alpha = 1.0; /*< Simple contrast control */
    int beta = 0;       /*< Simple brightness control */
    String imageName("../data/lena.jpg"); // by default
    if (argc > 1)
    {
        imageName = argv[1];
    }
    Mat image = imread( imageName );
    Mat new_image = Mat::zeros( image.size(), image.type() );
    cout << " Basic Linear Transforms " << endl;
    cout << "-------------------------" << endl;
    cout << "* Enter the alpha value [1.0-3.0]: "; cin >> alpha;
    cout << "* Enter the beta value [0-100]: ";    cin >> 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 );
            }
        }
    }
    namedWindow("Original Image", WINDOW_AUTOSIZE);
    namedWindow("New Image", WINDOW_AUTOSIZE);
    imshow("Original Image", image);
    imshow("New Image", new_image);
    waitKey();
    return 0;
}

說明

  • 我們首先創(chuàng)建參數(shù)來保存用戶要輸入的和\ beta:αβ
    double alpha = 1.0; /*< Simple contrast control */
    int beta = 0;       /*< Simple brightness control */
  • 我們使用cv :: imread加載圖像并將其保存在Mat對象中:
    String imageName("../data/lena.jpg"); // by default
    if (argc > 1)
    {
        imageName = argv[1];
    }
    Mat image = imread( imageName );
  • 現(xiàn)在,由于我們會對這個圖像進(jìn)行一些轉(zhuǎn)換,所以我們需要一個新的Mat對象來存儲它。此外,我們希望這具有以下功能:
  1. 初始像素值等于零
  2. 與原始圖像相同的大小和類型
        Mat new_image = Mat :: zeros(image.size(),image.type());

    我們觀察到cv :: Mat :: zeros返回基于image.size()image.type()的Matlab風(fēng)格的零初始化器,

    • 現(xiàn)在,要執(zhí)行我們將訪問圖像中的每個像素。由于我們使用BGR圖像,我們將每像素(B,G和R)有三個值,因此我們也將分別訪問它們。這是代碼片段:g(i,j)=α?f(i,j)+β
          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 );
                  }
              }
          }

    請注意以下事項:

      1. 初始像素值等于零
      2. 與原始圖像相同的大小和類型
        • 最后,我們創(chuàng)建窗口并顯示圖像,通常的方式。
        •     namedWindow("Original Image", WINDOW_AUTOSIZE);
              namedWindow("New Image", WINDOW_AUTOSIZE);
              imshow("Original Image", image);
              imshow("New Image", new_image);
              waitKey();
        注意
        而不是使用for循環(huán)訪問每個像素,我們可以簡單地使用這個命令:
        image.convertTo(new_image,-1,alpha,beta);
        

             其中cv :: Mat :: convertTo將有效地執(zhí)行* new_image = a * image + beta *。但是,我們想告訴你如何訪問每個像素。在任何情況下,兩種方法都給出相同的結(jié)果,但是convertTo是更優(yōu)化的,并且工作得更快。

        結(jié)果

        運行我們的代碼并使用和\ beta = 50α=2.2β=50

        $ ./BasicLinearTransforms lena.jpg
        Basic Linear Transforms
        -------------------------
        * Enter the alpha value [1.0-3.0]: 2.2
        * Enter the beta value [0-100]: 50

        我們得到這個:

        Basic_Linear_Transform_Tutorial_Result_big

        實際例子

        在本段中,我們將通過調(diào)整圖像的亮度和對比度來實踐我們學(xué)到的來校正曝光不足的圖像。我們還將看到另一種技術(shù)來校正稱為伽馬校正的圖像的亮度。

        亮度和對比度調(diào)整

        增加(/減少)值將為每個像素添加(/減)一個常量值。像素值超出[0; 255]范圍將飽和(即像素值高于(/小于255)(/ 0)將被鉗位到255(/ 0))。β

        Basic_Linear_Transform_Tutorial_hist_beta

        在淺灰色,原始圖像的直方圖,在深灰色當(dāng)亮度= 80在Gimp

        直方圖表示每個顏色級別具有該顏色級別的像素數(shù)。黑暗的圖像將具有許多具有低顏色值的像素,因此直方圖將在其左部分呈現(xiàn)峰值。當(dāng)添加恒定偏差時,直方圖向右移動,因為我們向所有像素添加了一個恒定的偏置。

        該參數(shù)將修改水平如何傳播。如果\ alpha <1,顏色級別將被壓縮,結(jié)果將是對比度較小的圖像。αα<1

        Basic_Linear_Transform_Tutorial_hist_alpha

        在淺灰色,原始圖像的直方圖,在Gimp中對比度<0時,呈深灰色

        請注意,這些直方圖是使用Gimp軟件中的“亮度 - 對比度”工具獲得的。亮度工具應(yīng)該與偏置參數(shù)相同,但是對比度工具似乎與\ alpha增益不同,其中輸出范圍似乎以Gimp為中心(您可以注意到先前的直方圖)。βα

        可以發(fā)現(xiàn),使用偏置可以提高亮度,但是同時,由于對比度會降低,圖像會出現(xiàn)輕微的面紗。該\阿爾法收益可以用來diminue這種效果,但由于飽和,我們將失去原有的明亮區(qū)域的一些細(xì)節(jié)。βα

        伽瑪矯正

        伽馬校正可以用于通過使用輸入值和映射的輸出值之間的非線性變換來校正圖像的亮度:

        QQ圖片20170829142107

        由于該關(guān)系是非線性的,因此對于所有像素的效果將不同,并且將取決于它們的原始值。

        Basic_Linear_Transform_Tutorial_gamma

        繪制不同的伽瑪值

        當(dāng),原始的暗區(qū)域會更亮,直方圖將向右移動,而\ gamma> 1則會相反。γ<1γ>1

        更正曝光不足的圖像

        以下圖像已更正:和\ beta = 40。α=1.3β=40

        Basic_Linear_Transform_Tutorial_linear_transform_correction

        維基百科,自由的百科全書[CC BY-SA 3.0]

        整體亮度得到改善,但您可以注意到,由于實施的數(shù)字飽和度,云彩現(xiàn)在已經(jīng)飽和了(突出顯示拍攝中的剪輯)。

        以下圖像已更正:。γ=0.4

        Basic_Linear_Transform_Tutorial_gamma_correction

        維基百科,自由的百科全書[CC BY-SA 3.0]

        伽馬校正應(yīng)傾向于增加較少的飽和效應(yīng),因為映射是非線性的,并且沒有像以前的方法那樣的數(shù)值飽和。

        Basic_Linear_Transform_Tutorial_histogram_compare

        左:直方圖alpha,β校正; 中心:原始圖像的直方圖; 右:伽馬校正后的直方圖

        上圖比較了三個圖像的直方圖(三個直方圖之間的y范圍是不一樣的)。您可以注意到,大多數(shù)像素值位于原始圖像的直方圖的較低部分。在,更正后,由于飽和度以及右側(cè)的偏移,我們可以在255觀察到一個高峰。在伽馬校正之后,直方圖向右移動,但是暗區(qū)域中的像素比明亮區(qū)域中的像素更大偏移(參見伽馬曲線圖)。αβ

        在本教程中,您已經(jīng)看到了兩種簡單的方法來調(diào)整圖像的對比度和亮度。它們是基本技術(shù),不用于替代光柵圖形編輯器!

        Code

        本教程的代碼在這里。伽馬校正代碼:

            Mat LookUpTable(1,256,CV_8U);
            uchar * p = lookUpTable.ptr();
            for(int i = 0; i <256; ++ i)
                p [i] = saturate_cast <uchar>(pow(i / 255.0,gamma_)* 255.0);
            Mat res = img.clone();
            LUT(img,lookUpTable,res);

        查詢表用于提高計算性能,因為只需要計算256個值。

        額外的資源

        以上內(nèi)容是否對您有幫助:
        在線筆記
        App下載
        App下載

        掃描二維碼

        下載編程獅App

        公眾號
        微信公眾號

        編程獅公眾號