Mat Basic Processing2

These codes are included in the OpenCVForUnity Example Unity scenes. (MatBasicProcessingExample)

Merge

Example Code:

            //
            // simple composition: Merge example
            //

            // 2x2 matrix
            Mat m1 = new Mat (2, 2, CvType.CV_64FC1);
            m1.put (0, 0, 1.0, 2.0, 3.0, 4.0);
            Mat m2 = new Mat (2, 2, CvType.CV_64FC1);
            m2.put (0, 0, 1.1, 2.1, 3.1, 4.1);
            Mat m3 = new Mat (2, 2, CvType.CV_64FC1);
            m3.put (0, 0, 1.2, 2.2, 3.2, 4.2);

            List<Mat> mv = new List<Mat>();
            mv.Add (m1);
            mv.Add (m2);
            mv.Add (m3);

            // merge
            Mat m_merged = new Mat();
            Core.merge (mv, m_merged);

            // dump
            Debug.Log (""m_merged="" + m_merged.dump());

Execution Result:

m_merged=[1, 1.1, 1.2, 2, 2.1, 2.2;
 3, 3.1, 3.2, 4, 4.1, 4.2]

MixChannels

Example Code:

            //
            // complex composition: mixChannels example
            //

            // 2x2 matrix
            Mat m1 = new Mat (2, 2, CvType.CV_64FC1);
            m1.put (0, 0, 1.0, 2.0, 3.0, 4.0);
            Mat m2 = new Mat (2, 2, CvType.CV_64FC1);
            m2.put (0, 0, 1.1, 2.1, 3.1, 4.1);
            Mat m3 = new Mat (2, 2, CvType.CV_64FC1);
            m3.put (0, 0, 1.2, 2.2, 3.2, 4.2);

            List<Mat> mv = new List<Mat>();
            mv.Add (m1);
            mv.Add (m2);
            mv.Add (m3);

            // mat for output must be allocated.
            Mat m_mixed1 = new Mat(2, 2, CvType.CV_64FC2);
            Mat m_mixed2 = new Mat(2, 2, CvType.CV_64FC2);
            MatOfInt fromTo = new MatOfInt (0,0, 1,1, 1,3, 2,2);

            List<Mat> mixv = new List<Mat> ();
            mixv.Add (m_mixed1);
            mixv.Add (m_mixed2);

            // mix
            Core.mixChannels (mv, mixv, fromTo);

            // dump
            Debug.Log (""m_mixed1="" + m_mixed1.dump());
            Debug.Log (""m_mixed2="" + m_mixed2.dump());

Execution Result:

m_mixed1=[1, 1.1, 2, 2.1;
 3, 3.1, 4, 4.1]
m_mixed2=[1.2, 1.1, 2.2, 2.1;
 3.2, 3.1, 4.2, 4.1]

Split

Example Code:

            //
            // split example
            //

            // channels=3, 2x3 matrix
            Mat m1 = new Mat (2, 3, CvType.CV_64FC3);
            m1.put (0, 0, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18);

            List<Mat> planes = new List<Mat>();

            // split
            Core.split (m1, planes);

            // dump
            foreach (Mat item in planes) {
                Debug.Log (item.dump());
            }

Execution Result:

[1, 4, 7;
 10, 13, 16]
[2, 5, 8;
 11, 14, 17]
[3, 6, 9;
 12, 15, 18]

Reduce

