Mat Basic Processing2

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

Shallow copy and deep copy

Example Code:


            //
            // shallow copy and deep copy example
            //
            // When working with image and matrix data in OpenCVForUnity, the concepts of shallow copy and deep copy are important. These two methods differ in how they duplicate data, and can significantly affect the behavior of your program.
            // - Shallow copy: Creates a new Mat object that references the same memory region as the original data.
            // - Deep copy: Creates a new Mat object by copying the data into a new memory region, independent of the original data.
            //

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

            // shallow copy
            Mat m_shallow = mat1;

            // deep copy (clone, copyTo)
            Mat m_deep1 = mat1.clone();
            Mat m_deep2 = new Mat();
            mat1.copyTo (m_deep2);

            Debug.Log ("mat1=" + mat1.dump());
            Debug.Log ("m_shallow=" + m_shallow.dump());
            Debug.Log ("m_deep1=" + m_deep1.dump());
            Debug.Log ("m_deep2=" + m_deep2.dump());

            // rewrite (0, 0) element of matrix mat1
            mat1.put(0, 0, 100);

            Debug.Log ("mat1=" + mat1.dump());
            Debug.Log ("m_shallow=" + m_shallow.dump());
            Debug.Log ("m_deep1=" + m_deep1.dump());
            Debug.Log ("m_deep2=" + m_deep2.dump());

            Debug.Log ("mat1.Equals(m_shallow)=" + mat1.Equals(m_shallow));
            Debug.Log ("mat1.Equals(m_deep1)=" + mat1.Equals(m_deep1));
            Debug.Log ("mat1.Equals(m_deep2)=" + mat1.Equals(m_deep2));
            

Execution Result:

mat1=[1, 2, 3;
 4, 5, 6;
 7, 8, 9]
m_shallow=[1, 2, 3;
 4, 5, 6;
 7, 8, 9]
m_deep1=[1, 2, 3;
 4, 5, 6;
 7, 8, 9]
m_deep2=[1, 2, 3;
 4, 5, 6;
 7, 8, 9]
mat1=[100, 2, 3;
 4, 5, 6;
 7, 8, 9]
m_shallow=[100, 2, 3;
 4, 5, 6;
 7, 8, 9]
m_deep1=[1, 2, 3;
 4, 5, 6;
 7, 8, 9]
m_deep2=[1, 2, 3;
 4, 5, 6;
 7, 8, 9]
mat1.Equals(m_shallow)=True
mat1.Equals(m_deep1)=False
mat1.Equals(m_deep2)=False

Merge

Example Code:


            //
            // merge example
            //
            // The Core.merge function merges multiple Mat objects into a single Mat object.
            // - Number of channels: The number of Mat objects to merge is the number of channels in the output Mat object.
            // - Size: The size(number of rows and columns) of all Mat objects to be combined must match.
            // - Data Type: The data types of all Mat objects to be combined must match.
            //

            // 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:


            //
            // mixChannels example
            //
            // The Core.mixChannels function allows you to freely manipulate the channels of a Mat object.
            // It is used to reorder channels or to create a new Mat object from multiple Mat objects.
            //

            // 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
            //
            // The Core.split function separates a single multi-channel image (e.g., an RGB image) into its individual channels; it is the counterpart to the Core.merge function.
            //

            // 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
            //
            // The Core.reduce function compresses (reduces) a multidimensional array (Mat object) along a specified axis. In other words,
            // it can compress multidimensional data into lower dimensional data.
            //

            // 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]

RandShuffle

Example Code:


            //
            // randShuffle example
            //
            // The Core.randShuffle function randomly shuffles the elements in a Mat object. In other words, it can randomly reorder the order of elements in a Mat object.
            //

            // 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.CoreModule.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)=[15, 4, 14, 7, 6;
 16, 10, 13, 17, 12;
 19, 3, 9, 11, 18;
 5, 20, 1, 8, 2]
m2(sub-matrix)=[10, 13, 17;
 3, 9, 11]
m2(shuffle sub-matrix)=[3, 11, 13;
 10, 9, 17]
