OpenCV Mat

You will need to include only the opencv2/opencv.hpp header file in your program
Add the using namespace cv; line just after including header files

#include <opencv2/opencv.hpp>
using namespace cv;
#include <opencv2/opencv.hpp> 

int main(int argc, char** argv) 
{ 
 // Read the image file 
 cv::Mat image = cv::imread("D:/My OpenCV Website/Eagle.jpg"); 
 return 0; 
}

Data Types of Arrays

Any single channel array should belong to one of following data types.

  • CV_8U – 8 bit unsigned integer
  • CV_8S – 8 bit signed integer
  • CV_16U – 16 bit unsigned integer
  • CV_16S – 16 bit signed integer
  • CV_32S – 32 bit signed integer
  • CV_32F – 32 bit floating point number
  • CV_64F – 64 bit float floating point number

We can define all of above data types for multi channel arrays. OpenCV supports up to 512 channels. Here I am going to show you how to define CV_8U data type for multi channel arrays.

  • CV_8UC1 – Single channel array with 8 bit unsigned integers which is exactly same as CV_8U
  • CV_8UC2 – 2 channel array with 8 bit unsigned integers
  • CV_8UC3 – 3 channel array with 8 bit unsigned integers
  • CV_8UC4 – 4 channel array with 8 bit unsigned integers
  • CV_8UC(n) – n channel array with 8 bit unsigned integers (n can be from 1 to 512) )

Mat

The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms .
 M.step[i] >= M.step[i+1]

//3 channels 
 //image depth of 8 bits 
 //800 x 600 of resolution (800 wide and 600 high)
 //each pixels initialized to the value of (100, 250, 30) for Blue, Green and Red planes respectively.
 Mat image(600, 800, CV_8UC3, Scalar(100, 250, 30)); 
Mat ()
 
Mat (int rows, int cols, int type)
 
Mat (Size size, int type)
 
Mat (int rows, int cols, int type, const Scalar &s)
 
Mat (Size size, int type, const Scalar &s)
 
Mat (int ndims, const int *sizes, int type)
 
Mat (const std::vector< int > &sizes, int type)
 
Mat (int ndims, const int *sizes, int type, const Scalar &s)//multi dimensional mat
 
Mat (const std::vector< int > &sizes, int type, const Scalar &s)//multi dimensional mat
 
Mat (const Mat &m)//
 
Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)

Mat (const Mat &m, const Rect &roi)//Mat 	operator() (const Rect &roi) const

Mat (const Mat &m, const Range *ranges)//Mat 	operator() (const Range &roi) const

Use a copy constructor or assignment operator where there can be an array or expression on the right side (see below). As noted in the introduction, the array assignment is an O(1) operation because it only copies the header and increases the reference counter. The Mat::clone() method can be used to get a full (deep) copy of the array when you need it.

// make a 7x7 complex matrix filled with 1+3j.
Mat M(7,7,CV_32FC2,Scalar(1,3));
// and now turn M to a 100x60 15-channel 8-bit matrix.
// The old content will be deallocated
M.create(100,60,CV_8UC(15));
// create a 100x100x100 8-bit array
int sz[] = {100, 100, 100};
Mat bigCube(3, sz, CV_8U, Scalar::all(0));
// add the 5-th row, multiplied by 3 to the 3rd row
M.row(3) = M.row(3) + M.row(5)*3;
// now copy the 7-th column to the 1-st column
// M.col(1) = M.col(7); // this will not work
Mat M1 = M.col(1);
M.col(7).copyTo(M1);
// create a new 320x240 image
Mat img(Size(320,240),CV_8UC3);
// select a ROI
Mat roi(img, Rect(10,10,100,100));
// fill the ROI with (0,255,0) (which is green in RGB space);
// the original 320x240 image will be modified
roi = Scalar(0,255,0);
//locateROI
Mat A = Mat::eye(10, 10, CV_32S);
// extracts A columns, 1 (inclusive) to 3 (exclusive).
Mat B = A(Range::all(), Range(1, 3));
// extracts B rows, 5 (inclusive) to 9 (exclusive).
// that is, C \~ A(Range(5, 9), Range(1, 3))
Mat C = B(Range(5, 9), Range::all());
Size size; Point ofs;
C.locateROI(size, ofs);
// size will be (width=10,height=10) and the ofs will be (x=1, y=5)
double m[3][3] = {{a, b, c}, {d, e, f}, {g, h, i}};
Mat M = Mat(3, 3, CV_64F, m).inv();
//Use MATLAB-style array initializers, zeros(), ones(), eye()
// create a double-precision identity matrix and add it to M.
M += Mat::eye(M.rows, M.cols, CV_64F);
// create a 3x3 double-precision identity matrix
Mat M = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);

 If you want to release the data pointed by a array header before the array destructor is called, use Mat::release().