Example Code:

            //
            // reduce example
            //

            // 3x3 matrix
            Mat m1 = new Mat (3, 3, CvType.CV_64FC1);
            m1.put (0, 0, 1, 5, 3, 4, 2, 6, 7, 8, 9);

            Mat v1 = new Mat ();
            Mat v2 = new Mat ();
            Mat v3 = new Mat ();
            Mat v4 = new Mat ();

            // reduce 3 x 3 matrix to one row
            Core.reduce (m1, v1, 0, Core.REDUCE_SUM); // total value of each column
            Core.reduce (m1, v2, 0, Core.REDUCE_AVG); // total average value of each column
            Core.reduce (m1, v3, 0, Core.REDUCE_MIN); // minimum value of each column
            Core.reduce (m1, v4, 0, Core.REDUCE_MAX); // maximum value of each column

            // dump
            Debug.Log (""m1="" + m1.dump());
            Debug.Log (""v1(sum)="" + v1.dump());
            Debug.Log (""v2(avg)="" + v2.dump());
            Debug.Log (""v3(min)="" + v3.dump());
            Debug.Log (""v4(max)="" + v4.dump());

            // reduce 3 x 3 matrix to one col
            Core.reduce (m1, v1, 1, Core.REDUCE_SUM); // total value of each row
            Core.reduce (m1, v2, 1, Core.REDUCE_AVG); // total average value of row
            Core.reduce (m1, v3, 1, Core.REDUCE_MIN); // minimum value of each row
            Core.reduce (m1, v4, 1, Core.REDUCE_MAX); // maximum value of each row

            // dump
            Debug.Log (""m1="" + m1.dump());
            Debug.Log (""v1(sum)="" + v1.dump());
            Debug.Log (""v2(avg)="" + v2.dump());
            Debug.Log (""v3(min)="" + v3.dump());
            Debug.Log (""v4(max)="" + v4.dump());

Execution Result:

m1=[1, 5, 3;
 4, 2, 6;
 7, 8, 9]
v1(sum)=[12, 15, 18]
v2(avg)=[4, 5, 6]
v3(min)=[1, 2, 3]
v4(max)=[7, 8, 9]
m1=[1, 5, 3;
 4, 2, 6;
 7, 8, 9]
v1(sum)=[9;
 12;
 24]
v2(avg)=[3;
 4;
 8]
v3(min)=[1;
 2;
 7]
v4(max)=[5;
 6;
 9]

Submatrix

