Merge pull request #13956 from komakai:java-mat-class-improvements
authorGiles Payne <gilespayne@telepathix.net>
Sat, 9 Mar 2019 21:11:04 +0000 (06:11 +0900)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Sat, 9 Mar 2019 21:11:04 +0000 (00:11 +0300)
* Expose more C++ functionality in the Java wrapper of the Mat class
In particular expose methods for handling Mat with more than 2 dimensions
* add constructors taking an array of dimension sizes
* add constructor taking an existing Mat and an array of Ranges
* add override of the create method taking an array of dimension sizes
* add overrides of the ones and zeros methods taking an array of dimension sizes
* add override of the submat method taking an array of ranges
* add overrides of put and get taking arrays of indices
* add wrapper for copySize method
* fix crash in the JNI wrapper of the reshape(int cn, int[] newshape) method
* add test for each method added to Mat.java

* Fix broken test

modules/core/misc/java/src/java/core+Mat.java
modules/core/misc/java/test/MatTest.java
modules/java/generator/src/cpp/Mat.cpp
modules/java/test/android_test/src/org/opencv/test/OpenCVTestCase.java
modules/java/test/pure_test/src/org/opencv/test/OpenCVTestCase.java

index c75f9d5..e42fca9 100644 (file)
@@ -68,6 +68,19 @@ public class Mat {
     }
 
     //
+    // C++: Mat::Mat(int ndims, const int* sizes, int type)
+    //
+
+    // javadoc: Mat::Mat(sizes, type)
+    public Mat(int[] sizes, int type)
+    {
+
+        nativeObj = n_Mat(sizes.length, sizes, type);
+
+        return;
+    }
+
+    //
     // C++: Mat::Mat(int rows, int cols, int type, Scalar s)
     //
 
@@ -94,6 +107,19 @@ public class Mat {
     }
 
     //
+    // C++: Mat::Mat(int ndims, const int* sizes, int type, Scalar s)
+    //
+
+    // javadoc: Mat::Mat(sizes, type, s)
+    public Mat(int[] sizes, int type, Scalar s)
+    {
+
+        nativeObj = n_Mat(sizes.length, sizes, type, s.val[0], s.val[1], s.val[2], s.val[3]);
+
+        return;
+    }
+
+    //
     // C++: Mat::Mat(Mat m, Range rowRange, Range colRange = Range::all())
     //
 
@@ -116,6 +142,19 @@ public class Mat {
     }
 
     //
+    // C++: Mat::Mat(const Mat& m, const std::vector<Range>& ranges)
+    //
+
+    // javadoc: Mat::Mat(m, ranges)
+    public Mat(Mat m, Range[] ranges)
+    {
+
+        nativeObj = n_Mat(m.nativeObj, ranges);
+
+        return;
+    }
+
+    //
     // C++: Mat::Mat(Mat m, Rect roi)
     //
 
@@ -371,6 +410,31 @@ public class Mat {
     }
 
     //
+    // C++: void Mat::create(int ndims, const int* sizes, int type)
+    //
+
+    // javadoc: Mat::create(sizes, type)
+    public void create(int[] sizes, int type)
+    {
+
+        n_create(nativeObj, sizes.length, sizes, type);
+
+        return;
+    }
+
+    //
+    // C++: void Mat::copySize(const Mat& m);
+    //
+
+    // javadoc: Mat::copySize(m)
+    public void copySize(Mat m)
+    {
+        n_copySize(nativeObj, m.nativeObj);
+
+        return;
+    }
+
+    //
     // C++: Mat Mat::cross(Mat m)
     //
 
@@ -634,6 +698,19 @@ public class Mat {
     }
 
     //
+    // C++: static Mat Mat::ones(int ndims, const int* sizes, int type)
+    //
+
+    // javadoc: Mat::ones(sizes, type)
+    public static Mat ones(int[] sizes, int type)
+    {
+
+        Mat retVal = new Mat(n_ones(sizes.length, sizes, type));
+
+        return retVal;
+    }
+
+    //
     // C++: void Mat::push_back(Mat m)
     //
 
@@ -868,6 +945,19 @@ public class Mat {
     }
 
     //
+    // C++: Mat Mat::operator()(const std::vector<Range>& ranges)
+    //
+
+    // javadoc: Mat::operator()(ranges[])
+    public Mat submat(Range[] ranges)
+    {
+
+        Mat retVal = new Mat(n_submat_ranges(nativeObj, ranges));
+
+        return retVal;
+    }
+
+    //
     // C++: Mat Mat::operator()(Rect roi)
     //
 
@@ -945,6 +1035,19 @@ public class Mat {
         return retVal;
     }
 