// you can access the element Mij of a 2-dimensional array as:
M.at<double>(i,j) += 1.f;
//rows ptr
// compute sum of positive matrix elements
// (assuming that M is a double-precision matrix)
double sum=0;
for(int i = 0; i < M.rows; i++)
{
    const double* Mi = M.ptr<double>(i);
    for(int j = 0; j < M.cols; j++)
        sum += std::max(Mi[j], 0.);
}

matrix iterator
The matrix iterators are random-access iterators, so they can be passed to any STL algorithm, including std::sort().

// compute sum of positive matrix elements, iterator-based variant
double sum=0;
MatConstIterator_<double> it = M.begin<double>(), it_end = M.end<double>();
for(; it != it_end; ++it)
    sum += std::max(*it, 0.);
//rows and cols and at
Mat H(100, 100, CV_64F);
for(int i = 0; i < H.rows; i++)
    for(int j = 0; j < H.cols; j++)
        H.at<double>(i,j)=1./(i+j+1);
// alternative implementation of Mat::isContinuous()
bool myCheckMatContinuity(const Mat& m)
{
    //return (m.flags & Mat::CONTINUOUS_FLAG) != 0;
    return m.rows == 1 || m.step == m.cols*m.elemSize();
}
//foreach
// Creating 3D matrix (255 x 255 x 255) typed uint8_t
// and initialize all elements by the value which equals elements position.
// i.e. pixels (x,y,z) = (1,2,3) is (b,g,r) = (1,2,3).
int sizes[] = { 255, 255, 255 };
typedef cv::Point3_<uint8_t> Pixel;
Mat_<Pixel> image = Mat::zeros(3, sizes, CV_8UC3);
image.forEach<Pixel>([&](Pixel& pixel, const int position[]) -> void {
    pixel.x = position[0];
    pixel.y = position[1];
    pixel.z = position[2];
});
//reshape
std::vector<Point3f> vec;
...
Mat pointMat = Mat(vec). // convert vector to Mat, O(1) operation
                  reshape(1). // make Nx3 1-channel matrix out of Nx1 3-channel.
                              // Also, an O(1) operation
                     t(); // finally, transpose the Nx3 matrix.
                          // This involves copying all the elements

clone() :
The method creates a full copy of the array .

copyTo(OutputArray) :
The method copies the matrix data to another matrix . Before copying the data, the method invokes : ceate(size,type) .

Mat row(int y) const :
The method makes a new header for the specified matrix row and returns it .

Mat cv::Mat::rowRange( int startrow,int endrow) const :
Creates a matrix header for the specified row span. startrow is inclusive and endrow is exclusive .

same way with col(int) and colRange(int,int)

isSubmatrix() :
return true if the matrix is submatrix of other matrix .

isContinuous():
m.rows == 1 || m.step == m.cols*m.elemSize() so supmatrix is not continues because m.step is the full row elements size but m.cols is sub of original .

adjustROI(int dtop, int dbottom, int dleft, int dright):
Adjusts a submatrix size and position within the parent matrix.

locateROI(Size,Point):
save size of full matrix and offset x and y to point .

reshape(int channels,dimensions) :
Changes the shape and/or the number of channels of a 2D matrix without copying the data.

convertTo(OutputArray m,int rtype,double alpha=1,double beta=0)
m(x,y)=saturate_cast<rType>(α(∗this)(x,y)+β)