m1=[15, 4, 14, 7, 6;
 16, 3, 11, 13, 12;
 19, 10, 9, 17, 18;
 5, 20, 1, 8, 2]

Sort

Example Code:


            //
            // sort example
            //
            // The Core.sort function sorts the elements in a Mat object in ascending or descending order.
            // In other words, it allows you to sort the elements in a Mat object in a specific order.
            //

            // 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=[ 18,  20,   7,  17,  16;
  17,  14,  13,  23,   3;
  19,  20,   9,  21,  23;
  18,  18,  11,  23,  17;
  12,  20,   8,  18,   3]
ROW|ASCENDING:[  7,  16,  17,  18,  20;
   3,  13,  14,  17,  23;
   9,  19,  20,  21,  23;
  11,  17,  18,  18,  23;
   3,   8,  12,  18,  20]
ROW|DESCENDING:[ 20,  18,  17,  16,   7;
  23,  17,  14,  13,   3;
  23,  21,  20,  19,   9;
  23,  18,  18,  17,  11;
  20,  18,  12,   8,   3]
COLUMN|ASCENDING:[ 12,  14,   7,  17,   3;
  17,  18,   8,  18,   3;
  18,  20,   9,  21,  16;
  18,  20,  11,  23,  17;
  19,  20,  13,  23,  23]
COLUMN|DESCENDING:[ 19,  20,  13,  23,  23;
  18,  20,  11,  23,  17;
  18,  20,   9,  21,  16;
  17,  18,   8,  18,   3;
  12,  14,   7,  17,   3]

Comparison

Example Code:


            //
            // comparison example
            //
            // The Core.compare function compares the corresponding elements of two Mat objects and stores the result of the comparison in a new Mat object.
            // When the comparison result is true, the corresponding element of output array is set to 255.
            //

            // 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
            //
            // 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.
            // In c#, it is not possible to explicitly overload compound assignment operators such as “A *= B“.
            // Instead, binary operator overloading is used implicitly.
            // Therefore, whenever an operator is used, a new mat is created and assigned.
            //

            // 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
            Scalar s = new Scalar(5);
            // alpha
            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());
            

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]

Get and Put

Example Code:


            //
            // get and put example
            //
            // mat.get() function gets the value of a specific element in a Mat object.
            // mat.put() function sets a new value for a specific element in a Mat object.
            //
            // OpenCVForUnity has several faster and more efficient functions for accessing Mat elements.
            // - Use the MatUtils.copyFromMat or copyToMat functions to copy through a data array in one go.
            // - Use the mat.at function to access the element of ​​Mat.
            // - Use the mat.AsSpan function to access the data memory area of ​​Mat.
            //

            // 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 elements
            //

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

#if NET_STANDARD_2_1 && !OPENCV_DONT_USE_UNSAFE_CODE
            // an even faster, more efficient, non-memory-allocated method using the mat.at function.
            Span<byte> m1_2_2 = m1.at<byte>(1, 1);
            Debug.Log("m1[2, 2] (use mat.at())= " + m1_2_2[0] + ", " + m1_2_2[1] + ", " + m1_2_2[2] + ", " + m1_2_2[3]);
#endif

            // 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 (use mat.get())=" + dump_str);

            // a faster and more efficient method using the MatUtils.copyFromMat function.
            MatUtils.copyFromMat(m1, m1_array);
            dump_str = ";
            foreach (var i in m1_array)
            {
                dump_str += i + ", ";
            }
            Debug.Log("m1_array (use MatUtils.copyFromMat())=" + dump_str);

#if NET_STANDARD_2_1 && !OPENCV_DONT_USE_UNSAFE_CODE
            // an even faster, more efficient, non-memory-allocated method using the mat.AsSpan function.
            Span<byte> m1_span = m1.AsSpan<byte>();
            dump_str = ";
            for (int i = 0; i < m1_span.Length; i++)
            {
                dump_str += m1_span[i] + ", ";
            }
            Debug.Log("m1_span (use mat.AsSpan())=" + dump_str);
#endif


            //
            // Put elements
            //

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