Example Code:

            //
            // submatrix (ROI) example
            //

            // 3x3 matrix
            Mat m1 = new Mat (3, 3, CvType.CV_64FC1);
            m1.put (0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            Debug.Log (""m1="" + m1.dump ());

            // get submatrix (ROI) of range (row[0_2] col[0_2])
            Mat m2 = new Mat (m1, new OpenCVForUnity.Rect(0,0,2,2));
            Debug.Log (""m2="" + m2.dump());
            Debug.Log (""m2.submat()="" + m2.submat(0,2,0,2).dump());

            // find the parent matrix size of the submatrix (ROI) m2 and its position in it
            Size wholeSize = new Size ();
            Point ofs = new Point ();
            m2.locateROI (wholeSize, ofs);
            Debug.Log (""wholeSize:"" + wholeSize.width + ""x"" + wholeSize.height);
            Debug.Log (""offset:"" + ofs.x + "", "" + ofs.y);

            // expand the range of submatrix (ROI)
            m2.adjustROI(0, 1, 0, 1);
            Debug.Log (""rows="" + m2.rows() + "", "" + ""cols="" + m2.cols());
            Debug.Log (""m2="" + m2.dump());

Execution Result:

m1=[1, 2, 3;
 4, 5, 6;
 7, 8, 9]
m2=[1, 2;
 4, 5]
m2.submat()=[1, 2;
 4, 5]
wholeSize:3x3
offset:0, 0
rows=3, cols=3
m2=[1, 2, 3;
 4, 5, 6;
 7, 8, 9]

RandShuffle

Example Code:

            //
            // randShuffle example
            //

            // 4x5 matrix
            Mat m1 = new Mat (4, 5, CvType.CV_64FC1);
            m1.put (0, 0, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
            Debug.Log (""m1(original)="" + m1.dump ());

            // shuffle
            Core.randShuffle (m1, UnityEngine.Random.value);
            Debug.Log (""m1(shuffle)="" + m1.dump ());

            // submatrix
            Mat m2 = new Mat (m1, new OpenCVForUnity.Rect(1,1,3,2));
            Debug.Log (""m2(sub-matrix)="" + m2.dump());

            Core.randShuffle (m2, UnityEngine.Random.value);
            Debug.Log (""m2(sub-matrix)="" + m2.dump());
            Debug.Log (""m1="" + m1.dump ());

Execution Result:

m1(original)=[1, 2, 3, 4, 5;
 6, 7, 8, 9, 10;
 11, 12, 13, 14, 15;
 16, 17, 18, 19, 20]
m1(shuffle)=[7, 5, 20, 3, 2;
 11, 1, 13, 17, 4;
 12, 19, 14, 6, 16;
 10, 8, 9, 18, 15]
m2(sub-matrix)=[1, 13, 17;
 19, 14, 6]
m2(shuffle sub-matrix)=[1, 6, 19;
 14, 13, 17]
m1=[7, 5, 20, 3, 2;
 11, 1, 6, 19, 4;
 12, 14, 13, 17, 16;
 10, 8, 9, 18, 15]

Sort

Example Code:

            //
            // sort example
            //

            // 5x5 matrix
            Mat m1 = new Mat (5, 5, CvType.CV_8UC1);
            Core.randu (m1, 0, 25);
            Debug.Log (""m1="" + m1.dump ());

            executionResultText.text = ""m1="" + m1.dump() + ""\n"";

            Mat dst_mat = new Mat ();

            // sort ascending
            Core.sort (m1, dst_mat, Core.SORT_EVERY_ROW|Core.SORT_ASCENDING);
            Debug.Log (""ROW|ASCENDING:"" + dst_mat.dump ());

            // sort descending
            Core.sort (m1, dst_mat, Core.SORT_EVERY_ROW|Core.SORT_DESCENDING);
            Debug.Log (""ROW|DESCENDING:"" + dst_mat.dump ());

            // sort ascending
            Core.sort (m1, dst_mat, Core.SORT_EVERY_COLUMN|Core.SORT_ASCENDING);
            Debug.Log (""COLUMN|ASCENDING:"" + dst_mat.dump ());

            // sort descending
            Core.sort (m1, dst_mat, Core.SORT_EVERY_COLUMN|Core.SORT_DESCENDING);
            Debug.Log (""COLUMN|DESCENDING:"" + dst_mat.dump ());

Execution Result:

m1=[ 21,   6,  12,  22,   1;
  21,  10,  22,  23,  15;
   0,  16,   3,   3,  17;
  15,   0,   5,  18,  20;
   7,  17,  16,  17,  14]
ROW|ASCENDING:[  1,   6,  12,  21,  22;
  10,  15,  21,  22,  23;
   0,   3,   3,  16,  17;
   0,   5,  15,  18,  20;
   7,  14,  16,  17,  17]
ROW|DESCENDING:[ 22,  21,  12,   6,   1;
  23,  22,  21,  15,  10;
  17,  16,   3,   3,   0;
  20,  18,  15,   5,   0;
  17,  17,  16,  14,   7]
COLUMN|ASCENDING:[  0,   0,   3,   3,   1;
   7,   6,   5,  17,  14;
  15,  10,  12,  18,  15;
  21,  16,  16,  22,  17;
  21,  17,  22,  23,  20]
COLUMN|DESCENDING:[ 21,  17,  22,  23,  20;
  21,  16,  16,  22,  17;
  15,  10,  12,  18,  15;
   7,   6,   5,  17,  14;
   0,   0,   3,   3,   1]

Comparison

Example Code:

            //
            // comparison example
            //

            // 3x3 matrix
            Mat m1 = new Mat (3, 3, CvType.CV_64FC1);
            m1.put (0, 0, 1,2,3,4,5,6,7,8,9);
            Mat m2 = new Mat (3, 3, CvType.CV_64FC1);
            m2.put (0, 0, 10,11,12,13,14,15,16,17,18);

            Debug.Log (""m1="" + m1.dump ());
            Debug.Log (""m2="" + m2.dump ());

            Mat dst_mat = new Mat ();

            // GT (M1 > M2)
            Core.compare (m1, m2, dst_mat, Core.CMP_GT);
            Debug.Log (""GT (M1 > M2)="" + dst_mat.dump ());

            // GE (M1 >= M2)
            Core.compare (m1, m2, dst_mat, Core.CMP_GE);
            Debug.Log (""GE (M1 >= M2)="" + dst_mat.dump ());

            // EQ (M1 == M2)
            Core.compare (m1, m2, dst_mat, Core.CMP_EQ);
            Debug.Log (""EQ (M1 == M2)="" + dst_mat.dump ());

            // NE (M1 != M2)
            Core.compare (m1, m2, dst_mat, Core.CMP_NE);
            Debug.Log (""NE (M1 != M2)="" + dst_mat.dump ());

            // LE (M1 <= M2)
            Core.compare (m1, m2, dst_mat, Core.CMP_LE);
            Debug.Log (""LE (M1 <= M2)="" + dst_mat.dump ());

            // LT (M1 < M2)
            Core.compare (m1, m2, dst_mat, Core.CMP_LT);
            Debug.Log (""LT (M1 < M2)="" + dst_mat.dump ());

Execution Result:

m1=[1, 2, 3;
 4, 5, 6;
 7, 8, 9]
m2=[9, 8, 7;
 6, 5, 4;
 3, 2, 1]
GT (M1 > M2)=[  0,   0,   0;
   0,   0, 255;
 255, 255, 255]
GE (M1 >= M2)=[  0,   0,   0;
   0, 255, 255;
 255, 255, 255]
EQ (M1 == M2)=[  0,   0,   0;
   0, 255,   0;
   0,   0,   0]
NE (M1 != M2)=[255, 255, 255;
 255,   0, 255;
 255, 255, 255]
LE (M1 <= M2)=[255, 255, 255;
 255, 255,   0;
   0,   0,   0]
LT (M1 < M2)=[255, 255, 255;
 255,   0,   0;
   0,   0,   0]

Operators

Example Code:

            //
            // operators example
            //

            // 3x3 matrix
            Mat m1 = new Mat (3, 3, CvType.CV_64FC1);
            m1.put (0, 0, 1,2,3,4,5,6,7,8,9);
            Mat m2 = new Mat (3, 3, CvType.CV_64FC1);
            m2.put (0, 0, 10,11,12,13,14,15,16,17,18);
            Scalar s = new Scalar (5);
            double alpha = 3;

            Debug.Log (""m1="" + m1.dump ());
            Debug.Log (""m2="" + m2.dump ());
            Debug.Log (""s="" + s);
            Debug.Log (""alpha="" + alpha);

            // Addition, subtraction, negation: A+B, A-B, A+s, A-s, s+A, s-A, -A
            // (M1 + M2 = Core.add (M1, M2, M_dst))
            Debug.Log (""m1+m2="" + (m1 + m2).dump());
            // (M1 + s = Core.add (M1, s, M_dst))
            Debug.Log (""m1+s="" + (m1 + s).dump());

            // (M1 – M2 = Core.subtract (M1, M2, M_dst))
            Debug.Log (""m1-m2="" + (m1 - m2).dump());
            // (M1 – s = Core.subtract (M1, s, M_dst))
            Debug.Log (""m1-s="" + (m1 - s).dump());

            // (-M1 = Core.multiply (M1, Scalar.all (-1), M_dst))
            Debug.Log (""-m1="" + (-m1).dump());


            // Scaling: A*alpha A/alpha
            // (M1 * 3 = Core.multiply (M1, Scalar.all (3), M_dst))
            Debug.Log (""m1*alpha="" + (m1*alpha).dump());
            // (M1 / 3 = Core.divide (M1, Scalar.all (3), M_dst))
            Debug.Log (""m1/alpha="" + (m1/alpha).dump());


            // Per-element multiplication and division: A.mul(B), A/B, alpha/A
            // (M1.mul(M2) = M1.mul (M2))
            Debug.Log (""m1.mul(m2)="" + (m1.mul(m2)).dump());

            // (M1 / M2 = Core.divide (M1, M2, M_dst))
            Debug.Log (""m1/m2="" + (m1 / m2).dump());

            // (3 / M1 = Core.divide (new Mat (M1.size (), M1.type (), Scalar.all (3)), M1, M_dst))
            Debug.Log (""alpha/m2="" + (alpha / m2).dump());


            // Matrix multiplication: A*B
            // (M1 * M2 = Core.gemm (M1, M2, 1, new Mat (), 0, M_dst))
            Debug.Log (""m1*m2="" + (m1 * m2).dump());


            // Bitwise logical operations: A logicop B, A logicop s, s logicop A, ~A, where logicop is one of :  &, |, ^.
            // (M1 & M2 = Core.bitwise_and (M1, M2, M_dst))
            Debug.Log (""m1&m2="" + (m1 & m2).dump());

            // (M1 | M2 = Core.bitwise_or (M1, M2, M_dst))
            Debug.Log (""m1|m2="" + (m1 | m2).dump());

            // (M1 ^ M2 = Core.bitwise_xor (M1, M2, M_dst))
            Debug.Log (""m1^m2="" + (m1 ^ m2).dump());

            // (~M1 = Core.bitwise_not (M1, M_dst))
            Debug.Log (""~m1="" + (~m1).dump());
			
            // Note.
            // The assignment operator behavior is different from OpenCV (c ++). 
            // For example, C = A + B will not be expanded to cv::add(A, B, C).
            // Also cannot assign a scalar to Mat like C = s.

Execution Result:

m1=[1, 2, 3;
 4, 5, 6;
 7, 8, 9]
m2=[10, 11, 12;
 13, 14, 15;
 16, 17, 18]
s=[5, 0, 0, 0]
alpha=3
m1+m2=[11, 13, 15;
 17, 19, 21;
 23, 25, 27]
m1+s=[6, 7, 8;
 9, 10, 11;
 12, 13, 14]
m1-m2=[-9, -9, -9;
 -9, -9, -9;
 -9, -9, -9]
m1-s=[-4, -3, -2;
 -1, 0, 1;
 2, 3, 4]
-m1=[-1, -2, -3;
 -4, -5, -6;
 -7, -8, -9]
m1*alpha=[3, 6, 9;
 12, 15, 18;
 21, 24, 27]
m1/alpha=[0.3333333333333333, 0.6666666666666666, 1;
 1.333333333333333, 1.666666666666667, 2;
 2.333333333333333, 2.666666666666667, 3]
m1.mul(m2)=[10, 22, 36;
 52, 70, 90;
 112, 136, 162]
m1/m2=[0.1, 0.1818181818181818, 0.25;
 0.3076923076923077, 0.3571428571428572, 0.4;
 0.4375, 0.4705882352941176, 0.5]
alpha/m2=[0.3, 0.2727272727272727, 0.25;
 0.2307692307692308, 0.2142857142857143, 0.2;
 0.1875, 0.1764705882352941, 0.1666666666666667]
m1*m2=[84, 90, 96;
 201, 216, 231;
 318, 342, 366]
m1&m2=[4.450147717014403e-308, 2, 3;
 2, 2.5, 3;
 4, 8, 9]
m1|m2=[nan(snan), 11, 12;
 26, 28, 30;
 28, 17, 18]
m1^m2=[5.617791046444737e+307, 6.118953110894804e-308, 4.450147717014403e-308;
 1.446298008029681e-307, 1.335044315104321e-307, 1.223790622178961e-307;
 7.787758504775205e-308, 2.364140974663901e-308, 2.225073858507201e-308]
~m1=[-4, -2, -1.5;
 -0.9999999999999999, -0.8749999999999999, -0.7499999999999999;
 -0.6249999999999999, -0.4999999999999999, -0.4687499999999999]	
	
// Note.
// The assignment operator behavior is different from OpenCV (c ++). 
// For example, C = A + B will not be expanded to cv::add(A, B, C).
// Also cannot assign a scalar to Mat like C = s.

Get And Put

Example Code:

            //
            // get and put example
            //

            // channels=4 3x3 matrix
            Mat m1 = new Mat (3, 3, CvType.CV_8UC4 , new Scalar(1,2,3,4));
            Debug.Log (""m1="" + m1.dump ());


            // get an element value.
            double[] m1_1_1 = m1.get(1,1);
            Debug.Log (""m1[1,1]="" + m1_1_1[0] + "", "" + m1_1_1[1] + "", "" + m1_1_1[2] + "", "" + m1_1_1[3]);

            // get an array of all element values.
            byte[] m1_array = new byte[m1.total () * m1.channels()];
            m1.get (0, 0, m1_array);

            string dump_str = """";
            foreach (var i in m1_array){
                dump_str += i + "", "";
            }
            Debug.Log (""m1_array="" + dump_str);
			
            // another faster way. (use Utils.copyFromMat())
            Utils.copyFromMat (m1, m1_array);

            dump_str = "";
            foreach (var i in m1_array) {
                dump_str += i + ", ";
            }
            Debug.Log ("m1_array (use Utils.copyFromMat())=" + dump_str);


            // put an element value in a matrix.
            Mat m2 = m1.clone ();
            m2.put (1, 1, 5,6,7,8);
            Debug.Log (""m2="" + m2.dump ());

            // put an array of element values in a matrix.
            byte[] m2_arr = new byte[]{5,6,7,8,5,6,7,8,5,6,7,8,5,6,7,8,5,6,7,8,5,6,7,8,5,6,7,8,5,6,7,8,5,6,7,8};
            m2.put (0, 0, m2_arr);
            Debug.Log (""m2="" + m2.dump ());
			
            // another faster way. (use Utils.copyToMat())
            Utils.copyToMat (m2_arr, m2);
            Debug.Log ("m2 (use Utils.copyToMat())=" + m2.dump ());
			

            // fill element values (setTo method)
            m2.setTo(new Scalar(100,100,100,100));
            Debug.Log (""m2="" + m2.dump ());

Execution Result:

m1=[  1,   2,   3,   4,   1,   2,   3,   4,   1,   2,   3,   4;
   1,   2,   3,   4,   1,   2,   3,   4,   1,   2,   3,   4;
   1,   2,   3,   4,   1,   2,   3,   4,   1,   2,   3,   4]
m1[1,1]=1, 2, 3, 4
m1_array=1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 
m1_array (use Utils.copyFromMat())=1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 
m2=[  1,   2,   3,   4,   1,   2,   3,   4,   1,   2,   3,   4;
   1,   2,   3,   4,   5,   6,   7,   8,   1,   2,   3,   4;
   1,   2,   3,   4,   1,   2,   3,   4,   1,   2,   3,   4]
m2=[  5,   6,   7,   8,   5,   6,   7,   8,   5,   6,   7,   8;
   5,   6,   7,   8,   5,   6,   7,   8,   5,   6,   7,   8;
   5,   6,   7,   8,   5,   6,   7,   8,   5,   6,   7,   8]
m2 (use Utils.copyToMat())=[  5,   6,   7,   8,   5,   6,   7,   8,   5,   6,   7,   8;
   5,   6,   7,   8,   5,   6,   7,   8,   5,   6,   7,   8;
   5,   6,   7,   8,   5,   6,   7,   8,   5,   6,   7,   8]
m2=[100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100;
 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100;
 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100]

Accessing Pixel Values

Example Code:

            //
            // accessing pixel value example
            //

            // How access pixel value in an OpenCV Mat.

            // channels=4 512x512 matrix (RGBA color image)
            Mat imgMat = new Mat(512, 512, CvType.CV_8UC4, new Scalar(0, 0, 0, 255));


            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();

            //
            // 1. Use get and put method.
            //
            imgMat.setTo(new Scalar(0, 0, 0, 255));

            watch.Start();

            int rows = imgMat.rows();
            int cols = imgMat.cols();
            for (int i0 = 0; i0 < rows; i0++)
            {
                for (int i1 = 0; i1 < cols; i1++)
                {
                    byte[] p = new byte[4];
                    imgMat.get(i0, i1, p);

                    p[0] = (byte)(p[0] + 127); // R
                    p[1] = (byte)(p[1] + 127); // G
                    p[2] = (byte)(p[2] + 127); // B

                    imgMat.put(i0, i1, p);
                }
            }

            watch.Stop();

            Debug.Log("1. Use get and put method. time: " + watch.ElapsedMilliseconds + " ms");
            executionResultText.text = "1. Use get and put method. time: " + watch.ElapsedMilliseconds + " ms" + "\n";


            //
            // 2. Use MatIndexer.
            //
            imgMat.setTo(new Scalar(0, 0, 0, 255));

            watch.Stop();
            watch.Reset();
            watch.Start();

            MatIndexer indexer = new MatIndexer(imgMat);
            rows = imgMat.rows();
            cols = imgMat.cols();
            for (int i0 = 0; i0 < rows; i0++)
            {
                for (int i1 = 0; i1 < cols; i1++)
                {
                    byte[] p = new byte[4];
                    indexer.get(i0, i1, p);

                    p[0] = (byte)(p[0] + 127); // R
                    p[1] = (byte)(p[1] + 127); // G
                    p[2] = (byte)(p[2] + 127); // B

                    indexer.put(i0, i1, p);
                }
            }

            watch.Stop();

            Debug.Log("2. Use MatIndexer. time: " + watch.ElapsedMilliseconds + " ms");
            executionResultText.text += "2. Use MatIndexer. time: " + watch.ElapsedMilliseconds + " ms" + "\n";


            //
            // 3. Use MatUtils.copyFromMat and MatUtils.copyToMat method.
            //
            imgMat.setTo(new Scalar(0, 0, 0, 255));

            watch.Stop();
            watch.Reset();
            watch.Start();

            // Copies an OpenCV Mat data to a pixel data Array.
            byte[] img_array = new byte[imgMat.total() * imgMat.channels()];
            MatUtils.copyFromMat(imgMat, img_array);

            long step0 = imgMat.step1(0);
            long step1 = imgMat.step1(1);

            rows = imgMat.rows();
            cols = imgMat.cols();
            for (int i0 = 0; i0 < rows; i0++)
            {
                for (int i1 = 0; i1 < cols; i1++)
                {
                    long p1 = step0 * i0 + step1 * i1;
                    long p2 = p1 + 1;
                    long p3 = p1 + 2;

                    img_array[p1] = (byte)(img_array[p1] + 127); // R
                    img_array[p2] = (byte)(img_array[p2] + 127); // G
                    img_array[p3] = (byte)(img_array[p3] + 127); // B
                }
            }
            // Copies a pixel data Array to an OpenCV Mat data.
            MatUtils.copyToMat(img_array, imgMat);

            watch.Stop();

            Debug.Log("3. Use MatUtils.copyFromMat and MatUtils.copyToMat method. time: " + watch.ElapsedMilliseconds + " ms");
            executionResultText.text += "3. Use MatUtils.copyFromMat and MatUtils.copyToMat method. time: " + watch.ElapsedMilliseconds + " ms" + "\n";


#if OPENCV_USE_UNSAFE_CODE

            //
            // 4. Use pointer access.
            //

            imgMat.setTo(new Scalar(0, 0, 0, 255));

            watch.Stop();
            watch.Reset();
            watch.Start();

            step0 = imgMat.step1(0);
            step1 = imgMat.step1(1);
            long ptrVal = imgMat.dataAddr();

            unsafe
            {
                rows = imgMat.rows();
                cols = imgMat.cols();
                for (int i0 = 0; i0 < rows; i0++)
                {
                    for (int i1 = 0; i1 < cols; i1++)
                    {
                        byte* p1 = (byte*)(ptrVal + (step0 * i0) + (step1 * i1));
                        byte* p2 = p1 + 1;
                        byte* p3 = p1 + 2;

                        *p1 = (byte)(*p1 + 127); // R
                        *p2 = (byte)(*p2 + 127); // G
                        *p3 = (byte)(*p3 + 127); // B
                    }
                }
            }

            watch.Stop();

            Debug.Log("4. Use pointer access. time: " + watch.ElapsedMilliseconds + " ms");
            executionResultText.text += "4. Use pointer access. time: " + watch.ElapsedMilliseconds + " ms" + "\n";

#endif

Execution Result:

1. Use get and put method. time: 107 ms
2. Use MatIndexer. time: 60 ms
3. Use MatUtils.copyFromMat and MatUtils.copyToMat method. time: 4 ms
4. Use pointer access. time: 1 ms