Merge pull request #15805 from i-murzov:3.4

pull/15826/head
Alexander Alekhin 5 years ago
commit 5c12bafe80
  1. 6
      doc/tutorials/core/basic_linear_transform/basic_linear_transform.markdown
  2. 42
      doc/tutorials/core/how_to_scan_images/how_to_scan_images.markdown
  3. 6
      doc/tutorials/core/mat-mask-operations/mat_mask_operations.markdown
  4. 40
      doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown
  5. 2
      modules/core/include/opencv2/core/saturate.hpp

@ -150,7 +150,7 @@ We observe that @ref cv::Mat::zeros returns a Matlab-style zero initializer base
Notice the following (**C++ code only**): Notice the following (**C++ code only**):
- To access each pixel in the images we are using this syntax: *image.at\<Vec3b\>(y,x)[c]* - To access each pixel in the images we are using this syntax: *image.at\<Vec3b\>(y,x)[c]*
where *y* is the row, *x* is the column and *c* is R, G or B (0, 1 or 2). where *y* is the row, *x* is the column and *c* is B, G or R (0, 1 or 2).
- Since the operation \f$\alpha \cdot p(i,j) + \beta\f$ can give values out of range or not - Since the operation \f$\alpha \cdot p(i,j) + \beta\f$ can give values out of range or not
integers (if \f$\alpha\f$ is float), we use cv::saturate_cast to make sure the integers (if \f$\alpha\f$ is float), we use cv::saturate_cast to make sure the
values are valid. values are valid.
@ -220,12 +220,12 @@ gamma correction.
### Brightness and contrast adjustments ### Brightness and contrast adjustments
Increasing (/ decreasing) the \f$\beta\f$ value will add (/ subtract) a constant value to every pixel. Pixel values outside of the [0 ; 255] Increasing (/ decreasing) the \f$\beta\f$ value will add (/ subtract) a constant value to every pixel. Pixel values outside of the [0 ; 255]
range will be saturated (i.e. a pixel value higher (/ lesser) than 255 (/ 0) will be clamp to 255 (/ 0)). range will be saturated (i.e. a pixel value higher (/ lesser) than 255 (/ 0) will be clamped to 255 (/ 0)).
![In light gray, histogram of the original image, in dark gray when brightness = 80 in Gimp](images/Basic_Linear_Transform_Tutorial_hist_beta.png) ![In light gray, histogram of the original image, in dark gray when brightness = 80 in Gimp](images/Basic_Linear_Transform_Tutorial_hist_beta.png)
The histogram represents for each color level the number of pixels with that color level. A dark image will have many pixels with The histogram represents for each color level the number of pixels with that color level. A dark image will have many pixels with
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 low color value and thus the histogram will present a peak in its left part. When adding a constant bias, the histogram is shifted to the
right as we have added a constant bias to all the pixels. right as we have added a constant bias to all the pixels.
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 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