+    //
+    // C++: static Mat Mat::zeros(int ndims, const int* sizes, int type)
+    //
+
+    // javadoc: Mat::zeros(sizes, type)
+    public static Mat zeros(int[] sizes, int type)
+    {
+
+        Mat retVal = new Mat(n_zeros(sizes.length, sizes, type));
+
+        return retVal;
+    }
+
     @Override
     protected void finalize() throws Throwable {
         n_delete(nativeObj);
@@ -979,6 +1082,20 @@ public class Mat {
         return nPutD(nativeObj, row, col, data.length, data);
     }
 
+    // javadoc:Mat::put(idx,data)
+    public int put(int[] idx, double... data) {
+        int t = type();
+        if (data == null || data.length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        return nPutDIdx(nativeObj, idx, data.length, data);
+    }
+
     // javadoc:Mat::put(row,col,data)
     public int put(int row, int col, float[] data) {
         int t = type();
@@ -994,6 +1111,23 @@ public class Mat {
         throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
     }
 
+    // javadoc:Mat::put(idx,data)
+    public int put(int[] idx, float[] data) {
+        int t = type();
+        if (data == null || data.length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        if (CvType.depth(t) == CvType.CV_32F) {
+            return nPutFIdx(nativeObj, idx, data.length, data);
+        }
+        throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
+    }
+
     // javadoc:Mat::put(row,col,data)
     public int put(int row, int col, int[] data) {
         int t = type();
@@ -1009,6 +1143,23 @@ public class Mat {
         throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
     }
 
+    // javadoc:Mat::put(idx,data)
+    public int put(int[] idx, int[] data) {
+        int t = type();
+        if (data == null || data.length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        if (CvType.depth(t) == CvType.CV_32S) {
+            return nPutIIdx(nativeObj, idx, data.length, data);
+        }
+        throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
+    }
+
     // javadoc:Mat::put(row,col,data)
     public int put(int row, int col, short[] data) {
         int t = type();
@@ -1024,6 +1175,23 @@ public class Mat {
         throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
     }
 
+    // javadoc:Mat::put(idx,data)
+    public int put(int[] idx, short[] data) {
+        int t = type();
+        if (data == null || data.length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        if (CvType.depth(t) == CvType.CV_16U || CvType.depth(t) == CvType.CV_16S) {
+            return nPutSIdx(nativeObj, idx, data.length, data);
+        }
+        throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
+    }
+
     // javadoc:Mat::put(row,col,data)
     public int put(int row, int col, byte[] data) {
         int t = type();
@@ -1039,6 +1207,23 @@ public class Mat {
         throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
     }
 
+    // javadoc:Mat::put(idx,data)
+    public int put(int[] idx, byte[] data) {
+        int t = type();
+        if (data == null || data.length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        if (CvType.depth(t) == CvType.CV_8U || CvType.depth(t) == CvType.CV_8S) {
+            return nPutBIdx(nativeObj, idx, data.length, data);
+        }
+        throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
+    }
+
     // javadoc:Mat::put(row,col,data,offset,length)
     public int put(int row, int col, byte[] data, int offset, int length) {
         int t = type();
@@ -1054,6 +1239,23 @@ public class Mat {
         throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
     }
 
+    // javadoc:Mat::put(idx,data,offset,length)
+    public int put(int[] idx, byte[] data, int offset, int length) {
+        int t = type();
+        if (data == null || length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        if (CvType.depth(t) == CvType.CV_8U || CvType.depth(t) == CvType.CV_8S) {
+            return nPutBwIdxOffset(nativeObj, idx, length, offset, data);
+        }
+        throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
+    }
+
     // javadoc:Mat::get(row,col,data)
     public int get(int row, int col, byte[] data) {
         int t = type();
@@ -1069,6 +1271,23 @@ public class Mat {
         throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
     }
 
+    // javadoc:Mat::get(idx,data)
+    public int get(int[] idx, byte[] data) {
+        int t = type();
+        if (data == null || data.length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        if (CvType.depth(t) == CvType.CV_8U || CvType.depth(t) == CvType.CV_8S) {
+            return nGetBIdx(nativeObj, idx, data.length, data);
+        }
+        throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
+    }
+
     // javadoc:Mat::get(row,col,data)
     public int get(int row, int col, short[] data) {
         int t = type();
@@ -1084,6 +1303,23 @@ public class Mat {
         throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
     }
 
+    // javadoc:Mat::get(idx,data)
+    public int get(int[] idx, short[] data) {
+        int t = type();
+        if (data == null || data.length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        if (CvType.depth(t) == CvType.CV_16U || CvType.depth(t) == CvType.CV_16S) {
+            return nGetSIdx(nativeObj, idx, data.length, data);
+        }
+        throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
+    }
+
     // javadoc:Mat::get(row,col,data)
     public int get(int row, int col, int[] data) {
         int t = type();
@@ -1099,6 +1335,23 @@ public class Mat {
         throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
     }
 
+    // javadoc:Mat::get(idx,data)
+    public int get(int[] idx, int[] data) {
+        int t = type();
+        if (data == null || data.length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        if (CvType.depth(t) == CvType.CV_32S) {
+            return nGetIIdx(nativeObj, idx, data.length, data);
+        }
+        throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
+    }
+
     // javadoc:Mat::get(row,col,data)
     public int get(int row, int col, float[] data) {
         int t = type();
@@ -1114,6 +1367,23 @@ public class Mat {
         throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
     }
 
+    // javadoc:Mat::get(idx,data)
+    public int get(int[] idx, float[] data) {
+        int t = type();
+        if (data == null || data.length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        if (CvType.depth(t) == CvType.CV_32F) {
+            return nGetFIdx(nativeObj, idx, data.length, data);
+        }
+        throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
+    }
+
     // javadoc:Mat::get(row,col,data)
     public int get(int row, int col, double[] data) {
         int t = type();
@@ -1129,11 +1399,35 @@ public class Mat {
         throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
     }
 
+    // javadoc:Mat::get(idx,data)
+    public int get(int[] idx, double[] data) {
+        int t = type();
+        if (data == null || data.length % CvType.channels(t) != 0)
+            throw new java.lang.UnsupportedOperationException(
+                    "Provided data element number (" +
+                            (data == null ? 0 : data.length) +
+                            ") should be multiple of the Mat channels count (" +
+                            CvType.channels(t) + ")");
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        if (CvType.depth(t) == CvType.CV_64F) {
+            return nGetDIdx(nativeObj, idx, data.length, data);
+        }
+        throw new java.lang.UnsupportedOperationException("Mat data type is not compatible: " + t);
+    }
+
     // javadoc:Mat::get(row,col)
     public double[] get(int row, int col) {
         return nGet(nativeObj, row, col);
     }
 
+    // javadoc:Mat::get(idx)
+    public double[] get(int[] idx) {
+        if (idx.length != dims())
+            throw new IllegalArgumentException("Incorrect number of indices");
+        return nGetIdx(nativeObj, idx);
+    }
+
     // javadoc:Mat::height()
     public int height() {
         return rows();
@@ -1155,6 +1449,9 @@ public class Mat {
     // C++: Mat::Mat(int rows, int cols, int type)
     private static native long n_Mat(int rows, int cols, int type);
 
+    // C++: Mat::Mat(int ndims, const int* sizes, int type)
+    private static native long n_Mat(int ndims, int[] sizes, int type);
+
     // C++: Mat::Mat(int rows, int cols, int type, void* data)
     private static native long n_Mat(int rows, int cols, int type, ByteBuffer data);
 
@@ -1167,11 +1464,17 @@ public class Mat {
     // C++: Mat::Mat(Size size, int type, Scalar s)
     private static native long n_Mat(double size_width, double size_height, int type, double s_val0, double s_val1, double s_val2, double s_val3);
 
+    // C++: Mat::Mat(int ndims, const int* sizes, int type, Scalar s)
+    private static native long n_Mat(int ndims, int[] sizes, int type, double s_val0, double s_val1, double s_val2, double s_val3);
+
     // C++: Mat::Mat(Mat m, Range rowRange, Range colRange = Range::all())
     private static native long n_Mat(long m_nativeObj, int rowRange_start, int rowRange_end, int colRange_start, int colRange_end);
 
     private static native long n_Mat(long m_nativeObj, int rowRange_start, int rowRange_end);
 
+    // C++: Mat::Mat(const Mat& m, const std::vector<Range>& ranges)
+    private static native long n_Mat(long m_nativeObj, Range[] ranges);
+
     // C++: Mat Mat::adjustROI(int dtop, int dbottom, int dleft, int dright)
     private static native long n_adjustROI(long nativeObj, int dtop, int dbottom, int dleft, int dright);
 
@@ -1226,6 +1529,12 @@ public class Mat {
     // C++: void Mat::create(Size size, int type)
     private static native void n_create(long nativeObj, double size_width, double size_height, int type);
 
+    // C++: void Mat::create(int ndims, const int* sizes, int type)
+    private static native void n_create(long nativeObj, int ndims, int[] sizes, int type);
+
+    // C++: void Mat::copySize(const Mat& m)
+    private static native void n_copySize(long nativeObj, long m_nativeObj);
+
     // C++: Mat Mat::cross(Mat m)
     private static native long n_cross(long nativeObj, long m_nativeObj);
 
@@ -1284,6 +1593,9 @@ public class Mat {
     // C++: static Mat Mat::ones(Size size, int type)
     private static native long n_ones(double size_width, double size_height, int type);
 
+    // C++: static Mat Mat::ones(int ndims, const int* sizes, int type)
+    private static native long n_ones(int ndims, int[] sizes, int type);
+
     // C++: void Mat::push_back(Mat m)
     private static native void n_push_back(long nativeObj, long m_nativeObj);
 
@@ -1332,6 +1644,9 @@ public class Mat {
     // C++: Mat Mat::operator()(Range rowRange, Range colRange)
     private static native long n_submat_rr(long nativeObj, int rowRange_start, int rowRange_end, int colRange_start, int colRange_end);
 
+    // C++: Mat Mat::operator()(const std::vector<Range>& ranges)
+    private static native long n_submat_ranges(long nativeObj, Range[] ranges);
+
     // C++: Mat Mat::operator()(Rect roi)
     private static native long n_submat(long nativeObj, int roi_x, int roi_y, int roi_width, int roi_height);
 
@@ -1350,32 +1665,59 @@ public class Mat {
     // C++: static Mat Mat::zeros(Size size, int type)
     private static native long n_zeros(double size_width, double size_height, int type);
 
+    // C++: static Mat Mat::zeros(int ndims, const int* sizes, int type)
+    private static native long n_zeros(int ndims, int[] sizes, int type);
+
     // native support for java finalize()
     private static native void n_delete(long nativeObj);
 
     private static native int nPutD(long self, int row, int col, int count, double[] data);
 
+    private static native int nPutDIdx(long self, int[] idx, int count, double[] data);
+
     private static native int nPutF(long self, int row, int col, int count, float[] data);
 
+    private static native int nPutFIdx(long self, int[] idx, int count, float[] data);
+
     private static native int nPutI(long self, int row, int col, int count, int[] data);
 
+    private static native int nPutIIdx(long self, int[] idx, int count, int[] data);
+
     private static native int nPutS(long self, int row, int col, int count, short[] data);
 
+    private static native int nPutSIdx(long self, int[] idx, int count, short[] data);
+
     private static native int nPutB(long self, int row, int col, int count, byte[] data);
 
+    private static native int nPutBIdx(long self, int[] idx, int count, byte[] data);
+
     private static native int nPutBwOffset(long self, int row, int col, int count, int offset, byte[] data);
 
+    private static native int nPutBwIdxOffset(long self, int[] idx, int count, int offset, byte[] data);
+
     private static native int nGetB(long self, int row, int col, int count, byte[] vals);
 
+    private static native int nGetBIdx(long self, int[] idx, int count, byte[] vals);
+
     private static native int nGetS(long self, int row, int col, int count, short[] vals);
 
+    private static native int nGetSIdx(long self, int[] idx, int count, short[] vals);
+
     private static native int nGetI(long self, int row, int col, int count, int[] vals);
 
+    private static native int nGetIIdx(long self, int[] idx, int count, int[] vals);
+
     private static native int nGetF(long self, int row, int col, int count, float[] vals);
 
+    private static native int nGetFIdx(long self, int[] idx, int count, float[] vals);
+
     private static native int nGetD(long self, int row, int col, int count, double[] vals);
 
+    private static native int nGetDIdx(long self, int[] idx, int count, double[] vals);
+
     private static native double[] nGet(long self, int row, int col);
 
+    private static native double[] nGetIdx(long self, int[] idx);
+
     private static native String nDump(long self);
 }
index f0f4fdc..4c8c52b 100644 (file)
@@ -185,6 +185,16 @@ public class MatTest extends OpenCVTestCase {
         assertEquals(CvType.CV_16U, dst.type());
     }
 
+    public void testCreateIntArrayInt() {
+        int[] dims = new int[] {5, 6, 7};
+        dst.create(dims, CvType.CV_16U);
+
+        assertEquals(5, dst.size(0));
+        assertEquals(6, dst.size(1));
+        assertEquals(7, dst.size(2));
+        assertEquals(CvType.CV_16U, dst.type());
+    }
+
     public void testCross() {
         Mat answer = new Mat(1, 3, CvType.CV_32F);
         answer.put(0, 0, 7.0, 1.0, -5.0);
@@ -569,6 +579,15 @@ public class MatTest extends OpenCVTestCase {
         assertMatEqual(truth, dst, EPS);
     }
 
+    public void testMatMatRangeArray() {
+        dst = new Mat(gray255_32f_3d, new Range[]{new Range(0, 5), new Range(0, 5), new Range(0, 5)});
+
+        truth = new Mat(new int[] {5, 5, 5}, CvType.CV_32FC1, new Scalar(255));
+
+        assertFalse(dst.empty());
+        assertMatEqual(truth, dst, EPS);
+    }
+
     public void testMatMatRect() {
         Mat m = new Mat(7, 6, CvType.CV_32SC1);
         m.put(0,  0,
@@ -606,6 +625,13 @@ public class MatTest extends OpenCVTestCase {
         assertMatEqual(gray255_32f, dst, EPS);
     }
 
+    public void testMatIntArrayIntScalar() {
+        dst = new Mat(new int[]{10, 10, 10}, CvType.CV_32F, new Scalar(255));
+
+        assertFalse(dst.empty());
+        assertMatEqual(gray255_32f_3d, dst, EPS);
+    }
+
     public void testMulMat() {
         assertMatEqual(gray0, gray0.mul(gray255));
 
@@ -619,6 +645,16 @@ public class MatTest extends OpenCVTestCase {
 
     }
 
+    public void testMulMat3d() {
+        Mat m1 = new Mat(new int[] {2, 2, 2}, CvType.CV_32F, new Scalar(2));
+        Mat m2 = new Mat(new int[] {2, 2, 2}, CvType.CV_32F, new Scalar(3));
+
+        dst = m1.mul(m2);
+
+        truth = new Mat(new int[] {2, 2, 2}, CvType.CV_32F, new Scalar(6));
+        assertMatEqual(truth, dst, EPS);
+    }
+
     public void testMulMatDouble() {
         Mat m1 = new Mat(2, 2, CvType.CV_32F, new Scalar(2));
         Mat m2 = new Mat(2, 2, CvType.CV_32F, new Scalar(3));
@@ -642,6 +678,12 @@ public class MatTest extends OpenCVTestCase {
         assertMatEqual(truth, dst);
     }
 
+    public void testOnesIntArrayInt() {
+        dst = Mat.ones(new int[]{2, 2, 2}, CvType.CV_16S);
+        truth = new Mat(new int[]{2, 2, 2}, CvType.CV_16S, new Scalar(1));
+        assertMatEqual(truth, dst);
+    }
+
     public void testPush_back() {
         Mat m1 = new Mat(2, 4, CvType.CV_32F, new Scalar(2));
         Mat m2 = new Mat(3, 4, CvType.CV_32F, new Scalar(3));
@@ -699,6 +741,46 @@ public class MatTest extends OpenCVTestCase {
         }
     }
 
+    public void testPutIntArrayByteArray() {
+        Mat m = new Mat(new int[]{5, 5, 5}, CvType.CV_8UC3, new Scalar(1, 2, 3));
+        Mat sm = m.submat(new Range[]{ new Range(0, 2), new Range(1, 3), new Range(2, 4)});
+        byte[] buff  = new byte[] { 0, 0, 0, 0, 0, 0 };
+        byte[] buff0 = new byte[] { 10, 20, 30, 40, 50, 60 };
+        byte[] buff1 = new byte[] { -1, -2, -3, -4, -5, -6 };
+
+        int bytesNum = m.put(new int[]{1, 2, 0}, buff0);
+
+        assertEquals(6, bytesNum);
+        bytesNum = m.get(new int[]{1, 2, 0}, buff);
+        assertEquals(6, bytesNum);
+        assertTrue(Arrays.equals(buff, buff0));
+
+        bytesNum = sm.put(new int[]{0, 0, 0}, buff1);
+
+        assertEquals(6, bytesNum);
+        bytesNum = sm.get(new int[]{0, 0, 0}, buff);
+        assertEquals(6, bytesNum);
+        assertTrue(Arrays.equals(buff, buff1));
+
+        bytesNum = m.get(new int[]{0, 1, 2}, buff);
+        assertEquals(6, bytesNum);
+        assertTrue(Arrays.equals(buff, buff1));
+
+        Mat m1 = m.submat(new Range[]{ new Range(1,2), Range.all(), Range.all() });
+        bytesNum = m1.get(new int[]{ 0, 2, 0}, buff);
+        assertEquals(6, bytesNum);
+        assertTrue(Arrays.equals(buff, buff0));
+
+        try {
+            byte[] bytes2 = new byte[] { 10, 20, 30, 40, 50 };
+            m.put(new int[]{ 2, 2, 0 }, bytes2);
+            fail("Expected UnsupportedOperationException (data.length % CvType.channels(t) != 0)");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+
+    }
+
     public void testPutIntIntDoubleArray() {
         Mat m = new Mat(5, 5, CvType.CV_8UC3, new Scalar(1, 2, 3));
         Mat sm = m.submat(2, 4, 3, 5);
@@ -722,6 +804,29 @@ public class MatTest extends OpenCVTestCase {
         assertTrue(Arrays.equals(buff, new byte[]{-1, -2, -3, -4, -5, -6}));
     }
 
+    public void testPutIntArrayDoubleArray() {
+        Mat m = new Mat(new int[]{5, 5, 5}, CvType.CV_8UC3, new Scalar(1, 2, 3));
+        Mat sm = m.submat(new Range[]{ new Range(0, 2), new Range(1, 3), new Range(2, 4)});
+        byte[] buff  = new byte[] { 0, 0, 0, 0, 0, 0 };
+
+        int bytesNum = m.put(new int[]{1, 2, 0}, 10, 20, 30, 40, 50, 60);
+
+        assertEquals(6, bytesNum);
+        bytesNum = m.get(new int[]{1, 2, 0}, buff);
+        assertEquals(6, bytesNum);
+        assertTrue(Arrays.equals(buff, new byte[]{10, 20, 30, 40, 50, 60}));
+
+        bytesNum = sm.put(new int[]{0, 0, 0}, 255, 254, 253, 252, 251, 250);
+
+        assertEquals(6, bytesNum);
+        bytesNum = sm.get(new int[]{0, 0, 0}, buff);
+        assertEquals(6, bytesNum);
+        assertTrue(Arrays.equals(buff, new byte[]{-1, -2, -3, -4, -5, -6}));
+        bytesNum = m.get(new int[]{0, 1, 2}, buff);
+        assertEquals(6, bytesNum);
+        assertTrue(Arrays.equals(buff, new byte[]{-1, -2, -3, -4, -5, -6}));
+    }
+
     public void testPutIntIntFloatArray() {
         Mat m = new Mat(5, 5, CvType.CV_32FC3, new Scalar(1, 2, 3));
         float[] elements = new float[] { 10, 20, 30, 40, 50, 60 };
@@ -745,6 +850,29 @@ public class MatTest extends OpenCVTestCase {
         }
     }
 
+    public void testPutIntArrayFloatArray() {
+        Mat m = new Mat(new int[]{5, 5, 5}, CvType.CV_32FC3, new Scalar(1, 2, 3));
+        float[] elements = new float[] { 10, 20, 30, 40, 50, 60 };
+
+        int bytesNum = m.put(new int[]{0, 4, 3}, elements);
+
+        assertEquals(elements.length * 4, bytesNum);
+        Mat m1 = m.submat(new Range[]{ Range.all(), new Range(4, 5), Range.all() });
+        float buff[] = new float[3];
+        bytesNum = m1.get(new int[]{ 0, 0, 4 }, buff);
+        assertEquals(buff.length * 4, bytesNum);
+        assertTrue(Arrays.equals(new float[]{40, 50, 60}, buff));
+        assertArrayEquals(new double[]{10, 20, 30}, m.get(new int[]{ 0, 4, 3 }), EPS);
+
+        try {
+            float[] elements2 = new float[] { 10, 20, 30, 40, 50 };
+            m.put(new int[]{4, 2, 2}, elements2);
+            fail("Expected UnsupportedOperationException (data.length % CvType.channels(t) != 0)");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+    }
+
     public void testPutIntIntIntArray() {
         Mat m = new Mat(5, 5, CvType.CV_32SC3, new Scalar(-1, -2, -3));
         int[] elements = new int[] { 10, 20, 30, 40, 50, 60 };
@@ -768,6 +896,29 @@ public class MatTest extends OpenCVTestCase {
         }
     }
 
+    public void testPutIntArrayIntArray() {
+        Mat m = new Mat(new int[]{5, 5, 5}, CvType.CV_32SC3, new Scalar(-1, -2, -3));
+        int[] elements = new int[] { 10, 20, 30, 40, 50, 60 };
+
+        int bytesNum = m.put(new int[]{ 0, 0, 4 }, elements);
+
+        assertEquals(elements.length * 4, bytesNum);
+        Mat m1 = m.submat(new Range[]{ Range.all(), Range.all(), new Range(4, 5)});
+        int buff[] = new int[3];
+        bytesNum = m1.get(new int[]{ 0, 0, 0 }, buff);
+        assertEquals(buff.length * 4, bytesNum);
+        assertTrue(Arrays.equals(new int[]{ 10, 20, 30 }, buff));
+        assertArrayEquals(new double[]{ 40, 50, 60 }, m.get(new int[]{ 0, 1, 0 }), EPS);
+
+        try {
+            int[] elements2 = new int[] { 10, 20, 30, 40, 50 };
+            m.put(new int[] { 2, 2, 0 }, elements2);
+            fail("Expected UnsupportedOperationException (data.length % CvType.channels(t) != 0)");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+    }
+
     public void testPutIntIntShortArray() {
         Mat m = new Mat(5, 5, CvType.CV_16SC3, new Scalar(-1, -2, -3));
         short[] elements = new short[] { 10, 20, 30, 40, 50, 60 };
@@ -790,6 +941,28 @@ public class MatTest extends OpenCVTestCase {
         }
     }
 
+    public void testPutIntArrayShortArray() {
+        Mat m = new Mat(new int[]{ 5, 5, 5}, CvType.CV_16SC3, new Scalar(-1, -2, -3));
+        short[] elements = new short[] { 10, 20, 30, 40, 50, 60 };
+
+        int bytesNum = m.put(new int[]{ 0, 2, 3 }, elements);
+
+        assertEquals(elements.length * 2, bytesNum);
+        Mat m1 = m.submat(new Range[]{ Range.all(), Range.all(), new Range(3, 4)});
+        short buff[] = new short[3];
+        bytesNum = m1.get(new int[]{ 0, 2, 0 }, buff);
+        assertTrue(Arrays.equals(new short[]{10, 20, 30}, buff));
+        assertArrayEquals(new double[]{40, 50, 60}, m.get(new int[]{ 0, 2, 4 }), EPS);
+
+        try {
+            short[] elements2 = new short[] { 10, 20, 30, 40, 50 };
+            m.put(new int[] { 2, 2, 0 }, elements2);
+            fail("Expected UnsupportedOperationException (data.length % CvType.channels(t) != 0)");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+    }
+
     public void testRelease() {
         assertFalse(gray0.empty());
         assertTrue(gray0.rows() > 0);
@@ -818,6 +991,7 @@ public class MatTest extends OpenCVTestCase {
     }
 
     public void testReshapeIntIntArray() {
+        // 2D -> 4D
         Mat src = new Mat(6, 5, CvType.CV_8UC3, new Scalar(0));
         assertEquals(2, src.dims());
         assertEquals(src.rows(), src.size(0));
@@ -828,6 +1002,34 @@ public class MatTest extends OpenCVTestCase {
         assertEquals(newShape.length, dst.dims());
         for (int i = 0; i < newShape.length; ++i)
             assertEquals(newShape[i], dst.size(i));
+
+        // 3D -> 2D
+        src = new Mat(new int[]{4, 6, 7}, CvType.CV_8UC3, new Scalar(0));
+        assertEquals(3, src.dims());
+        assertEquals(4, src.size(0));
+        assertEquals(6, src.size(1));
+        assertEquals(7, src.size(2));
+
+        int[] newShape2 = {src.channels() * src.size(2), src.size(0) * src.size(1)};
+        dst = src.reshape(1, newShape2);
+        assertEquals(newShape2.length, dst.dims());
+        for (int i = 0; i < newShape2.length; ++i)
+            assertEquals(newShape2[i], dst.size(i));
+    }
+
+    public void testCopySize() {
+        Mat src = new Mat(new int[]{1, 1, 10, 10}, CvType.CV_8UC1, new Scalar(1));
+        assertEquals(4, src.dims());
+        assertEquals(1, src.size(0));
+        assertEquals(1, src.size(1));
+        assertEquals(10, src.size(2));
+        assertEquals(10, src.size(3));
+        Mat other = new Mat(new int[]{10, 10}, src.type());
+
+        src.copySize(other);
+        assertEquals(other.dims(), src.dims());
+        for (int i = 0; i < other.dims(); ++i)
+            assertEquals(other.size(i), src.size(i));
     }
 
     public void testRow() {
@@ -949,6 +1151,16 @@ public class MatTest extends OpenCVTestCase {
         assertEquals(2, submat.cols());
     }
 
+    public void testSubmatRangeArray() {
+        Mat submat = gray255_32f_3d.submat(new Range[]{ new Range(2, 4), new Range(2, 4), new Range(3, 6) });
+        assertTrue(submat.isSubmatrix());
+        assertFalse(submat.isContinuous());
+
+        assertEquals(2, submat.size(0));
+        assertEquals(2, submat.size(1));
+        assertEquals(3, submat.size(2));
+    }
+
     public void testSubmatRect() {
         Mat submat = gray255.submat(new Rect(5, 5, gray255.cols() / 2, gray255.rows() / 2));
         assertTrue(submat.isSubmatrix());
@@ -1015,6 +1227,13 @@ public class MatTest extends OpenCVTestCase {
         assertMatEqual(truth, dst);
     }
 
+    public void testZerosIntArray() {
+        dst = Mat.zeros(new int[]{2, 3, 4}, CvType.CV_16S);
+
+        truth = new Mat(new int[]{2, 3, 4}, CvType.CV_16S, new Scalar(0));
+        assertMatEqual(truth, dst);
+    }
+
     public void testMatFromByteBuffer() {
         ByteBuffer bbuf = ByteBuffer.allocateDirect(64*64);
         bbuf.putInt(0x01010101);
index e222cb5..1ae2aa6 100644 (file)
@@ -32,6 +32,18 @@ static void throwJavaException(JNIEnv *env, const std::exception *e, const char
   CV_UNUSED(method);        // avoid "unused" warning
 }
 
+// jint could be int or int32_t so casting jint* to int* in general wouldn't work
+static std::vector<int> convertJintArrayToVector(JNIEnv* env, jintArray in) {
+    std::vector<int> out;
+    int len = env->GetArrayLength(in);
+    jint* inArray = env->GetIntArrayElements(in, 0);
+    for ( int i = 0; i < len; i++ ) {
+        out.push_back(inArray[i]);
+    }
+    env->ReleaseIntArrayElements(in, inArray, 0);
+    return out;
+}
+
 extern "C" {
 
 
@@ -100,6 +112,30 @@ JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__III
     return 0;
 }
 
+//
+//   Mat::Mat(int[] sizes, int type)
+//
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__I_3II
+  (JNIEnv* env, jclass, jint ndims, jintArray sizesArray, jint type);
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__I_3II
+  (JNIEnv* env, jclass, jint ndims, jintArray sizesArray, jint type)
+{
+    static const char method_name[] = "Mat::n_1Mat__I_3II()";
+    try {
+        LOGD("%s", method_name);
+        std::vector<int> sizes = convertJintArrayToVector(env, sizesArray);
+        return (jlong) new Mat( ndims, sizes.data(), type );
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+
+    return 0;
+}
+
 
 
 //
@@ -183,6 +219,33 @@ JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__DDIDDDD
 
 
 //
+//   Mat::Mat(int[] sizes, int type, Scalar s)
+//
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__I_3IIDDDD
+  (JNIEnv* env, jclass, jint ndims, jintArray sizesArray, jint type, jdouble s_val0, jdouble s_val1, jdouble s_val2, jdouble s_val3);
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__I_3IIDDDD
+  (JNIEnv* env, jclass, jint ndims, jintArray sizesArray, jint type, jdouble s_val0, jdouble s_val1, jdouble s_val2, jdouble s_val3)
+{
+    static const char method_name[] = "Mat::n_1Mat__I_3IIDDDD()";
+    try {
+        LOGD("%s", method_name);
+        std::vector<int> sizes = convertJintArrayToVector(env, sizesArray);
+        Scalar s(s_val0, s_val1, s_val2, s_val3);
+        return (jlong) new Mat( ndims, sizes.data(), type, s );
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+
+    return 0;
+}
+
+
+
+//
 //   Mat::Mat(Mat m, Range rowRange, Range colRange = Range::all())
 //
 
@@ -207,6 +270,59 @@ JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__JIIII
     return 0;
 }
 
+jint getObjectIntField(JNIEnv* env, jobject obj, const char * fieldName);
+
+jint getObjectIntField(JNIEnv* env, jobject obj, const char * fieldName) {
+    jfieldID fid; /* store the field ID */
+
+    /* Get a reference to obj's class */
+    jclass cls = env->GetObjectClass(obj);
+
+    /* Look for the instance field s in cls */
+    fid = env->GetFieldID(cls, fieldName, "I");
+    if (fid == NULL)
+    {
+        return 0; /* failed to find the field */
+    }
+
+    /* Read the instance field s */
+    return env->GetIntField(obj, fid);
+}
+
+#define RANGE_START_FIELD    "start"
+#define RANGE_END_FIELD      "end"
+
+//
+//   Mat::Mat(Mat m, Range[] ranges)
+//
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__J_3Lorg_opencv_core_Range_2
+  (JNIEnv* env, jclass, jlong m_nativeObj, jobjectArray rangesArray);
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__J_3Lorg_opencv_core_Range_2
+  (JNIEnv* env, jclass, jlong m_nativeObj, jobjectArray rangesArray)
+{
+    static const char method_name[] = "Mat::n_1Mat__J_3Lorg_opencv_core_Range_2()";
+    try {
+        LOGD("%s", method_name);
+        std::vector<Range> ranges;
+        int rangeCount = env->GetArrayLength(rangesArray);
+        for (int i = 0; i < rangeCount; i++) {
+            jobject range = env->GetObjectArrayElement(rangesArray, i);
+            jint start = getObjectIntField(env, range, RANGE_START_FIELD);
+            jint end = getObjectIntField(env, range, RANGE_END_FIELD);
+            ranges.push_back(Range(start, end));
+        }
+        return (jlong) new Mat( (*(Mat*)m_nativeObj), ranges );
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+
+    return 0;
+}
+
 
 JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__JII
   (JNIEnv* env, jclass, jlong m_nativeObj, jint rowRange_start, jint rowRange_end);
@@ -719,6 +835,56 @@ JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1create__JDDI
 
 
 //
+//  void Mat::create(int[] sizes, int type)
+//
+
+JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1create__JI_3II
+  (JNIEnv* env, jclass, jlong self, jint ndims, jintArray sizesArray, jint type);
+
+JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1create__JI_3II
+  (JNIEnv* env, jclass, jlong self, jint ndims, jintArray sizesArray, jint type)
+{
+    static const char method_name[] = "Mat::n_1create__JI_3II()";
+    try {
+        LOGD("%s", method_name);
+        Mat* me = (Mat*) self;
+        std::vector<int> sizes = convertJintArrayToVector(env, sizesArray);
+        me->create( ndims, sizes.data(), type );
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+}
+
+
+
+//
+//  Mat Mat::copySize(Mat m)
+//
+
+JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1copySize
+  (JNIEnv* env, jclass, jlong self, jlong m_nativeObj);
+
+JNIEXPORT void JNICALL Java_org_opencv_core_Mat_n_1copySize
+  (JNIEnv* env, jclass, jlong self, jlong m_nativeObj)
+{
+    static const char method_name[] = "Mat::n_1copySize()";
+    try {
+        LOGD("%s", method_name);
+        Mat* me = (Mat*) self;
+        Mat& m = *((Mat*)m_nativeObj);
+        me->copySize( m );
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+}
+
+
+
+//
 //  Mat Mat::cross(Mat m)
 //
 
@@ -1235,6 +1401,33 @@ JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1ones__DDI
 
 
 //
+// static Mat Mat::ones(int[] sizes, int type)
+//
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1ones__I_3II
+  (JNIEnv* env, jclass, jint ndims, jintArray sizesArray, jint type);
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1ones__I_3II
+  (JNIEnv* env, jclass, jint ndims, jintArray sizesArray, jint type)
+{
+    static const char method_name[] = "Mat::n_1ones__I_3II()";
+    try {
+        LOGD("%s", method_name);
+        std::vector<int> sizes = convertJintArrayToVector(env, sizesArray);
+        Mat _retval_ = Mat::ones( ndims, sizes.data(), type );
+        return (jlong) new Mat(_retval_);
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+
+    return 0;
+}
+
+
+
+//
 //  void Mat::push_back(Mat m)
 //
 
@@ -1344,8 +1537,8 @@ JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1reshape_11
     try {
         LOGD("%s", method_name);
         Mat* me = (Mat*) self; //TODO: check for NULL
-        int* newsz = (int*)env->GetPrimitiveArrayCritical(newshape, 0);
-        Mat _retval_ = me->reshape( cn, newndims, newsz );
+        std::vector<int> newsz = convertJintArrayToVector(env, newshape);
+        Mat _retval_ = me->reshape( cn, newndims, newsz.data() );
         return (jlong) new Mat(_retval_);
     } catch(const std::exception &e) {
         throwJavaException(env, &e, method_name);
@@ -1649,6 +1842,39 @@ JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1submat_1rr
     return 0;
 }
 
+//
+//  Mat Mat::operator()(Range[] ranges)
+//
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1submat_1ranges
+(JNIEnv* env, jclass, jlong self, jobjectArray rangesArray);
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1submat_1ranges
+(JNIEnv* env, jclass, jlong self, jobjectArray rangesArray)
+{
+    static const char method_name[] = "Mat::n_1submat_1ranges()";
+    try {
+        LOGD("%s", method_name);
+        Mat* me = (Mat*) self;
+        std::vector<Range> ranges;
+        int rangeCount = env->GetArrayLength(rangesArray);
+        for (int i = 0; i < rangeCount; i++) {
+            jobject range = env->GetObjectArrayElement(rangesArray, i);
+            jint start = getObjectIntField(env, range, RANGE_START_FIELD);
+            jint end = getObjectIntField(env, range, RANGE_END_FIELD);
+            ranges.push_back(Range(start, end));
+        }
+        Mat _retval_ = me->operator()( ranges );
+        return (jlong) new Mat(_retval_);
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+
+    return 0;
+}
+
 
 
 //
@@ -1812,6 +2038,33 @@ JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1zeros__DDI
 
 
 //
+// static Mat Mat::zeros(int[] sizes, int type)
+//
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1zeros__I_3II
+(JNIEnv* env, jclass, jint ndims, jintArray sizesArray, jint type);
+
+JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1zeros__I_3II
+(JNIEnv* env, jclass, jint ndims, jintArray sizesArray, jint type)
+{
+    static const char method_name[] = "Mat::n_1zeros__I_3II()";
+    try {
+        LOGD("%s", method_name);
+        std::vector<int> sizes = convertJintArrayToVector(env, sizesArray);
+        Mat _retval_ = Mat::zeros( ndims, sizes.data(), type );
+        return (jlong) new Mat(_retval_);
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+
+    return 0;
+}
+
+
+
+//
 //  native support for java finalize()
 //  static void Mat::n_delete( __int64 self )
 //
@@ -1880,6 +2133,50 @@ template<typename T> static int mat_put(cv::Mat* m, int row, int col, int count,
     return res;
 }
 
+// returns true if final index was reached
+static bool updateIdx(cv::Mat* m, std::vector<int>& idx, int inc) {
+    for (int i=m->dims-1; i>=0; i--) {
+        if (inc == 0) return false;
+        idx[i] = (idx[i] + 1) % m->size[i];
+        inc--;
+    }
+    return true;
+}
+
+template<typename T> static int mat_put_idx(cv::Mat* m, std::vector<int>& idx, int count, int offset, char* buff)
+{
+    if(! m) return 0;
+    if(! buff) return 0;
+
+    count *= sizeof(T);
+    int rest = (int)m->elemSize();
+    for (int i = 0; i < m->dims; i++) {
+        rest *= (m->size[i] - idx[i]);
+    }
+    if(count>rest) count = rest;
+    int res = count;
+
+    if( m->isContinuous() )
+    {
+        memcpy(m->ptr(idx.data()), buff + offset, count);
+    } else {
+        // dim by dim
+        int num = (m->size[m->dims-1] - idx[m->dims-1]) * (int)m->elemSize(); // 1st partial row
+        if(count<num) num = count;
+        uchar* data = m->ptr(idx.data());
+        while(count>0){
+            memcpy(data, buff + offset, num);
+            updateIdx(m, idx, num / (int)m->elemSize());
+            count -= num;
+            buff += num;
+            num = m->size[m->dims-1] * (int)m->elemSize();
+            if(count<num) num = count;
+            data = m->ptr(idx.data());
+        }
+    }
+    return res;
+}
+
 template<class ARRAY> static jint java_mat_put(JNIEnv* env, jlong self, jint row, jint col, jint count, jint offset, ARRAY vals)
 {
     static const char *method_name = JavaOpenCVTrait<ARRAY>::put;
@@ -1903,6 +2200,31 @@ template<class ARRAY> static jint java_mat_put(JNIEnv* env, jlong self, jint row
     return 0;
 }
 
+template<class ARRAY> static jint java_mat_put_idx(JNIEnv* env, jlong self, jintArray idxArray, jint count, jint offset, ARRAY vals)
+{
+    static const char *method_name = JavaOpenCVTrait<ARRAY>::put;
+    try {
+        LOGD("%s", method_name);
+        cv::Mat* me = (cv::Mat*) self;
+        if(! self) return 0; // no native object behind
+        if(me->depth() != JavaOpenCVTrait<ARRAY>::cvtype_1 && me->depth() != JavaOpenCVTrait<ARRAY>::cvtype_2) return 0; // incompatible type
+        std::vector<int> idx = convertJintArrayToVector(env, idxArray);
+        for (int i = 0; i < me->dims ; i++ ) {
+            if (me->size[i]<=idx[i]) return 0;
+        }
+        char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
+        int res = mat_put_idx<typename JavaOpenCVTrait<ARRAY>::value_type>(me, idx, count, offset, values);
+        env->ReleasePrimitiveArrayCritical(vals, values, JNI_ABORT);
+        return res;
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+
+    return 0;
+}
+
 extern "C" {
 
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutB
@@ -1914,6 +2236,15 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutB
   return java_mat_put(env, self, row, col, count, 0, vals);
 }
 
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutBIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jbyteArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutBIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jbyteArray vals)
+{
+    return java_mat_put_idx(env, self, idxArray, count, 0, vals);
+}
+
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutBwOffset
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jint offset, jbyteArray vals);
 
@@ -1923,6 +2254,15 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutBwOffset
   return java_mat_put(env, self, row, col, count, offset, vals);
 }
 
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutBwIdxOffset
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jint offset, jbyteArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutBwIdxOffset
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jint offset, jbyteArray vals)
+{
+    return java_mat_put_idx(env, self, idxArray, count, offset, vals);
+}
+
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutS
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jshortArray vals);
 
@@ -1932,6 +2272,15 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutS
   return java_mat_put(env, self, row, col, count, 0, vals);
 }
 
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutSIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jshortArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutSIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jshortArray vals)
+{
+    return java_mat_put_idx(env, self, idxArray, count, 0, vals);
+}
+
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutI
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jintArray vals);
 
@@ -1941,6 +2290,15 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutI
   return java_mat_put(env, self, row, col, count, 0, vals);
 }
 
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutIIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jintArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutIIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jintArray vals)
+{
+    return java_mat_put_idx(env, self, idxArray, count, 0, vals);
+}
+
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutF
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jfloatArray vals);
 
@@ -1950,6 +2308,15 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutF
   return java_mat_put(env, self, row, col, count, 0, vals);
 }
 
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutFIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jfloatArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutFIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jfloatArray vals)
+{
+    return java_mat_put_idx(env, self, idxArray, count, 0, vals);
+}
+
 // unlike other nPut()-s this one (with double[]) should convert input values to correct type
 #define PUT_ITEM(T, R, C) { T*dst = (T*)me->ptr(R, C); for(int ch=0; ch<me->channels() && count>0; count--,ch++,src++,dst++) *dst = cv::saturate_cast<T>(*src); }
 
@@ -2010,6 +2377,56 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutD
     return 0;
 }
 
+// unlike other nPut()-s this one (with double[]) should convert input values to correct type
+#define PUT_ITEM_IDX(T, I) { T*dst = (T*)me->ptr(I); for(int ch=0; ch<me->channels() && count>0; count--,ch++,src++,dst++) *dst = cv::saturate_cast<T>(*src); }
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutDIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jdoubleArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutDIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jdoubleArray vals)
+{
+    static const char* method_name = JavaOpenCVTrait<jdoubleArray>::put;
+    try {
+        LOGD("%s", method_name);
+        cv::Mat* me = (cv::Mat*) self;
+        if(!me || !me->data) return 0;  // no native object behind
+        std::vector<int> idx = convertJintArrayToVector(env, idxArray);
+        for (int i=0; i<me->dims; i++) {
+            if (me->size[i]<=idx[i]) return 0; // indexes out of range
+        }
+        int rest = me->channels();
+        for (int i=0; i<me->dims; i++) {
+            rest *= (me->size[i] - idx[i]);
+        }
+        if(count>rest) count = rest;
+        int res = count;
+        double* values = (double*)env->GetPrimitiveArrayCritical(vals, 0);
+        double* src = values;
+        bool reachedFinalIndex = false;
+        for(; !reachedFinalIndex && count>0; reachedFinalIndex = updateIdx(me, idx, 1))
+        {
+            switch(me->depth()) {
+                case CV_8U:  PUT_ITEM_IDX(uchar,  idx.data()); break;
+                case CV_8S:  PUT_ITEM_IDX(schar,  idx.data()); break;
+                case CV_16U: PUT_ITEM_IDX(ushort, idx.data()); break;
+                case CV_16S: PUT_ITEM_IDX(short,  idx.data()); break;
+                case CV_32S: PUT_ITEM_IDX(int,    idx.data()); break;
+                case CV_32F: PUT_ITEM_IDX(float,  idx.data()); break;
+                case CV_64F: PUT_ITEM_IDX(double, idx.data()); break;
+            }
+        }
+        env->ReleasePrimitiveArrayCritical(vals, values, 0);
+        return res;
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+
+    return 0;
+}
+
 } // extern "C"
 
 template<typename T> static int mat_get(cv::Mat* m, int row, int col, int count, char* buff)
@@ -2042,6 +2459,40 @@ template<typename T> static int mat_get(cv::Mat* m, int row, int col, int count,
     return res;
 }
 
+template<typename T> static int mat_get_idx(cv::Mat* m, std::vector<int>& idx, int count, char* buff)
+{
+    if(! m) return 0;
+    if(! buff) return 0;
+
+    count *= sizeof(T);
+    int rest = (int)m->elemSize();
+    for (int i = 0; i < m->dims; i++) {
+        rest *= (m->size[i] - idx[i]);
+    }
+    if(count>rest) count = rest;
+    int res = count;
+
+    if( m->isContinuous() )
+    {
+        memcpy(buff, m->ptr(idx.data()), count);
+    } else {
+        // dim by dim
+        int num = (m->size[m->dims-1] - idx[m->dims-1]) * (int)m->elemSize(); // 1st partial row
+        if(count<num) num = count;
+        uchar* data = m->ptr(idx.data());
+        while(count>0){
+            memcpy(buff, data, num);
+            updateIdx(m, idx, num / (int)m->elemSize());
+            count -= num;
+            buff += num;
+            num = m->size[m->dims-1] * (int)m->elemSize();
+            if(count<num) num = count;
+            data = m->ptr(idx.data());
+        }
+    }
+    return res;
+}
+
 template<class ARRAY> static jint java_mat_get(JNIEnv* env, jlong self, jint row, jint col, jint count, ARRAY vals) {
     static const char *method_name = JavaOpenCVTrait<ARRAY>::get;
     try {
@@ -2064,6 +2515,31 @@ template<class ARRAY> static jint java_mat_get(JNIEnv* env, jlong self, jint row
     return 0;
 }
 
+template<class ARRAY> static jint java_mat_get_idx(JNIEnv* env, jlong self, jintArray idxArray, jint count, ARRAY vals) {
+    static const char *method_name = JavaOpenCVTrait<ARRAY>::get;
+    try {
+        LOGD("%s", method_name);
+        cv::Mat* me = (cv::Mat*) self;
+        if(! self) return 0; // no native object behind
+        if(me->depth() != JavaOpenCVTrait<ARRAY>::cvtype_1 && me->depth() != JavaOpenCVTrait<ARRAY>::cvtype_2) return 0; // incompatible type
+        std::vector<int> idx = convertJintArrayToVector(env, idxArray);
+        for (int i = 0; i < me->dims ; i++ ) {
+            if (me->size[i]<=idx[i]) return 0;
+        }
+
+        char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
+        int res = mat_get_idx<typename JavaOpenCVTrait<ARRAY>::value_type>(me, idx, count, values);
+        env->ReleasePrimitiveArrayCritical(vals, values, 0);
+        return res;
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+
+    return 0;
+}
+
 extern "C" {
 
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetB
@@ -2075,6 +2551,15 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetB
   return java_mat_get(env, self, row, col, count, vals);
 }
 
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetBIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jbyteArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetBIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jbyteArray vals)
+{
+    return java_mat_get_idx(env, self, idxArray, count, vals);
+}
+
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetS
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jshortArray vals);
 
@@ -2084,6 +2569,15 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetS
   return java_mat_get(env, self, row, col, count, vals);
 }
 
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetSIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jshortArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetSIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jshortArray vals)
+{
+    return java_mat_get_idx(env, self, idxArray, count, vals);
+}
+
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetI
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jintArray vals);
 
@@ -2093,6 +2587,15 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetI
   return java_mat_get(env, self, row, col, count, vals);
 }
 
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetIIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jintArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetIIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jintArray vals)
+{
+    return java_mat_get_idx(env, self, idxArray, count, vals);
+}
+
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetF
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jfloatArray vals);
 
@@ -2102,6 +2605,15 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetF
   return java_mat_get(env, self, row, col, count, vals);
 }
 
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetFIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jfloatArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetFIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jfloatArray vals)
+{
+    return java_mat_get_idx(env, self, idxArray, count, vals);
+}
+
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetD
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jdoubleArray vals);
 
@@ -2111,6 +2623,15 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetD
   return java_mat_get(env, self, row, col, count, vals);
 }
 
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetDIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jdoubleArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetDIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray, jint count, jdoubleArray vals)
+{
+    return java_mat_get_idx(env, self, idxArray, count, vals);
+}
+
 JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_Mat_nGet
     (JNIEnv* env, jclass, jlong self, jint row, jint col);
 
@@ -2149,6 +2670,47 @@ JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_Mat_nGet
     return 0;
 }
 
+JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_Mat_nGetIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray);
+
+JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_Mat_nGetIdx
+    (JNIEnv* env, jclass, jlong self, jintArray idxArray)
+{
+    static const char method_name[] = "Mat::nGetIdx()";
+    try {
+        LOGD("%s", method_name);
+        cv::Mat* me = (cv::Mat*) self;
+        if(! self) return 0; // no native object behind
+        std::vector<int> idx = convertJintArrayToVector(env, idxArray);
+        for (int i=0; i<me->dims; i++) {
+            if (me->size[i]<=idx[i]) return 0; // indexes out of range
+        }
+
+        jdoubleArray res = env->NewDoubleArray(me->channels());
+        if(res){
+            jdouble buff[CV_CN_MAX];//me->channels()
+            int i;
+            switch(me->depth()){
+                case CV_8U:  for(i=0; i<me->channels(); i++) buff[i] = *((unsigned char*) me->ptr(idx.data()) + i); break;
+                case CV_8S:  for(i=0; i<me->channels(); i++) buff[i] = *((signed char*)   me->ptr(idx.data()) + i); break;
+                case CV_16U: for(i=0; i<me->channels(); i++) buff[i] = *((unsigned short*)me->ptr(idx.data()) + i); break;
+                case CV_16S: for(i=0; i<me->channels(); i++) buff[i] = *((signed short*)  me->ptr(idx.data()) + i); break;
+                case CV_32S: for(i=0; i<me->channels(); i++) buff[i] = *((int*)           me->ptr(idx.data()) + i); break;
+                case CV_32F: for(i=0; i<me->channels(); i++) buff[i] = *((float*)         me->ptr(idx.data()) + i); break;
+                case CV_64F: for(i=0; i<me->channels(); i++) buff[i] = *((double*)        me->ptr(idx.data()) + i); break;
+            }
+            env->SetDoubleArrayRegion(res, 0, me->channels(), buff);
+        }
+        return res;
+    } catch(const std::exception &e) {
+        throwJavaException(env, &e, method_name);
+    } catch (...) {
+        throwJavaException(env, 0, method_name);
+    }
+
+    return 0;
+}
+
 JNIEXPORT jstring JNICALL Java_org_opencv_core_Mat_nDump
   (JNIEnv *env, jclass, jlong self);
 
index c3af0b3..cc7eb9d 100644 (file)
@@ -99,6 +99,8 @@ public class OpenCVTestCase extends TestCase {
     protected Mat rgbLena;
     protected Mat grayChess;
 
+    protected Mat gray255_32f_3d;
+
     protected Mat v1;
     protected Mat v2;
 
@@ -149,6 +151,8 @@ public class OpenCVTestCase extends TestCase {
         rgbLena = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH);
         grayChess = Imgcodecs.imread(OpenCVTestRunner.CHESS_PATH, 0);
 
+        gray255_32f_3d = new Mat(new int[]{matSize, matSize, matSize}, CvType.CV_32F, new Scalar(255.0));
+
         v1 = new Mat(1, 3, CvType.CV_32F);
         v1.put(0, 0, 1.0, 3.0, 2.0);
         v2 = new Mat(1, 3, CvType.CV_32F);
@@ -184,6 +188,7 @@ public class OpenCVTestCase extends TestCase {
         rgba128.release();
         rgbLena.release();
         grayChess.release();
+        gray255_32f_3d.release();
         v1.release();
         v2.release();
 
@@ -442,8 +447,24 @@ public class OpenCVTestCase extends TestCase {
         assertEquals(msg, expected.z, actual.z, eps);
     }
 
+    static private boolean dimensionsEqual(Mat expected, Mat actual) {
+        if (expected.dims() != actual.dims()) {
+            return false;
+        }
+        if (expected.dims() > 2) {
+            for (int i = 0; i < expected.dims(); i++) {
+                if (expected.size(i) != actual.size(i)) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return expected.cols() == actual.cols() && expected.rows() == actual.rows();
+        }
+    }
+
     static private void compareMats(Mat expected, Mat actual, boolean isEqualityMeasured) {
-        if (expected.type() != actual.type() || expected.cols() != actual.cols() || expected.rows() != actual.rows()) {
+        if (expected.type() != actual.type() || !dimensionsEqual(expected, actual)) {
             throw new UnsupportedOperationException("Can not compare " + expected + " and " + actual);
         }
 
@@ -471,7 +492,7 @@ public class OpenCVTestCase extends TestCase {
     }
 
     static private void compareMats(Mat expected, Mat actual, double eps, boolean isEqualityMeasured) {
-        if (expected.type() != actual.type() || expected.cols() != actual.cols() || expected.rows() != actual.rows()) {
+        if (expected.type() != actual.type() || !dimensionsEqual(expected, actual)) {
             throw new UnsupportedOperationException("Can not compare " + expected + " and " + actual);
         }
 
index a66206e..7dc3432 100644 (file)
@@ -97,6 +97,8 @@ public class OpenCVTestCase extends TestCase {
     protected Mat rgbLena;
     protected Mat grayChess;
 
+    protected Mat gray255_32f_3d;
+
     protected Mat v1;
     protected Mat v2;
 
@@ -175,6 +177,8 @@ public class OpenCVTestCase extends TestCase {
         rgbLena = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH);
         grayChess = Imgcodecs.imread(OpenCVTestRunner.CHESS_PATH, 0);
 
+        gray255_32f_3d = new Mat(new int[]{matSize, matSize, matSize}, CvType.CV_32F, new Scalar(255.0));
+
         v1 = new Mat(1, 3, CvType.CV_32F);
         v1.put(0, 0, 1.0, 3.0, 2.0);
         v2 = new Mat(1, 3, CvType.CV_32F);
@@ -210,6 +214,7 @@ public class OpenCVTestCase extends TestCase {
         rgba128.release();
         rgbLena.release();
         grayChess.release();
+        gray255_32f_3d.release();
         v1.release();
         v2.release();
 
@@ -468,8 +473,24 @@ public class OpenCVTestCase extends TestCase {
         assertEquals(msg, expected.z, actual.z, eps);
     }
 
+    static private boolean dimensionsEqual(Mat expected, Mat actual) {
+        if (expected.dims() != actual.dims()) {
+            return false;
+        }
+        if (expected.dims() > 2) {
+            for (int i = 0; i < expected.dims(); i++) {
+                if (expected.size(i) != actual.size(i)) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return expected.cols() == actual.cols() && expected.rows() == actual.rows();
+        }
+    }
+
     static private void compareMats(Mat expected, Mat actual, boolean isEqualityMeasured) {
-        if (expected.type() != actual.type() || expected.cols() != actual.cols() || expected.rows() != actual.rows()) {
+        if (expected.type() != actual.type() || !dimensionsEqual(expected, actual)) {
             throw new UnsupportedOperationException("Can not compare " + expected + " and " + actual);
         }
 
@@ -497,7 +518,7 @@ public class OpenCVTestCase extends TestCase {
     }
 
     static private void compareMats(Mat expected, Mat actual, double eps, boolean isEqualityMeasured) {
-        if (expected.type() != actual.type() || expected.cols() != actual.cols() || expected.rows() != actual.rows()) {
+        if (expected.type() != actual.type() || !dimensionsEqual(expected, actual)) {
             throw new UnsupportedOperationException("Can not compare " + expected + " and " + actual);
         }