learning openCV
Compilation notes
Command to compile the program:
cd build && cmake .. && make
NOTE: need to have a directory called build
ALSO, need to have a file called CMakeLists.txt
It should contain:
cmake_minimum_required(VERSION 2.8.12)
project(demo)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(demo demo.cpp)
target_link_libraries(demo ${OpenCV_LIBS})
// replace demo with cpp file name
Code to read and display an image
Mat image;
Mat gray_image;
// reads matrix into Mat image
image = imread( imageName, 1 );
// imreads second parameter can have stuff like
// IMREAD_GRAYSCALE or can have IMREAD_COLOR
// saves grayscale image into gray_image
cvtColor( image, gray_image, COLOR_BGR2GRAY );
// opens a window with original image
namedWindow( "Original image", WINDOW_AUTOSIZE );
// opens a window with the grayscale image
namedWindow( "Gray image", WINDOW_AUTOSIZE );
imshow( imageName, image ); // displays the image
imshow( "Gray image", gray_image ); //displays other image
To write images can use:
imwrite( "../../images/Gray_Image.jpg", gray_image );
A matrix
Mat M(2,2, CV_8UC3, Scalar(0,0,255));<br>
// M.depth() returns CV_8UC
// M.channels() returns the number of channels (3 here)
cout << "M = " << endl << " " << M << endl << endl;
Results in:
M =
[ 0, 0, 255, 0, 0, 255;
0, 0, 255, 0, 0, 255]
Breakdown:
No_row, No_col, Type, Initial_Val
CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
Scalar(V1,V2,V3,V4) initialized all values to this array
Its length is the same as no of channels {MAX = 4}
Getting a Row or Column
Mat myMat(5,5, CV_8UC4, Scalar(10, 100, 200, 255));
cout << "myMat = " << endl << " " << myMat << endl << endl;
cout << "row 1 in myMat: " << myMat.row(1) << endl;
cout << "col 4 in myMat: " << myMat.col(4) << endl;
// myMat.rows returns number of rows
// myMat.cols returns number of cols
row 1 in myMat: [ 10, 100, 200, 255, 10, 100, 200, 255, 10, 100, 200, 255, 10, 100, 200, 255, 10, 100, 200, 255]
column 4 in myMat: [ 10, 100, 200, 255;
10, 100, 200, 255;
10, 100, 200, 255;
10, 100, 200, 255;
10, 100, 200, 255]
// another example of accessing rows // using cloning
Mat RowClone = C.row(1).clone();
cout << "RowClone = " << endl << " " << RowClone << endl;
// above code clones C's row 1 into Matrix RowClone
Random Matrix Array
Mat myMat = Mat(720, 1080, CV_8UC3);
randu(myMat, Scalar::all(0), Scalar::all(255));
To create a Mat array with diagonal having 1's:
Mat E = Mat::eye(4, 4, CV_64F);
Traversing a Matrix
This function is passed a "table" that is used to set values array.
The idea of the function is to scale down all values to integers.
As mentioned above, I.depth() is the type of matrix and I.channels()
returns the number of channels in the Matrix (max 4 (BGRA)).
I.isContinuous() checks if the matrix is stored as a continuous block
of memory, if it is, we shall traverse I as if it was a long char array
finally, the matrix is traversed using a pointer to the matrix and
the value of the pointer is changed
Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
// accept only char type matrices
CV_Assert(I.depth() != sizeof(uchar));
int channels = I.channels();
int nRows = I.rows;
int nCols = I.cols * channels;
if (I.isContinuous())
{
nCols *= nRows;
nRows = 1;
}
int i,j;
uchar* p;
for( i = 0; i < nRows; ++i)
{
p = I.ptr<uchar>(i);
for ( j = 0; j < nCols; ++j)
{
p[j] = table[p[j]];
}
}
return I;
}
where :
uchar table[256];
for (int i = 0; i < 256; ++i)
table[i] = (uchar)(divideWith * (i/divideWith));
Alternatively, can use LUT (look up table)
Transforms the source matrix into the destination matrix using the given look-up table: dst(I) = lut(src(I))
C++: void gpu::LUT(const GpuMat& src, const Mat& lut, GpuMat& dst, Stream& stream=Stream::Null())
- src – Source matrix. CV_8UC1 and CV_8UC3 matrices are supported for now.
- lut – Look-up table of 256 elements. It is a continuous CV_8U matrix.
- dst – Destination matrix with the same depth as lut and the same number of channels as src .
stream – Stream for the asynchronous version.
Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.ptr();
for( int i = 0; i < 256; ++i)
p[i] = table[i]; // same table that was defined above
LUT(I, lookUpTable, J);
The most straightforward way is to:
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 );
}
}
}
// an ALTERNATIVE to change CONTRAST and BRIGHTNESS
image.convertTo(new_image, -1, alpha, beta);pan>
above code helps change brightness and contrast of an image
========================================================
addWeighted( src1, alpha, src2, beta, 0.0, dst);
{dst} (I)= {saturate} ( {src1} (I) {alpha} + {src2} (I) {beta} + {gamma} )
Drawing
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#define w 400
using namespace cv;
int main(int argc, char **argv)
{
char windowA[] = "atom picture";
char windowB[] = "rook picture";
// Mat A = Mat::zeros(w, w, CV_8UC3);
Mat B = Mat::zeros(w, w, CV_8UC3);
// namedWindow(windowA);
namedWindow(windowB);
rectangle(B, Point(0, 7*w/8), Point(w,w),
Scalar(0,0,100), -1, 8);
int thickness = 2;
int lineType = 8;
Point rook_points[1][20];
rook_points[0][0] = Point( w/4, 7*w/8 );
rook_points[0][1] = Point( 3*w/4, 7*w/8 );
rook_points[0][2] = Point( 3*w/4, 13*w/16 );
rook_points[0][3] = Point( 11*w/16, 13*w/16 );
rook_points[0][4] = Point( 19*w/32, 3*w/8 );
rook_points[0][5] = Point( 3*w/4, 3*w/8 );
rook_points[0][6] = Point( 3*w/4, w/8 );
rook_points[0][7] = Point( 26*w/40, w/8 );
rook_points[0][8] = Point( 26*w/40, w/4 );
rook_points[0][9] = Point( 22*w/40, w/4 );
rook_points[0][10] = Point( 22*w/40, w/8 );
rook_points[0][11] = Point( 18*w/40, w/8 );
rook_points[0][12] = Point( 18*w/40, w/4 );
rook_points[0][13] = Point( 14*w/40, w/4 );
rook_points[0][14] = Point( 14*w/40, w/8 );
rook_points[0][15] = Point( w/4, w/8 );
rook_points[0][16] = Point( w/4, 3*w/8 );
rook_points[0][17] = Point( 13*w/32, 3*w/8 );
rook_points[0][18] = Point( 5*w/16, 13*w/16 );
rook_points[0][19] = Point( w/4, 13*w/16 );
const Point* ppt[1] = { rook_points[0] };
int npt[] = { 20 };
fillPoly( B, ppt, npt, 1, Scalar( 255, 255, 255 ),
8 );
// line( img, start, end,
// Scalar( 0, 0, 0 ), thickness, lineType );
line( B, Point(0, 15*w/16), Point(w, 15*w/16), Scalar( 0, 10, 120 ), 2, 8 );
line( B, Point(w/4, 14*w/16), Point(w/4, w), Scalar( 0, 10, 120 ), 2, 8 );
line( B, Point(w/2, 14*w/16), Point(w/2, w), Scalar( 0, 10, 120 ), 2, 8 );
line( B, Point(3*w/4, 14*w/16), Point(3*w/4, w), Scalar( 0, 10, 120 ), 2, 8 );
ellipse( B, Point( w/2, w/2 ), Size( w/4, w/16 ), -45, 0, 360/2, Scalar( 255, 0, 0 ), 2, 8 );
ellipse( B, Point( w/4, w/4 ), Size( w/4, w/16 ), -45, 0, 360, Scalar( 255, 25, 250 ), 2, 8 );
circle( B, Point(3*w/4, w/4), w/64, Scalar(100,255,100), 1, 3 );
imshow(windowB, B);
waitKey(0);
return 0;
}
NOTE: The top left corner is (0,0) and bottom right is (x,y)
NOTE: they have a random number generator called RNG:
// below, seedVal = 0xFFFFFFFF; is an example
RNG rng(seedVal);
/* -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
static Scalar randomColor( RNG& rng )
{
int icolor = (unsigned) rng;
return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
}