@ -10,7 +10,7 @@ Goal
We'll seek answers for the following questions: We'll seek answers for the following questions:
- How to go through each and every pixel of an image? - How to go through each and every pixel of an image?
- How is OpenCV matrix values stored? - How are OpenCV matrix values stored?
- How to measure the performance of our algorithm? - How to measure the performance of our algorithm?
- What are lookup tables and why use them? - What are lookup tables and why use them?
@ -45,13 +45,13 @@ operation. In case of the *uchar* system this is 256 to be exact.
Therefore, for larger images it would be wise to calculate all possible values beforehand and during Therefore, for larger images it would be wise to calculate all possible values beforehand and during
the assignment just make the assignment, by using a lookup table. Lookup tables are simple arrays the assignment just make the assignment, by using a lookup table. Lookup tables are simple arrays
(having one or more dimensions) that for a given input value variation holds the final output value. (having one or more dimensions) that for a given input value variation holds the final output value.
Its strength lies that we do not need to make the calculation, we just need to read the result. Its strength is that we do not need to make the calculation, we just need to read the result.
Our test case program (and the sample presented here) will do the following: read in a console line Our test case program (and the code sample below) will do the following: read in an image passed
argument image (that may be either color or gray scale - console line argument too) and apply the as a command line argument (it may be either color or grayscale) and apply the reduction
reduction with the given console line argument integer value. In OpenCV, at the moment there are with the given command line argument integer value. In OpenCV, at the moment there are
three major ways of going through an image pixel by pixel. To make things a little more interesting three major ways of going through an image pixel by pixel. To make things a little more interesting
will make the scanning for each image using all of these methods, and print out how long it took. we'll make the scanning of the image using each of these methods, and print out how long it took.
You can download the full source code [here You can download the full source code [here
](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp) or look it up in ](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp) or look it up in
@ -59,7 +59,7 @@ the samples directory of OpenCV at the cpp tutorial code for the core section. I
@code{.bash} @code{.bash}
how_to_scan_images imageName.jpg intValueToReduce [G] how_to_scan_images imageName.jpg intValueToReduce [G]
@endcode @endcode
The final argument is optional. If given the image will be loaded in gray scale format, otherwise The final argument is optional. If given the image will be loaded in grayscale format, otherwise
the BGR color space is used. The first thing is to calculate the lookup table. the BGR color space is used. The first thing is to calculate the lookup table.
@snippet how_to_scan_images.cpp dividewith @snippet how_to_scan_images.cpp dividewith
@ -71,8 +71,8 @@ No OpenCV specific stuff here.
Another issue is how do we measure time? Well OpenCV offers two simple functions to achieve this Another issue is how do we measure time? Well OpenCV offers two simple functions to achieve this
cv::getTickCount() and cv::getTickFrequency() . The first returns the number of ticks of cv::getTickCount() and cv::getTickFrequency() . The first returns the number of ticks of
your systems CPU from a certain event (like since you booted your system). The second returns how your systems CPU from a certain event (like since you booted your system). The second returns how
many times your CPU emits a tick during a second. So to measure in seconds the number of time many times your CPU emits a tick during a second. So, measuring amount of time elapsed between
elapsed between two operations is easy as: two operations is as easy as:
@code{.cpp} @code{.cpp}
double t = (double)getTickCount(); double t = (double)getTickCount();
// do something ... // do something ...
@ -85,8 +85,8 @@ How is the image matrix stored in memory?
----------------------------------------- -----------------------------------------
As you could already read in my @ref tutorial_mat_the_basic_image_container tutorial the size of the matrix As you could already read in my @ref tutorial_mat_the_basic_image_container tutorial the size of the matrix
depends on the color system used. More accurately, it depends from the number of channels used. In depends on the color system used. More accurately, it depends on the number of channels used. In
case of a gray scale image we have something like: case of a grayscale image we have something like:
![](tutorial_how_matrix_stored_1.png) ![](tutorial_how_matrix_stored_1.png)
@ -117,12 +117,12 @@ three channels so we need to pass through three times more items in each row.
There's another way of this. The *data* data member of a *Mat* object returns the pointer to the There's another way of this. The *data* data member of a *Mat* object returns the pointer to the
first row, first column. If this pointer is null you have no valid input in that object. Checking first row, first column. If this pointer is null you have no valid input in that object. Checking
this is the simplest method to check if your image loading was a success. In case the storage is this is the simplest method to check if your image loading was a success. In case the storage is
continuous we can use this to go through the whole data pointer. In case of a gray scale image this continuous we can use this to go through the whole data pointer. In case of a grayscale image this
would look like: would look like:
@code{.cpp} @code{.cpp}
uchar* p = I.data; uchar* p = I.data;
for( unsigned int i =0; i < ncol*nrows; ++i) for( unsigned int i = 0; i < ncol*nrows; ++i)
*p++ = table[*p]; *p++ = table[*p];
@endcode @endcode
You would get the same result. However, this code is a lot harder to read later on. It gets even You would get the same result. However, this code is a lot harder to read later on. It gets even
@ -135,7 +135,7 @@ The iterator (safe) method
In case of the efficient way making sure that you pass through the right amount of *uchar* fields In case of the efficient way making sure that you pass through the right amount of *uchar* fields
and to skip the gaps that may occur between the rows was your responsibility. The iterator method is and to skip the gaps that may occur between the rows was your responsibility. The iterator method is
considered a safer way as it takes over these tasks from the user. All you need to do is ask the considered a safer way as it takes over these tasks from the user. All you need to do is to ask the
begin and the end of the image matrix and then just increase the begin iterator until you reach the begin and the end of the image matrix and then just increase the begin iterator until you reach the
end. To acquire the value *pointed* by the iterator use the \* operator (add it before it). end. To acquire the value *pointed* by the iterator use the \* operator (add it before it).
@ -152,17 +152,17 @@ On-the-fly address calculation with reference returning
The final method isn't recommended for scanning. It was made to acquire or modify somehow random The final method isn't recommended for scanning. It was made to acquire or modify somehow random
elements in the image. Its basic usage is to specify the row and column number of the item you want elements in the image. Its basic usage is to specify the row and column number of the item you want
to access. During our earlier scanning methods you could already observe that is important through to access. During our earlier scanning methods you could already notice that it is important through
what type we are looking at the image. It's no different here as you need to manually specify what what type we are looking at the image. It's no different here as you need to manually specify what
type to use at the automatic lookup. You can observe this in case of the gray scale images for the type to use at the automatic lookup. You can observe this in case of the grayscale images for the
following source code (the usage of the + cv::Mat::at() function): following source code (the usage of the + cv::Mat::at() function):
@snippet how_to_scan_images.cpp scan-random @snippet how_to_scan_images.cpp scan-random
The functions takes your input type and coordinates and calculates on the fly the address of the The function takes your input type and coordinates and calculates the address of the
queried item. Then returns a reference to that. This may be a constant when you *get* the value and queried item. Then returns a reference to that. This may be a constant when you *get* the value and
non-constant when you *set* the value. As a safety step in **debug mode only**\* there is performed non-constant when you *set* the value. As a safety step in **debug mode only**\* there is a check
a check that your input coordinates are valid and does exist. If this isn't the case you'll get a performed that your input coordinates are valid and do exist. If this isn't the case you'll get a
nice output message of this on the standard error output stream. Compared to the efficient way in nice output message of this on the standard error output stream. Compared to the efficient way in
release mode the only difference in using this is that for every element of the image you'll get a release mode the only difference in using this is that for every element of the image you'll get a
new row pointer for what we use the C operator[] to acquire the column element. new row pointer for what we use the C operator[] to acquire the column element.
@ -173,7 +173,7 @@ OpenCV has a cv::Mat_ data type. It's the same as Mat with the extra need that a
you need to specify the data type through what to look at the data matrix, however in return you can you need to specify the data type through what to look at the data matrix, however in return you can
use the operator() for fast access of items. To make things even better this is easily convertible use the operator() for fast access of items. To make things even better this is easily convertible
from and to the usual cv::Mat data type. A sample usage of this you can see in case of the from and to the usual cv::Mat data type. A sample usage of this you can see in case of the
color images of the upper function. Nevertheless, it's important to note that the same operation color images of the function above. Nevertheless, it's important to note that the same operation
(with the same runtime speed) could have been done with the cv::Mat::at function. It's just a less (with the same runtime speed) could have been done with the cv::Mat::at function. It's just a less
to write for the lazy programmer trick. to write for the lazy programmer trick.
@ -195,7 +195,7 @@ Finally call the function (I is our input image and J the output one):
Performance Difference Performance Difference
---------------------- ----------------------
For the best result compile the program and run it on your own speed. To make the differences more For the best result compile the program and run it yourself. To make the differences more
clear, I've used a quite large (2560 X 1600) image. The performance presented here are for clear, I've used a quite large (2560 X 1600) image. The performance presented here are for
color images. For a more accurate value I've averaged the value I got from the call of the function color images. For a more accurate value I've averaged the value I got from the call of the function
for hundred times. for hundred times.

