目标

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

  • 访问像素值
  • 用零初始化矩阵
  • 了解cv :: saturate_cast的作用以及它有用的原因
  • 获取有关像素转换的一些很酷的信息
  • 在实际例子中提高图像的亮度

理论

注意,以下解释属于Richard Szeliski 所着的Computer Vision:Algorithms and Applications一书

图像处理

  • 一般图像处理操作符是获取一个或多个输入图像并产生输出图像的功能。
  • 图像变换可以看作:
    • 点运算(像素变换)-
    • Point operators (pixel transforms)
    • 邻域操作
    • Neighborhood (area-based) operators

像素转换

  • 在这种图像处理变换中,每个输出像素的值仅取决于相应的输入像素值。
  • 这种算子的例子包括亮度对比度调整以及颜色校正和变换

亮度和对比度调整

  • 两个常用的点过程是乘法加法与常量:

  • 参数α>0和β通常称为增益偏差参数(the gain and bias parameters),这些参数分别控制对比度亮度
  • 假设f(x)作为源图像像素,g(x)作为输出图像像素,上述表达式可以改写为:

    其中,i和j表示像素位于i行和第j

Coding

C ++

  • 完整代码:
/*** @file BasicLinearTransforms.cpp* @brief Simple program to change contrast and brightness* @author OpenCV team*/#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>// we're NOT "using namespace std;" here, to avoid collisions between the beta variable and std::beta in c++17
using std::cin;
using std::cout;
using std::endl;
using namespace cv;/*** @function main* @brief Main function*/
int main( int argc, char** argv )
{/// Read image given by user//! [basic-linear-transform-load]CommandLineParser parser( argc, argv, "{@input | ../data/lena.jpg | input image}" );Mat image = imread( parser.get<String>( "@input" ) );if( image.empty() ){cout << "Could not open or find the image!\n" << endl;cout << "Usage: " << argv[0] << " <Input image>" << endl;return -1;}//! [basic-linear-transform-load]//! [basic-linear-transform-output]Mat new_image = Mat::zeros( image.size(), image.type() );//! [basic-linear-transform-output]//! [basic-linear-transform-parameters]double alpha = 1.0; /*< Simple contrast control */int beta = 0;       /*< Simple brightness control *//// Initialize valuescout << " 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;//! [basic-linear-transform-parameters]/// Do the operation new_image(i,j) = alpha*image(i,j) + beta/// Instead of these 'for' loops we could have used simply:/// image.convertTo(new_image, -1, alpha, beta);/// but we wanted to show you how to access the pixels :)//! [basic-linear-transform-operation]for( int y = 0; y < image.rows; y++ ) {for( int x = 0; x < image.cols; x++ ) {for( int c = 0; c < image.channels(); c++ ) {new_image.at<Vec3b>(y,x)[c] =saturate_cast<uchar>( alpha*image.at<Vec3b>(y,x)[c] + beta );}}}//! [basic-linear-transform-operation]//! [basic-linear-transform-display]/// Show stuffimshow("Original Image", image);imshow("New Image", new_image);/// Wait until user press some keywaitKey();//! [basic-linear-transform-display]return 0;
}

说明

  • 我们使用cv :: imread加载图像并将其保存在Mat对象中:
  CommandLineParser parser( argc, argv, "{@input | ../data/lena.jpg | input image}" );Mat image = imread( parser.get<String>( "@input" ) );if( image.empty() ){cout << "Could not open or find the image!\n" << endl;cout << "Usage: " << argv[0] << " <Input image>" << endl;return -1;}
  • 现在,由于我们将对此图像进行一些转换,因此我们需要一个新的Mat对象来存储它。此外,我们希望它具有以下功能:

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

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

  • 我们现在问α的值和β 由用户输入:
 double alpha = 1.0; /*< Simple contrast control */int beta = 0;       /*< Simple brightness control */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;
  • 现在,执行操作g(i,j)= α · f(i,j)+ b我们将访问图像中的每个像素。由于我们使用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 < image.channels(); c++ ) {new_image.at<Vec3b>(y,x)[c] =saturate_cast<uchar>( alpha*image.at<Vec3b>(y,x)[c] + beta );}}}

请注意以下内容(仅限C ++代码):

  • 要访问图像中的每个像素,我们使用以下语法:image.at <Vec3b>(y,x)[c]其中y是行,x是列,c是R,G或B(0,1或2)。
  • 由于操作α&CenterDot;&p(i,j)+ b可以给出超出范围的值或不是整数(如果α是浮动),我们使用cv :: saturate_cast来确保值是有效的。
  • 最后,我们创建窗口并以通常的方式显示图像。
    imshow("Original Image", image);imshow("New Image", new_image);waitKey();

注意

我们可以简单地使用此命令,而不是使用for循环来访问每个像素:

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