#if NET_STANDARD_2_1 && !OPENCV_DONT_USE_UNSAFE_CODE
            // an even faster, more efficient, non-memory-allocated method using the mat.at function.
            m2.setTo(new Scalar(1, 2, 3, 4));// reset values
            Span<byte> m2_1_1 = m2.at<byte>(1, 1);
            m2_1_1[0] = 5;
            m2_1_1[1] = 6;
            m2_1_1[2] = 7;
            m2_1_1[3] = 8;
            Debug.Log("m2 (use mat.at())= " + m2.dump());
#endif

            // put an array of element values in a matrix.
            m2.setTo(new Scalar(1, 2, 3, 4));// reset values
            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 (use mat.put())=" + m2.dump());

            // a faster and more efficient method using the MatUtils.copyToMat function.
            m2.setTo(new Scalar(1, 2, 3, 4));// reset values
            MatUtils.copyToMat(m2_arr, m2);
            Debug.Log("m2 (use MatUtils.copyToMat())=" + m2.dump());

#if NET_STANDARD_2_1 && !OPENCV_DONT_USE_UNSAFE_CODE
            // an even faster, more efficient, non-memory-allocated method using the mat.AsSpan function.
            m2.setTo(new Scalar(1, 2, 3, 4));// reset values
            Span<byte> m2_span = m2.AsSpan<byte>();
            m2_arr.AsSpan<byte>().CopyTo(m2_span);
            Debug.Log("m2(use mat.AsSpan()) = " + m2.dump());
#endif

            // fill element values (setTo method)
            m2.setTo(new Scalar(100, 100, 100, 100));
            Debug.Log("m2 (use mat.setTo())=" + 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] (use mat.get())=1, 2, 3, 4
m1[2,2](use mat.at())=1, 2, 3, 4
m1_array (use mat.get())=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 MatUtils.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, 
m1_span (use mat.AsSpan())=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 (use mat.put())=[  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 (use mat.at())=[  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 (use mat.put())=[  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 MatUtils.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 (use mat.AsSpan())=[  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 mat.setTo())=[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 values example (unsafe)
            //

            // 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");

#if NET_STANDARD_2_1 && !OPENCV_DONT_USE_UNSAFE_CODE

            //
            // 2. Use mat.at method
            //
            imgMat.setTo(new Scalar(0, 0, 0, 255));

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

            rows = imgMat.rows();
            cols = imgMat.cols();
            for (int i0 = 0; i0 < rows; i0++)
            {
                for (int i1 = 0; i1 < cols; i1++)
                {
                    // use the mat.at function to access the element of ​​Mat.
                    Span<byte> p = imgMat.at<byte>(i0, i1);

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

            watch.Stop();

            Debug.Log("2.Use mat.at method. time: " + watch.ElapsedMilliseconds + " ms");

#endif

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

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


#if NET_STANDARD_2_1 && !OPENCV_DONT_USE_UNSAFE_CODE

            //
            // 4. Use mat.AsSpan method
            //
            imgMat.setTo(new Scalar(0, 0, 0, 255));

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

            // use the mat.AsSpan function to access the data memory area of ​​Mat.
            Span<byte> img_span = imgMat.AsSpan<byte>();

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

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

                    img_span[p1] = (byte)(img_span[p1] + 127); // R
                    img_span[p2] = (byte)(img_span[p2] + 127); // G
                    img_span[p3] = (byte)(img_span[p3] + 127); // B
                }
            }

            watch.Stop();

            Debug.Log("4.Use mat.AsSpan method. time: " + watch.ElapsedMilliseconds + " ms");

#endif


#if !OPENCV_DONT_USE_UNSAFE_CODE

            //
            // 5. Use pointer access
            //

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

            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("5. Use pointer access. time: " + watch.ElapsedMilliseconds + " ms");

#endif
            

Execution Result:

1. Use get and put method. time: 69 ms
2. Use mat.at method. time: 6 ms
3. Use MatUtils.copyFromMat and MatUtils.copyToMat method. time: 0 ms
4. Use mat.AsSpan method. time: 0 ms
5. Use pointer access. time: 0 ms