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