其中cv :: Mat :: convertTo将有效地执行* new_image = a * image + beta *。但是,我们想向您展示如何访问每个像素。在任何情况下,两种方法都给出相同的结果,但convertTo更优化,工作速度更快。


结果

  • 运行我们的代码并使用α=2.2和β= 50

    $ ./BasicLinearTransforms lena.jpg

    基本线性变换

    -------------------------

    *输入alpha值[1.0-3.0]:2.2

    *输入beta值[0-100]:50

  • 我们得到这个:

例子

在本段中,我们将通过调整图像的亮度和对比度来实践我们所学到的校正曝光不足图像的方法。我们还将看到另一种技术来校正称为伽马校正图像亮度。

亮度和对比度调整

增加(/减少)β将为每个像素添加(/减去)一个常量值。像素值在[0; 255]范围将饱和(即,高于(/小于)255(/ 0)的像素值将被截止到255(/ 0))。

原始图像的直方图,当Gimp中亮度= 80时为深灰色

直方图针对每个颜色级别表示具有该颜色级别的像素的数量。暗图像将具有许多具有低颜色值的像素,因此直方图将在其左侧部分呈现峰值。当添加恒定偏置时,直方图向右移动,因为我们已经为所有像素添加了恒定偏置。

在一个参数将修改级别的传播方式。如果α<1,颜色等级将被压缩,结果将是对比度较低的图像。

原始图像的直方图,当在Gimp中对比度<0时为深灰色

请注意,这些直方图是使用Gimp软件中的亮度 - 对比度工具获得的。亮度工具应与β相同偏差参数但对比工具似乎与α不同 输出范围似乎以Gimp为中心的增益(正如您在前面的直方图中所注意到的那样)。

β可能会发生偏差会改善亮度,但同时图像会出现轻微的面纱,因为对比度会降低。该α 增益可以用来减少这种效果,但由于饱和,我们将失去原始明亮区域的一些细节。


伽玛校正

通过在输入值和映射的输出值之间使用非线性变换,Gamma校正可用于校正图像的亮度:

由于此关系是非线性的,因此对于所有像素,效果将不相同,并且将取决于它们的原始值。

绘制不同的伽玛值,当γ< 1中,原始的暗区将是明亮,直方图将被向右移位,而这将是与相对的γ> 1。

纠正曝光不足的图像

以下图像已更正为:α=1.3和β= 40。

整体亮度已得到改善,但您可以注意到,经过对比度调整之后,暗部细节得到了明显改善,与此同时,高亮度部分的云已经过饱和,使得天空颜色失真。

以下图像已用:γ校正= 0.4。

伽马校正应该倾向于增加图像的动态对比度,因为映射是非线性的并且不存在如先前方法中那样的数值饱和。

左:alpha,beta校正后的直方图;  中:原始图像的直方图; 右:伽马校正后的直方图

上图比较了三幅图像的直方图(三个直方图之间的y范围不同)。您可以注意到,大多数像素值位于原始图像直方图的下半部分。在α之后,b校正,由于饱和以及右移,我们可以观察到255处的大峰值。在伽马校正之后,直方图向右移动但是暗区域中的像素比亮区域中的像素更加偏移(参见伽马曲线图)。


伽马变换代码段:

C++

 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);

完整代码:

#include <iostream>
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"// we're NOT "using namespace std;" here, to avoid collisions between the beta variable and std::beta in c++17
using std::cout;
using std::endl;
using namespace cv;namespace
{
/** Global Variables */
int alpha = 100;
int beta = 100;
int gamma_cor = 100;
Mat img_original, img_corrected, img_gamma_corrected;void basicLinearTransform(const Mat &img, const double alpha_, const int beta_)
{Mat res;img.convertTo(res, -1, alpha_, beta_);hconcat(img, res, img_corrected);imshow("Brightness and contrast adjustments", img_corrected);
}void gammaCorrection(const Mat &img, const double gamma_)
{CV_Assert(gamma_ >= 0);//! [changing-contrast-brightness-gamma-correction]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);//! [changing-contrast-brightness-gamma-correction]hconcat(img, res, img_gamma_corrected);imshow("Gamma correction", img_gamma_corrected);
}void on_linear_transform_alpha_trackbar(int, void *)
{double alpha_value = alpha / 100.0;int beta_value = beta - 100;basicLinearTransform(img_original, alpha_value, beta_value);
}void on_linear_transform_beta_trackbar(int, void *)
{double alpha_value = alpha / 100.0;int beta_value = beta - 100;basicLinearTransform(img_original, alpha_value, beta_value);
}void on_gamma_correction_trackbar(int, void *)
{double gamma_value = gamma_cor / 100.0;gammaCorrection(img_original, gamma_value);
}
}int main( int argc, char** argv )
{CommandLineParser parser( argc, argv, "{@input | ../data/lena.jpg | input image}" );img_original = imread( parser.get<String>( "@input" ) );if( img_original.empty() ){cout << "Could not open or find the image!\n" << endl;cout << "Usage: " << argv[0] << " <Input image>" << endl;return -1;}img_corrected = Mat(img_original.rows, img_original.cols*2, img_original.type());img_gamma_corrected = Mat(img_original.rows, img_original.cols*2, img_original.type());hconcat(img_original, img_original, img_corrected);hconcat(img_original, img_original, img_gamma_corrected);namedWindow("Brightness and contrast adjustments");namedWindow("Gamma correction");createTrackbar("Alpha gain (contrast)", "Brightness and contrast adjustments", &alpha, 500, on_linear_transform_alpha_trackbar);createTrackbar("Beta bias (brightness)", "Brightness and contrast adjustments", &beta, 200, on_linear_transform_beta_trackbar);createTrackbar("Gamma correction", "Gamma correction", &gamma_cor, 200, on_gamma_correction_trackbar);on_linear_transform_alpha_trackbar(0, 0);on_gamma_correction_trackbar(0, 0);waitKey();imwrite("linear_transform_correction.png", img_corrected);imwrite("gamma_correction.png", img_gamma_corrected);return 0;
}

