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

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