Matrix expression representation.

This is a list of implemented matrix operations that can be combined in arbitrary complex expressions (here A, B stand for matrices ( Mat ), s for a scalar ( Scalar ), alpha for a real-valued scalar ( double )):

  • Addition, subtraction, negation: A+BA-BA+sA-ss+As-A-A
  • Scaling: A*alpha
  • Per-element multiplication and division: A.mul(B)A/Balpha/A
  • Matrix multiplication: A*B
  • Transposition: A.t() (means AT)
  • Matrix inversion and pseudo-inversion, solving linear systems and least-squares problems: A.inv([method]) (~ A<sup>-1</sup>)A.inv([method])*B (~ X: AX=B)
  • Comparison: A cmpop BA cmpop alphaalpha cmpop A, where cmpop is one of >>===!=<=<. The result of comparison is an 8-bit single channel mask whose elements are set to 255 (if the particular element or pair of elements satisfy the condition) or 0.
  • Bitwise logical operations: A logicop BA logicop ss logicop A~A, where logicop is one of &|^.
  • Element-wise minimum and maximum: min(A, B)min(A, alpha)max(A, B)max(A, alpha)
  • Element-wise absolute value: abs(A)
  • Cross-product, dot-product: A.cross(B)A.dot(B)
  • Any function of matrix or matrices and scalars that returns a matrix or a scalar, such as norm, mean, sum, countNonZero, trace, determinant, repeat, and others.
  • Matrix initializers ( Mat::eye()Mat::zeros()Mat::ones() ), matrix comma-separated initializers, matrix constructors and operators that extract sub-matrices (see Mat description).
  • Mat_<destination_type>() constructors to cast the result to the proper type.
Mat m1= Mat::eye(2,3, CV_32F); 
Mat m2= Mat::ones(3,2, CV_32F); 
// Scalar by matrix 
cout << "nm1.*2n" << m1*2 << endl; 
// matrix per element multiplication 
cout << "n(m1+2).*(m1+3)n" << (m1+1).mul(m1+3) << endl; 
// Matrix multiplication 
cout << "nm1*m2n" << m1*m2 << endl; 

QImage to Mat and Opposit

image= QImage("C:/Users/malabdali/Pictures/elementary linear algebra.png");
qDebug()<<image.depth();//32 bits depth
m=Mat(image.height(),image.width(),CV_8UC(4),image.bits());
qDebug()<<m.step[0]<<m.step[1]<<" = "<<m.elemSize()<<m.size[1]<<m.type();//2380 number of bytes for row,4 number of bytes for pixel
QImage img((uchar*)mat.data, mat.cols, mat.rows, QImage::Format_RGB32);

most popular type classes

//2d points
typedef Point_<int> Point2i;
typedef Point2i Point;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;
//3d points
typedef Point3_<int> Point3i;
typedef Point3_<float> Point3f;
typedef Point3_<double> Point3d;
//vectors
typedef Vec<uchar, 3> Vec3b;
// 	Scalar (double v0, double v1, double v2=0, double v3=0)
Mat image(600, 800, CV_8UC3, Scalar(100, 250, 30)); 
//Size Rect RotatedRect Point Range
Mat m(image.height(),image.width(),CV_8UC(4),image.bits());
Vec<uint8_t,4> v=m.at<Vec<uint8_t,4>>(200,200);
qDebug()<<v[0]<<v[1]<<v[2];

how to make assignment by your self

Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() == CV_8U);
    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;
}

or use iterator

Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() == CV_8U);
    const int channels = I.channels();
    switch(channels)
    {
    case 1:
        {
            MatIterator_<uchar> it, end;
            for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)
                *it = table[*it];
            break;
        }
    case 3:
        {
            MatIterator_<Vec3b> it, end;
            for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)
            {
                (*it)[0] = table[(*it)[0]];
                (*it)[1] = table[(*it)[1]];
                (*it)[2] = table[(*it)[2]];
            }
        }
    }
    return I;
}