Python

lookUpTable = np.empty((1,256), np.uint8)for i in range(256):lookUpTable[0,i] = np.clip(pow(i / 255.0, gamma) * 255.0, 0, 255)res = cv.LUT(img_original, lookUpTable)

完整代码:

from __future__ import print_function
from __future__ import division
import cv2 as cv
import numpy as np
import argparsealpha = 1.0
alpha_max = 500
beta = 0
beta_max = 200
gamma = 1.0
gamma_max = 200def basicLinearTransform():res = cv.convertScaleAbs(img_original, alpha=alpha, beta=beta)img_corrected = cv.hconcat([img_original, res])cv.imshow("Brightness and contrast adjustments", img_corrected)def gammaCorrection():## [changing-contrast-brightness-gamma-correction]lookUpTable = np.empty((1,256), np.uint8)for i in range(256):lookUpTable[0,i] = np.clip(pow(i / 255.0, gamma) * 255.0, 0, 255)res = cv.LUT(img_original, lookUpTable)## [changing-contrast-brightness-gamma-correction]img_gamma_corrected = cv.hconcat([img_original, res]);cv.imshow("Gamma correction", img_gamma_corrected);def on_linear_transform_alpha_trackbar(val):global alphaalpha = val / 100basicLinearTransform()def on_linear_transform_beta_trackbar(val):global betabeta = val - 100basicLinearTransform()def on_gamma_correction_trackbar(val):global gammagamma = val / 100gammaCorrection()parser = argparse.ArgumentParser(description='Code for Changing the contrast and brightness of an image! tutorial.')
parser.add_argument('--input', help='Path to input image.', default='lena.jpg')
args = parser.parse_args()img_original = cv.imread(cv.samples.findFile(args.input))
if img_original is None:print('Could not open or find the image: ', args.input)exit(0)img_corrected = np.empty((img_original.shape[0], img_original.shape[1]*2, img_original.shape[2]), img_original.dtype)
img_gamma_corrected = np.empty((img_original.shape[0], img_original.shape[1]*2, img_original.shape[2]), img_original.dtype)img_corrected = cv.hconcat([img_original, img_original])
img_gamma_corrected = cv.hconcat([img_original, img_original])cv.namedWindow('Brightness and contrast adjustments')
cv.namedWindow('Gamma correction')alpha_init = int(alpha *100)
cv.createTrackbar('Alpha gain (contrast)', 'Brightness and contrast adjustments', alpha_init, alpha_max, on_linear_transform_alpha_trackbar)
beta_init = beta + 100
cv.createTrackbar('Beta bias (brightness)', 'Brightness and contrast adjustments', beta_init, beta_max, on_linear_transform_beta_trackbar)
gamma_init = int(gamma * 100)
cv.createTrackbar('Gamma correction', 'Gamma correction', gamma_init, gamma_max, on_gamma_correction_trackbar)on_linear_transform_alpha_trackbar(alpha_init)
on_gamma_correction_trackbar(gamma_init)cv.waitKey()

查找线性表用于提高计算性能,因为只需要计算一次256个值。

