diff --git a/modules/core/misc/java/src/java/core+Mat.java b/modules/core/misc/java/src/java/core+Mat.java index 5ebb5ee145..641d9f8ae8 100644 --- a/modules/core/misc/java/src/java/core+Mat.java +++ b/modules/core/misc/java/src/java/core+Mat.java @@ -41,6 +41,15 @@ public class Mat { nativeObj = n_Mat(rows, cols, type, data); } + // + // C++: Mat::Mat(int rows, int cols, int type, void* data, size_t step) + // + + // javadoc: Mat::Mat(rows, cols, type, data, step) + public Mat(int rows, int cols, int type, ByteBuffer data, long step) { + nativeObj = n_Mat(rows, cols, type, data, step); + } + // // C++: Mat::Mat(Size size, int type) // @@ -1136,6 +1145,9 @@ public class Mat { // 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); + // C++: Mat::Mat(int rows, int cols, int type, void* data, size_t step) + private static native long n_Mat(int rows, int cols, int type, ByteBuffer data, long step); + // C++: Mat::Mat(Size size, int type) private static native long n_Mat(double size_width, double size_height, int type); diff --git a/modules/core/misc/java/test/MatTest.java b/modules/core/misc/java/test/MatTest.java index cdd7950843..039aa39929 100644 --- a/modules/core/misc/java/test/MatTest.java +++ b/modules/core/misc/java/test/MatTest.java @@ -1246,4 +1246,22 @@ public class MatTest extends OpenCVTestCase { assertEquals(1, bbuf.get(4095)); } + public void testMatFromByteBufferWithStep() { + ByteBuffer bbuf = ByteBuffer.allocateDirect(80*64); + bbuf.putInt(0x01010101); + bbuf.putInt(64, 0x02020202); + bbuf.putInt(80, 0x03030303); + Mat m = new Mat(64, 64, CvType.CV_8UC1, bbuf, 80); + assertEquals(8, Core.countNonZero(m)); + Core.add(m, new Scalar(5), m); + assertEquals(4096, Core.countNonZero(m)); + m.release(); + assertEquals(6, bbuf.get(0)); + assertEquals(5, bbuf.get(63)); + assertEquals(2, bbuf.get(64)); + assertEquals(0, bbuf.get(79)); + assertEquals(8, bbuf.get(80)); + assertEquals(5, bbuf.get(63*80 + 63)); + } + } diff --git a/modules/java/generator/android-21/java/org/opencv/android/JavaCamera2View.java b/modules/java/generator/android-21/java/org/opencv/android/JavaCamera2View.java index e4a58539b5..09e01b01fc 100644 --- a/modules/java/generator/android-21/java/org/opencv/android/JavaCamera2View.java +++ b/modules/java/generator/android-21/java/org/opencv/android/JavaCamera2View.java @@ -332,8 +332,10 @@ public class JavaCamera2View extends CameraBridgeViewBase { Image.Plane[] planes = mImage.getPlanes(); int w = mImage.getWidth(); int h = mImage.getHeight(); + assert(planes[0].getPixelStride() == 1); ByteBuffer y_plane = planes[0].getBuffer(); - mGray = new Mat(h, w, CvType.CV_8UC1, y_plane); + int y_plane_step = planes[0].getRowStride(); + mGray = new Mat(h, w, CvType.CV_8UC1, y_plane, y_plane_step); return mGray; } @@ -349,11 +351,14 @@ public class JavaCamera2View extends CameraBridgeViewBase { assert(planes[0].getPixelStride() == 1); assert(planes[2].getPixelStride() == 2); ByteBuffer y_plane = planes[0].getBuffer(); + int y_plane_step = planes[0].getRowStride(); ByteBuffer uv_plane1 = planes[1].getBuffer(); + int uv_plane1_step = planes[1].getRowStride(); ByteBuffer uv_plane2 = planes[2].getBuffer(); - Mat y_mat = new Mat(h, w, CvType.CV_8UC1, y_plane); - Mat uv_mat1 = new Mat(h / 2, w / 2, CvType.CV_8UC2, uv_plane1); - Mat uv_mat2 = new Mat(h / 2, w / 2, CvType.CV_8UC2, uv_plane2); + int uv_plane2_step = planes[2].getRowStride(); + Mat y_mat = new Mat(h, w, CvType.CV_8UC1, y_plane, y_plane_step); + Mat uv_mat1 = new Mat(h / 2, w / 2, CvType.CV_8UC2, uv_plane1, uv_plane1_step); + Mat uv_mat2 = new Mat(h / 2, w / 2, CvType.CV_8UC2, uv_plane2, uv_plane2_step); long addr_diff = uv_mat2.dataAddr() - uv_mat1.dataAddr(); if (addr_diff > 0) { assert(addr_diff == 1); @@ -369,30 +374,45 @@ public class JavaCamera2View extends CameraBridgeViewBase { ByteBuffer u_plane = planes[1].getBuffer(); ByteBuffer v_plane = planes[2].getBuffer(); - y_plane.get(yuv_bytes, 0, w*h); + int yuv_bytes_offset = 0; + + int y_plane_step = planes[0].getRowStride(); + if (y_plane_step == w) { + y_plane.get(yuv_bytes, 0, w*h); + yuv_bytes_offset = w*h; + } else { + int padding = y_plane_step - w; + for (int i = 0; i < h; i++){ + y_plane.get(yuv_bytes, yuv_bytes_offset, w); + yuv_bytes_offset += w; + if (i < h - 1) { + y_plane.position(y_plane.position() + padding); + } + } + assert(yuv_bytes_offset == w * h); + } int chromaRowStride = planes[1].getRowStride(); int chromaRowPadding = chromaRowStride - w/2; - int offset = w*h; if (chromaRowPadding == 0){ // When the row stride of the chroma channels equals their width, we can copy // the entire channels in one go - u_plane.get(yuv_bytes, offset, w*h/4); - offset += w*h/4; - v_plane.get(yuv_bytes, offset, w*h/4); + u_plane.get(yuv_bytes, yuv_bytes_offset, w*h/4); + yuv_bytes_offset += w*h/4; + v_plane.get(yuv_bytes, yuv_bytes_offset, w*h/4); } else { // When not equal, we need to copy the channels row by row for (int i = 0; i < h/2; i++){ - u_plane.get(yuv_bytes, offset, w/2); - offset += w/2; + u_plane.get(yuv_bytes, yuv_bytes_offset, w/2); + yuv_bytes_offset += w/2; if (i < h/2-1){ u_plane.position(u_plane.position() + chromaRowPadding); } } for (int i = 0; i < h/2; i++){ - v_plane.get(yuv_bytes, offset, w/2); - offset += w/2; + v_plane.get(yuv_bytes, yuv_bytes_offset, w/2); + yuv_bytes_offset += w/2; if (i < h/2-1){ v_plane.position(v_plane.position() + chromaRowPadding); } diff --git a/modules/java/generator/src/cpp/Mat.cpp b/modules/java/generator/src/cpp/Mat.cpp index 1ae2aa6e8c..5203413ae4 100644 --- a/modules/java/generator/src/cpp/Mat.cpp +++ b/modules/java/generator/src/cpp/Mat.cpp @@ -74,7 +74,7 @@ JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__IIILjava_nio_ByteBuffer JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__IIILjava_nio_ByteBuffer_2 (JNIEnv* env, jclass, jint rows, jint cols, jint type, jobject data) { - static const char method_name[] = "Mat::n_1Mat__IIILByteBuffer()"; + static const char method_name[] = "Mat::n_1Mat__IIILjava_nio_ByteBuffer_2()"; try { LOGD("%s", method_name); return (jlong) new Mat( rows, cols, type, (void*)env->GetDirectBufferAddress(data) ); @@ -88,6 +88,32 @@ JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__IIILjava_nio_ByteBuffer } +/* + * Class: org_opencv_core_Mat + * Method: n_Mat + * Signature: (IIILjava/nio/ByteBuffer;J)J + * + * Mat::Mat(int rows, int cols, int type, void* data, size_t step) + */ +JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__IIILjava_nio_ByteBuffer_2J + (JNIEnv* env, jclass, jint rows, jint cols, jint type, jobject data, jlong step); + +JNIEXPORT jlong JNICALL Java_org_opencv_core_Mat_n_1Mat__IIILjava_nio_ByteBuffer_2J + (JNIEnv* env, jclass, jint rows, jint cols, jint type, jobject data, jlong step) +{ + static const char method_name[] = "Mat::n_1Mat__IIILjava_nio_ByteBuffer_2J()"; + try { + LOGD("%s", method_name); + return (jlong) new Mat(rows, cols, type, (void*)env->GetDirectBufferAddress(data), (size_t)step); + } catch(const std::exception &e) { + throwJavaException(env, &e, method_name); + } catch (...) { + throwJavaException(env, 0, method_name); + } + + return 0; +} + // // Mat::Mat(int rows, int cols, int type)