on the fly address

Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() == CV_8U);
    const int channels = I.channels();
    switch(channels)
    {
    case 1:
        {
            for( int i = 0; i < I.rows; ++i)
                for( int j = 0; j < I.cols; ++j )
                    I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
            break;
        }
    case 3:
        {
         Mat_<Vec3b> _I = I;
         for( int i = 0; i < I.rows; ++i)
            for( int j = 0; j < I.cols; ++j )
               {
                   _I(i,j)[0] = table[_I(i,j)[0]];
                   _I(i,j)[1] = table[_I(i,j)[1]];
                   _I(i,j)[2] = table[_I(i,j)[2]];
            }
         I = _I;
         break;
        }
    }
    return I;
}

lookup table modification cv::LUT()
Performs a look-up table transform of an array.
The function LUT fills the output array with values from the look-up table. Indices of the entries are taken from the input array. That is, the function processes each element of src as follows:dst(I)←lut(src(I) )

srcinput array of 8-bit elements.
lutlook-up table of 256 elements; in case of multi-channel input array, the table should either have a single channel (in this case the same table is used for all channels) or the same number of channels as in the input array.
dstoutput array of the same size and number of channels as src, and the same depth as lut.
Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.ptr();
for( int i = 0; i < 256; ++i)
        p[i] = table[i];
LUT(I, lookUpTable, J);

sharpen image example (filter2d or .ptr<>(i,j))

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
static void help(char* progName)
{
    cout << endl
        <<  "This program shows how to filter images with mask: the write it yourself and the"
        << "filter2d way. " << endl
        <<  "Usage:"                                                                        << endl
        << progName << " [image_path -- default lena.jpg] [G -- grayscale] "        << endl << endl;
}
void Sharpen(const Mat& myImage,Mat& Result);
int main( int argc, char* argv[])
{
    help(argv[0]);
    const char* filename = argc >=2 ? argv[1] : "lena.jpg";
    Mat src, dst0, dst1;
    if (argc >= 3 && !strcmp("G", argv[2]))
        src = imread( samples::findFile( filename ), IMREAD_GRAYSCALE);
    else
        src = imread( samples::findFile( filename ), IMREAD_COLOR);
    if (src.empty())
    {
        cerr << "Can't open image ["  << filename << "]" << endl;
        return EXIT_FAILURE;
    }
    namedWindow("Input", WINDOW_AUTOSIZE);
    namedWindow("Output", WINDOW_AUTOSIZE);
    imshow( "Input", src );
    double t = (double)getTickCount();
    Sharpen( src, dst0 );
    t = ((double)getTickCount() - t)/getTickFrequency();
    cout << "Hand written function time passed in seconds: " << t << endl;
    imshow( "Output", dst0 );
    waitKey();
    Mat kernel = (Mat_<char>(3,3) <<  0, -1,  0,
                                   -1,  5, -1,
                                    0, -1,  0);
    t = (double)getTickCount();
    filter2D( src, dst1, src.depth(), kernel );
    t = ((double)getTickCount() - t)/getTickFrequency();
    cout << "Built-in filter2D time passed in seconds:     " << t << endl;
    imshow( "Output", dst1 );
    waitKey();
    return EXIT_SUCCESS;
}
void Sharpen(const Mat& myImage,Mat& Result)
{
    CV_Assert(myImage.depth() == CV_8U);  // accept only uchar images
    const int nChannels = myImage.channels();
    Result.create(myImage.size(),myImage.type());
    for(int j = 1 ; j < myImage.rows-1; ++j)
    {
        const uchar* previous = myImage.ptr<uchar>(j - 1);
        const uchar* current  = myImage.ptr<uchar>(j    );
        const uchar* next     = myImage.ptr<uchar>(j + 1);
        uchar* output = Result.ptr<uchar>(j);
        for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i)
        {
            *output++ = saturate_cast<uchar>(5*current[i]
                         -current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);
        }
    }
    Result.row(0).setTo(Scalar(0));
    Result.row(Result.rows-1).setTo(Scalar(0));
    Result.col(0).setTo(Scalar(0));
    Result.col(Result.cols-1).setTo(Scalar(0));
}