(10)图像增强- -- 图像对比度和亮度调整方法与实现相关推荐

  1. OpenCV学习笔记(三):图像对比度、亮度调整源码

    OpenCV学习笔记(三):图像对比度.亮度调整源码 主函数: #include <opencv2/opencv.hpp>using namespace cv;using namespac ...

  2. OpenCV3之——图像对比度,亮度调整

    首先了解一下算子的概念,一般的图像处理算子都是一个函数,它接受一个或多个输入图像,并产生输出图像.下面是算子的一般形式: g(x) = h( f(x) )  或者  g(x) = h( f0(x)·· ...

  3. OpenCV之图像对比度与亮度调整(C++实现)

    图像对比度和亮度的调整,属于图像处理中的点操作,其有一个特点:仅仅根据输入像素的值,来计算相应的输出像素值.这列蒜子包括亮度和对比度调整.颜色校正和变换. 最常用的点操作是乘以一个常数,再加上一个常数 ...

  4. 图像 对比度、亮度调整

    #include "stdafx.h"#include <opencv2\highgui\highgui.hpp> #include <opencv2\core\ ...

  5. OpenCV-Python调整图像对比度和带文字白纸照片背景漂白方法

    一.引言 在前面我们介绍了直方图均衡可以调整图像的对比度,那么还有没有其他方式调整对比度呢?答案是肯定的,今天就来招硬核的. 二.对比度调整的硬核方法 这招硬核方法就是参考灰度图像的阈值处理,我们知道 ...

  6. matlab 增加图像对比度_计算机视觉学习笔记6 图像直方图与直方图均衡化

    图像的直方图 图像直方图表示图像中每一种像素的个数,反映了图像中每种像素值出现的频率,是图像的基本统计特征之一,具有平移,旋转,缩放不变性,广泛应用于图像处理的各个领域.比如灰度图像的阈值分割,基于颜 ...

  7. OpenCV—Python 对比度与亮度调整

    对比度与亮度调整方法1 对图片对比度和亮度的调整一般通过下面公式计算: g(x,y)=a∗f(x,y)+bg(x,y) = a*f(x,y)+bg(x,y)=a∗f(x,y)+b f(x,y)f(x, ...

  8. python opencv图像对比度增强_图像增强、锐化, Python-OpenCV 来实现 4 种方法!

    图像增强目的使得模糊图片变得更加清晰.图片模糊的原因是因为像素灰度差值变化不大,如片各区域产生视觉效果似乎都是一样的, 没有较为突出的地方,看起来不清晰的感觉 解决这个问题的最直接简单办法,放大像素灰 ...

  9. python增强对比度_python增加图像对比度的方法

    python增加图像对比度的方法 来源:中文源码网    浏览: 次    日期:2019年11月5日 [下载文档:  python增加图像对比度的方法.txt ] (友情提示:右键点上行txt文档名 ...

  10. 目标检测:python实现多种图像数据增强的方法(光照,对比度,遮挡,模糊)

    图像数据增强的内容(可根据需要自定义选择): 1.直方图均衡化 2.clahe自适应对比度直方图均衡化 3.白平衡 4.亮度增强 5.亮度,饱和度,对比度增强 6.去除图像上的高光部分 7.自适应亮度 ...

最新文章

  1. VS中快速生成dll和lib方法
  2. SAP QM 通过控制图 (Control Chart) 的实现提升企业质量管理水平
  3. mysql数据库的增删改查
  4. linux wireshark_WireShark使用教程
  5. junit数据驱动测试_使用Junit和Easytest进行数据驱动的测试
  6. 【算法基础笔记】常用的排序算法的时间、空间复杂度,部分排序算法原理
  7. 启动器和选择器学习-----(1)总括
  8. 栈——验证栈序列(洛谷 P4387)
  9. 补习系列(18)-springboot H2 迷你数据库
  10. 公司java框架让程序员变笨_框架会使程序员变笨吗?
  11. 响应式网站与自适应网站比较
  12. android实现Materia Design风格APP(三):部分Materia Design风格的控件介绍二
  13. CentOS安装网络驱动
  14. python中if else语句用法_Python条件语句详解:if、else、switch都有了
  15. 免费WiFi上网软件之WiFi共享精灵
  16. 房屋登记官考核模拟题(6)
  17. OV都大举降价了,荣耀定价却颇为昂贵,或许是带华为的光芒吧
  18. 计算机基础--作业5,计算机基础第5次作业-第五章-Powerpoint知识题 (精选可编辑)...
  19. java免费批注组件_Java给Word某个字串加批注
  20. 随机森林的java算法_spark 随机森林算法案例实战

热门文章

  1. 业界首款 ACAP 自适应计算加速平台——Xilinx Versal Premium 系列
  2. vue+高德离线地图vue-amap开发
  3. 调用百度AI开放平台实现图片文字识别
  4. 百度富文本编辑器修改图片上传尺寸
  5. 天线传播原理、作用及分类
  6. C++complex复数类
  7. DropDownMenu下拉菜单
  8. 解决 3 errors and 0 warnings potentially fixable with the `--fix` option.问题
  9. 算法教给我的人生道理-贪婪算法
  10. Android-video rotation详解