Merge remote-tracking branch 'upstream/3.4' into merge-3.4
[platform/upstream/opencv.git] / doc / tutorials / core / basic_linear_transform / basic_linear_transform.markdown
1 Changing the contrast and brightness of an image! {#tutorial_basic_linear_transform}
2 =================================================
3
4 Goal
5 ----
6
7 In this tutorial you will learn how to:
8
9 -   Access pixel values
10 -   Initialize a matrix with zeros
11 -   Learn what @ref cv::saturate_cast does and why it is useful
12 -   Get some cool info about pixel transformations
13 -   Improve the brightness of an image on a practical example
14
15 Theory
16 ------
17
18 @note
19    The explanation below belongs to the book [Computer Vision: Algorithms and
20     Applications](http://szeliski.org/Book/) by Richard Szeliski
21
22 ### Image Processing
23
24 -   A general image processing operator is a function that takes one or more input images and
25     produces an output image.
26 -   Image transforms can be seen as:
27     -   Point operators (pixel transforms)
28     -   Neighborhood (area-based) operators
29
30 ### Pixel Transforms
31
32 -   In this kind of image processing transform, each output pixel's value depends on only the
33     corresponding input pixel value (plus, potentially, some globally collected information or
34     parameters).
35 -   Examples of such operators include *brightness and contrast adjustments* as well as color
36     correction and transformations.
37
38 ### Brightness and contrast adjustments
39
40 -   Two commonly used point processes are *multiplication* and *addition* with a constant:
41
42     \f[g(x) = \alpha f(x) + \beta\f]
43
44 -   The parameters \f$\alpha > 0\f$ and \f$\beta\f$ are often called the *gain* and *bias* parameters;
45     sometimes these parameters are said to control *contrast* and *brightness* respectively.
46 -   You can think of \f$f(x)\f$ as the source image pixels and \f$g(x)\f$ as the output image pixels. Then,
47     more conveniently we can write the expression as:
48
49     \f[g(i,j) = \alpha \cdot f(i,j) + \beta\f]
50
51     where \f$i\f$ and \f$j\f$ indicates that the pixel is located in the *i-th* row and *j-th* column.
52
53 Code
54 ----
55
56 @add_toggle_cpp
57 -   **Downloadable code**: Click
58     [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp)
59
60 -   The following code performs the operation \f$g(i,j) = \alpha \cdot f(i,j) + \beta\f$ :
61     @include samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp
62 @end_toggle
63
64 @add_toggle_java
65 -   **Downloadable code**: Click
66     [here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/BasicLinearTransformsDemo.java)
67
68 -   The following code performs the operation \f$g(i,j) = \alpha \cdot f(i,j) + \beta\f$ :
69     @include samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/BasicLinearTransformsDemo.java
70 @end_toggle
71
72 @add_toggle_python
73 -   **Downloadable code**: Click
74     [here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/BasicLinearTransforms.py)
75
76 -   The following code performs the operation \f$g(i,j) = \alpha \cdot f(i,j) + \beta\f$ :
77     @include samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/BasicLinearTransforms.py
78 @end_toggle
79
80 Explanation
81 -----------
82
83 -   We load an image using @ref cv::imread and save it in a Mat object:
84
85 @add_toggle_cpp
86 @snippet samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp basic-linear-transform-load
87 @end_toggle
88
89 @add_toggle_java
90 @snippet samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/BasicLinearTransformsDemo.java basic-linear-transform-load
91 @end_toggle
92
93 @add_toggle_python
94 @snippet samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/BasicLinearTransforms.py basic-linear-transform-load
95 @end_toggle
96
97 -   Now, since we will make some transformations to this image, we need a new Mat object to store
98     it. Also, we want this to have the following features:
99
100     -   Initial pixel values equal to zero
101     -   Same size and type as the original image
102
103 @add_toggle_cpp
104 @snippet samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp basic-linear-transform-output
105 @end_toggle
106
107 @add_toggle_java
108 @snippet samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/BasicLinearTransformsDemo.java basic-linear-transform-output
109 @end_toggle
110
111 @add_toggle_python
112 @snippet samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/BasicLinearTransforms.py basic-linear-transform-output
113 @end_toggle
114
115 We observe that @ref cv::Mat::zeros returns a Matlab-style zero initializer based on
116 *image.size()* and *image.type()*
117
118 -   We ask now the values of \f$\alpha\f$ and \f$\beta\f$ to be entered by the user:
119
120 @add_toggle_cpp
121 @snippet samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp basic-linear-transform-parameters
122 @end_toggle
123
124 @add_toggle_java
125 @snippet samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/BasicLinearTransformsDemo.java basic-linear-transform-parameters
126 @end_toggle
127
128 @add_toggle_python
129 @snippet samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/BasicLinearTransforms.py basic-linear-transform-parameters
130 @end_toggle
131
132 -   Now, to perform the operation \f$g(i,j) = \alpha \cdot f(i,j) + \beta\f$ we will access to each
133     pixel in image. Since we are operating with BGR images, we will have three values per pixel (B,
134     G and R), so we will also access them separately. Here is the piece of code:
135
136 @add_toggle_cpp
137 @snippet samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp basic-linear-transform-operation
138 @end_toggle
139
140 @add_toggle_java
141 @snippet samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/BasicLinearTransformsDemo.java basic-linear-transform-operation
142 @end_toggle
143
144 @add_toggle_python
145 @snippet samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/BasicLinearTransforms.py basic-linear-transform-operation
146 @end_toggle
147
148 Notice the following (**C++ code only**):
149 -   To access each pixel in the images we are using this syntax: *image.at\<Vec3b\>(y,x)[c]*
150     where *y* is the row, *x* is the column and *c* is R, G or B (0, 1 or 2).
151 -   Since the operation \f$\alpha \cdot p(i,j) + \beta\f$ can give values out of range or not
152     integers (if \f$\alpha\f$ is float), we use cv::saturate_cast to make sure the
153     values are valid.
154
155 -   Finally, we create windows and show the images, the usual way.
156
157 @add_toggle_cpp
158 @snippet samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp basic-linear-transform-display
159 @end_toggle
160
161 @add_toggle_java
162 @snippet samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/BasicLinearTransformsDemo.java basic-linear-transform-display
163 @end_toggle
164
165 @add_toggle_python
166 @snippet samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/BasicLinearTransforms.py basic-linear-transform-display
167 @end_toggle
168
169 @note
170     Instead of using the **for** loops to access each pixel, we could have simply used this command:
171
172 @add_toggle_cpp
173 @code{.cpp}
174 image.convertTo(new_image, -1, alpha, beta);
175 @endcode
176 @end_toggle
177
178 @add_toggle_java
179 @code{.java}
180 image.convertTo(newImage, -1, alpha, beta);
181 @endcode
182 @end_toggle
183
184 @add_toggle_python
185 @code{.py}
186 new_image = cv.convertScaleAbs(image, alpha=alpha, beta=beta)
187 @endcode
188 @end_toggle
189
190 where @ref cv::Mat::convertTo would effectively perform *new_image = a*image + beta\*. However, we
191 wanted to show you how to access each pixel. In any case, both methods give the same result but
192 convertTo is more optimized and works a lot faster.
193
194 Result
195 ------
196
197 -   Running our code and using \f$\alpha = 2.2\f$ and \f$\beta = 50\f$
198     @code{.bash}
199     $ ./BasicLinearTransforms lena.jpg
200     Basic Linear Transforms
201     -------------------------
202     * Enter the alpha value [1.0-3.0]: 2.2
203     * Enter the beta value [0-100]: 50
204     @endcode
205
206 -   We get this:
207
208     ![](images/Basic_Linear_Transform_Tutorial_Result_big.jpg)
209
210 Practical example
211 ----
212
213 In this paragraph, we will put into practice what we have learned to correct an underexposed image by adjusting the brightness
214 and the contrast of the image. We will also see another technique to correct the brightness of an image called
215 gamma correction.
216
217 ### Brightness and contrast adjustments
218
219 Increasing (/ decreasing) the \f$\beta\f$ value will add (/ subtract) a constant value to every pixel. Pixel values outside of the [0 ; 255]
220 range will be saturated (i.e. a pixel value higher (/ lesser) than 255 (/ 0) will be clamp to 255 (/ 0)).
221
222 ![In light gray, histogram of the original image, in dark gray when brightness = 80 in Gimp](images/Basic_Linear_Transform_Tutorial_hist_beta.png)
223
224 The histogram represents for each color level the number of pixels with that color level. A dark image will have many pixels with
225 low color value and thus the histogram will present a peak in his left part. When adding a constant bias, the histogram is shifted to the
226 right as we have added a constant bias to all the pixels.
227
228 The \f$\alpha\f$ parameter will modify how the levels spread. If \f$ \alpha < 1 \f$, the color levels will be compressed and the result
229 will be an image with less contrast.
230
231 ![In light gray, histogram of the original image, in dark gray when contrast < 0 in Gimp](images/Basic_Linear_Transform_Tutorial_hist_alpha.png)
232
233 Note that these histograms have been obtained using the Brightness-Contrast tool in the Gimp software. The brightness tool should be
234 identical to the \f$\beta\f$ bias parameters but the contrast tool seems to differ to the \f$\alpha\f$ gain where the output range
235 seems to be centered with Gimp (as you can notice in the previous histogram).
236
237 It can occur that playing with the \f$\beta\f$ bias will improve the brightness but in the same time the image will appear with a
238 slight veil as the contrast will be reduced. The \f$\alpha\f$ gain can be used to diminue this effect but due to the saturation,
239 we will lose some details in the original bright regions.
240
241 ### Gamma correction
242
243 [Gamma correction](https://en.wikipedia.org/wiki/Gamma_correction) can be used to correct the brightness of an image by using a non
244 linear transformation between the input values and the mapped output values:
245
246 \f[O = \left( \frac{I}{255} \right)^{\gamma} \times 255\f]
247
248 As this relation is non linear, the effect will not be the same for all the pixels and will depend to their original value.
249
250 ![Plot for different values of gamma](images/Basic_Linear_Transform_Tutorial_gamma.png)
251
252 When \f$ \gamma < 1 \f$, the original dark regions will be brighter and the histogram will be shifted to the right whereas it will
253 be the opposite with \f$ \gamma > 1 \f$.
254
255 ### Correct an underexposed image
256
257 The following image has been corrected with: \f$ \alpha = 1.3 \f$ and \f$ \beta = 40 \f$.
258
259 ![By Visem (Own work) [CC BY-SA 3.0], via Wikimedia Commons](images/Basic_Linear_Transform_Tutorial_linear_transform_correction.jpg)
260
261 The overall brightness has been improved but you can notice that the clouds are now greatly saturated due to the numerical saturation
262 of the implementation used ([highlight clipping](https://en.wikipedia.org/wiki/Clipping_(photography)) in photography).
263
264 The following image has been corrected with: \f$ \gamma = 0.4 \f$.
265
266 ![By Visem (Own work) [CC BY-SA 3.0], via Wikimedia Commons](images/Basic_Linear_Transform_Tutorial_gamma_correction.jpg)
267
268 The gamma correction should tend to add less saturation effect as the mapping is non linear and there is no numerical saturation possible as in the previous method.
269
270 ![Left: histogram after alpha, beta correction ; Center: histogram of the original image ; Right: histogram after the gamma correction](images/Basic_Linear_Transform_Tutorial_histogram_compare.png)
271
272 The previous figure compares the histograms for the three images (the y-ranges are not the same between the three histograms).
273 You can notice that most of the pixel values are in the lower part of the histogram for the original image. After \f$ \alpha \f$,
274 \f$ \beta \f$ correction, we can observe a big peak at 255 due to the saturation as well as a shift in the right.
275 After gamma correction, the histogram is shifted to the right but the pixels in the dark regions are more shifted
276 (see the gamma curves [figure](Basic_Linear_Transform_Tutorial_gamma.png)) than those in the bright regions.
277
278 In this tutorial, you have seen two simple methods to adjust the contrast and the brightness of an image. **They are basic techniques
279 and are not intended to be used as a replacement of a raster graphics editor!**
280
281 ### Code
282
283 @add_toggle_cpp
284 Code for the tutorial is [here](https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/ImgProc/changing_contrast_brightness_image/changing_contrast_brightness_image.cpp).
285 @end_toggle
286
287 @add_toggle_java
288 Code for the tutorial is [here](https://github.com/opencv/opencv/blob/master/samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/ChangingContrastBrightnessImageDemo.java).
289 @end_toggle
290
291 @add_toggle_python
292 Code for the tutorial is [here](https://github.com/opencv/opencv/blob/master/samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/changing_contrast_brightness_image.py).
293 @end_toggle
294
295 Code for the gamma correction:
296
297 @add_toggle_cpp
298 @snippet samples/cpp/tutorial_code/ImgProc/changing_contrast_brightness_image/changing_contrast_brightness_image.cpp changing-contrast-brightness-gamma-correction
299 @end_toggle
300
301 @add_toggle_java
302 @snippet samples/java/tutorial_code/ImgProc/changing_contrast_brightness_image/ChangingContrastBrightnessImageDemo.java changing-contrast-brightness-gamma-correction
303 @end_toggle
304
305 @add_toggle_python
306 @snippet samples/python/tutorial_code/imgProc/changing_contrast_brightness_image/changing_contrast_brightness_image.py changing-contrast-brightness-gamma-correction
307 @end_toggle
308
309 A look-up table is used to improve the performance of the computation as only 256 values needs to be calculated once.
310
311 ### Additional resources
312
313 -   [Gamma correction in graphics rendering](https://learnopengl.com/#!Advanced-Lighting/Gamma-Correction)
314 -   [Gamma correction and images displayed on CRT monitors](http://www.graphics.cornell.edu/~westin/gamma/gamma.html)
315 -   [Digital exposure techniques](http://www.cambridgeincolour.com/tutorials/digital-exposure-techniques.htm)