@ -4,7 +4,7 @@ Mask operations on matrices {#tutorial_mat_mask_operations}
@prev_tutorial{tutorial_how_to_scan_images} @prev_tutorial{tutorial_how_to_scan_images}
@next_tutorial{tutorial_mat_operations} @next_tutorial{tutorial_mat_operations}
Mask operations on matrices are quite simple. The idea is that we recalculate each pixels value in Mask operations on matrices are quite simple. The idea is that we recalculate each pixel's value in
an image according to a mask matrix (also known as kernel). This mask holds values that will adjust an image according to a mask matrix (also known as kernel). This mask holds values that will adjust
how much influence neighboring pixels (and the current pixel) have on the new pixel value. From a how much influence neighboring pixels (and the current pixel) have on the new pixel value. From a
mathematical point of view we make a weighted average, with our specified values. mathematical point of view we make a weighted average, with our specified values.
@ -12,7 +12,7 @@ mathematical point of view we make a weighted average, with our specified values
Our test case Our test case
------------- -------------
Let us consider the issue of an image contrast enhancement method. Basically we want to apply for Let's consider the issue of an image contrast enhancement method. Basically we want to apply for
every pixel of the image the following formula: every pixel of the image the following formula:
\f[I(i,j) = 5*I(i,j) - [ I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]\f]\f[\iff I(i,j)*M, \text{where } \f[I(i,j) = 5*I(i,j) - [ I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]\f]\f[\iff I(i,j)*M, \text{where }
@ -144,7 +144,7 @@ Then we apply the sum and put the new value in the Result matrix.
The filter2D function The filter2D function
--------------------- ---------------------
Applying such filters are so common in image processing that in OpenCV there exist a function that Applying such filters are so common in image processing that in OpenCV there is a function that
will take care of applying the mask (also called a kernel in some places). For this you first need will take care of applying the mask (also called a kernel in some places). For this you first need
to define an object that holds the mask: to define an object that holds the mask:

@ -61,7 +61,7 @@ The last thing we want to do is further decrease the speed of your program by ma
copies of potentially *large* images. copies of potentially *large* images.
To tackle this issue OpenCV uses a reference counting system. The idea is that each *Mat* object has To tackle this issue OpenCV uses a reference counting system. The idea is that each *Mat* object has
its own header, however the matrix may be shared between two instance of them by having their matrix its own header, however a matrix may be shared between two *Mat* objects by having their matrix
pointers point to the same address. Moreover, the copy operators **will only copy the headers** and pointers point to the same address. Moreover, the copy operators **will only copy the headers** and
the pointer to the large matrix, not the data itself. the pointer to the large matrix, not the data itself.
@ -74,32 +74,32 @@ Mat B(A); // Use the copy constructor
C = A; // Assignment operator C = A; // Assignment operator
@endcode @endcode
All the above objects, in the end, point to the same single data matrix. Their headers are All the above objects, in the end, point to the same single data matrix and making a modification
different, however, and making a modification using any of them will affect all the other ones as using any of them will affect all the other ones as well. In practice the different objects just
well. In practice the different objects just provide different access method to the same underlying provide different access methods to the same underlying data. Nevertheless, their header parts are
data. Nevertheless, their header parts are different. The real interesting part is that you can different. The real interesting part is that you can create headers which refer to only a subsection
create headers which refer to only a subsection of the full data. For example, to create a region of of the full data. For example, to create a region of interest (*ROI*) in an image you just create
interest (*ROI*) in an image you just create a new header with the new boundaries: a new header with the new boundaries:
@code{.cpp} @code{.cpp}
Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle
Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries
@endcode @endcode
Now you may ask if the matrix itself may belong to multiple *Mat* objects who takes responsibility Now you may ask -- if the matrix itself may belong to multiple *Mat* objects who takes responsibility
for cleaning it up when it's no longer needed. The short answer is: the last object that used it. for cleaning it up when it's no longer needed. The short answer is: the last object that used it.
This is handled by using a reference counting mechanism. Whenever somebody copies a header of a This is handled by using a reference counting mechanism. Whenever somebody copies a header of a
*Mat* object, a counter is increased for the matrix. Whenever a header is cleaned this counter is *Mat* object, a counter is increased for the matrix. Whenever a header is cleaned, this counter
decreased. When the counter reaches zero the matrix too is freed. Sometimes you will want to copy is decreased. When the counter reaches zero the matrix is freed. Sometimes you will want to copy
the matrix itself too, so OpenCV provides the @ref cv::Mat::clone() and @ref cv::Mat::copyTo() functions. the matrix itself too, so OpenCV provides @ref cv::Mat::clone() and @ref cv::Mat::copyTo() functions.
@code{.cpp} @code{.cpp}
Mat F = A.clone(); Mat F = A.clone();
Mat G; Mat G;
A.copyTo(G); A.copyTo(G);
@endcode @endcode
Now modifying *F* or *G* will not affect the matrix pointed by the *Mat* header. What you need to Now modifying *F* or *G* will not affect the matrix pointed by the *A*'s header. What you need to
remember from all this is that: remember from all this is that:
- Output image allocation for OpenCV functions is automatic (unless specified otherwise). - Output image allocation for OpenCV functions is automatic (unless specified otherwise).
- You do not need to think about memory management with OpenCVs C++ interface. - You do not need to think about memory management with OpenCV's C++ interface.
- The assignment operator and the copy constructor only copies the header. - The assignment operator and the copy constructor only copies the header.
- The underlying matrix of an image may be copied using the @ref cv::Mat::clone() and @ref cv::Mat::copyTo() - The underlying matrix of an image may be copied using the @ref cv::Mat::clone() and @ref cv::Mat::copyTo()
functions. functions.
@ -109,7 +109,7 @@ Storing methods
This is about how you store the pixel values. You can select the color space and the data type used. This is about how you store the pixel values. You can select the color space and the data type used.
The color space refers to how we combine color components in order to code a given color. The The color space refers to how we combine color components in order to code a given color. The
simplest one is the gray scale where the colors at our disposal are black and white. The combination simplest one is the grayscale where the colors at our disposal are black and white. The combination
of these allows us to create many shades of gray. of these allows us to create many shades of gray.
For *colorful* ways we have a lot more methods to choose from. Each of them breaks it down to three For *colorful* ways we have a lot more methods to choose from. Each of them breaks it down to three
@ -121,15 +121,15 @@ added.
There are, however, many other color systems each with their own advantages: There are, however, many other color systems each with their own advantages:
- RGB is the most common as our eyes use something similar, however keep in mind that OpenCV standard display - RGB is the most common as our eyes use something similar, however keep in mind that OpenCV standard display
system composes colors using the BGR color space (a switch of the red and blue channel). system composes colors using the BGR color space (red and blue channels are swapped places).
- The HSV and HLS decompose colors into their hue, saturation and value/luminance components, - The HSV and HLS decompose colors into their hue, saturation and value/luminance components,
which is a more natural way for us to describe colors. You might, for example, dismiss the last which is a more natural way for us to describe colors. You might, for example, dismiss the last
component, making your algorithm less sensible to the light conditions of the input image. component, making your algorithm less sensible to the light conditions of the input image.
- YCrCb is used by the popular JPEG image format. - YCrCb is used by the popular JPEG image format.
- CIE L\*a\*b\* is a perceptually uniform color space, which comes handy if you need to measure - CIE L\*a\*b\* is a perceptually uniform color space, which comes in handy if you need to measure
the *distance* of a given color to another color. the *distance* of a given color to another color.
Each of the building components has their own valid domains. This leads to the data type used. How Each of the building components has its own valid domains. This leads to the data type used. How
we store a component defines the control we have over its domain. The smallest data type possible is we store a component defines the control we have over its domain. The smallest data type possible is
*char*, which means one byte or 8 bits. This may be unsigned (so can store values from 0 to 255) or *char*, which means one byte or 8 bits. This may be unsigned (so can store values from 0 to 255) or
signed (values from -127 to +127). Although in case of three components this already gives 16 signed (values from -127 to +127). Although in case of three components this already gives 16
@ -165,8 +165,8 @@ object in multiple ways:
CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number] CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
@endcode @endcode
For instance, *CV_8UC3* means we use unsigned char types that are 8 bit long and each pixel has For instance, *CV_8UC3* means we use unsigned char types that are 8 bit long and each pixel has
three of these to form the three channels. This are predefined for up to four channel numbers. The three of these to form the three channels. There are types predefined for up to four channels. The
@ref cv::Scalar is four element short vector. Specify this and you can initialize all matrix @ref cv::Scalar is four element short vector. Specify it and you can initialize all matrix
points with a custom value. If you need more you can create the type with the upper macro, setting points with a custom value. If you need more you can create the type with the upper macro, setting
the channel number in parenthesis as you can see below. the channel number in parenthesis as you can see below.
@ -210,7 +210,7 @@ object in multiple ways:
@note @note
You can fill out a matrix with random values using the @ref cv::randu() function. You need to You can fill out a matrix with random values using the @ref cv::randu() function. You need to
give the lower and upper value for the random values: give a lower and upper limit for the random values:
@snippet mat_the_basic_image_container.cpp random @snippet mat_the_basic_image_container.cpp random

@ -74,8 +74,6 @@ namespace cv
the floating-point value is first rounded to the nearest integer and then clipped if needed (when the floating-point value is first rounded to the nearest integer and then clipped if needed (when
the target type is 8- or 16-bit). the target type is 8- or 16-bit).
This operation is used in the simplest or most complex image processing functions in OpenCV.
@param v Function parameter. @param v Function parameter.
@sa add, subtract, multiply, divide, Mat::convertTo @sa add, subtract, multiply, divide, Mat::convertTo
*/ */

Loading…
Cancel
Save