Merge pull request #10489 from SarenT:offset-mat_put

Adding capability to parse subsections of a byte array in Java bindings (#10489)

* Adding capability to parse subsections of a byte array in Java bindings. (Because Java lacks pointers. Therefore, reading images within a subsection of a byte array is impossible by Java's nature and limitations. Because of this, many IO functions in Java require additional parameters offset and length to define, which section of an array to be read.)

* Corrected according to the review. Previous interfaces were restored, instead internal interfaces were modified to provide subsampling of java byte arrays.

* Adding tests and test related files.

* Adding missing files for the test.

* Simplified the test

* Check was corrected according to discussion. An OutOfRangeException will be thrown instead of returning.

* java: update MatOfByte implementation checks / tests
This commit is contained in:
SarenT 2018-01-12 16:00:58 +01:00 committed by Alexander Alekhin
parent 9deaddcdff
commit c6d9ce8fd3
4 changed files with 124 additions and 9 deletions

View File

@ -1015,6 +1015,21 @@ public class Mat {
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();
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 (CvType.depth(t) == CvType.CV_8U || CvType.depth(t) == CvType.CV_8S) {
return nPutBwOffset(nativeObj, row, col, 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();
@ -1318,6 +1333,8 @@ public class Mat {
private static native int nPutB(long self, int row, int col, 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 nGetB(long self, int row, int col, int count, byte[] vals);
private static native int nGetS(long self, int row, int col, int count, short[] vals);

View File

@ -35,6 +35,11 @@ public class MatOfByte extends Mat {
fromArray(a);
}
public MatOfByte(int offset, int length, byte...a) {
super();
fromArray(offset, length, a);
}
public void alloc(int elemNumber) {
if(elemNumber>0)
super.create(elemNumber, 1, CvType.makeType(_depth, _channels));
@ -48,6 +53,20 @@ public class MatOfByte extends Mat {
put(0, 0, a); //TODO: check ret val!
}
public void fromArray(int offset, int length, byte...a) {
if (offset < 0)
throw new IllegalArgumentException("offset < 0");
if (a == null)
throw new NullPointerException();
if (length < 0 || length + offset > a.length)
throw new IllegalArgumentException("invalid 'length' parameter: " + Integer.toString(length));
if (a.length == 0)
return;
int num = length / _channels;
alloc(num);
put(0, 0, a, offset, length); //TODO: check ret val!
}
public byte[] toArray() {
int num = checkVector(_channels, _depth);
if(num < 0)

View File

@ -0,0 +1,70 @@
package org.opencv.test.core;
import java.util.Arrays;
import org.opencv.core.Core;
import org.opencv.core.CvException;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfDouble;
import org.opencv.test.OpenCVTestCase;
import org.opencv.imgcodecs.Imgcodecs;
public class MatOfByteTest extends OpenCVTestCase {
public void testMatOfSubByteArray() {
byte[] inputBytes = { 1,2,3,4,5 };
MatOfByte m0 = new MatOfByte(inputBytes);
MatOfByte m1 = new MatOfByte(0, inputBytes.length, inputBytes);
MatOfByte m2 = new MatOfByte(1, inputBytes.length - 2, inputBytes);
assertEquals(5.0, m0.size().height);
assertEquals(1.0, m0.size().width);
assertEquals(m0.get(0, 0)[0], m1.get(0, 0)[0]);
assertEquals(m0.get((int) m0.size().height - 1, 0)[0], m1.get((int) m1.size().height - 1, 0)[0]);
assertEquals(3.0, m2.size().height);
assertEquals(1.0, m2.size().width);
assertEquals(2.0, m2.get(0, 0)[0]);
assertEquals(3.0, m2.get(1, 0)[0]);
assertEquals(4.0, m2.get(2, 0)[0]);
}
public void testMatOfSubByteArray_BadArg() {
byte[] inputBytes = { 1,2,3,4,5 };
try {
MatOfByte m1 = new MatOfByte(-1, inputBytes.length, inputBytes);
fail("Missing check: offset < 0");
} catch (IllegalArgumentException e) {
// pass
}
try {
MatOfByte m1 = new MatOfByte(0, inputBytes.length, null);
fail("Missing check: NullPointerException");
} catch (NullPointerException e) {
// pass
}
try {
MatOfByte m1 = new MatOfByte(0, -1, inputBytes);
fail("Missing check: length < 0");
} catch (IllegalArgumentException e) {
// pass
}
try {
MatOfByte m1 = new MatOfByte(1, inputBytes.length, inputBytes);
fail("Missing check: buffer bounds");
} catch (IllegalArgumentException e) {
// pass
}
}
}

View File

@ -1863,7 +1863,7 @@ namespace {
#undef JOCvT
}
template<typename T> static int mat_put(cv::Mat* m, int row, int col, int count, char* buff)
template<typename T> static int mat_put(cv::Mat* m, int row, int col, int count, int offset, char* buff)
{
if(! m) return 0;
if(! buff) return 0;
@ -1875,14 +1875,14 @@ template<typename T> static int mat_put(cv::Mat* m, int row, int col, int count,
if( m->isContinuous() )
{
memcpy(m->ptr(row, col), buff, count);
memcpy(m->ptr(row, col), buff + offset, count);
} else {
// row by row
int num = (m->cols - col) * (int)m->elemSize(); // 1st partial row
if(count<num) num = count;
uchar* data = m->ptr(row++, col);
while(count>0){
memcpy(data, buff, num);
memcpy(data, buff + offset, num);
count -= num;
buff += num;
num = m->cols * (int)m->elemSize();
@ -1893,7 +1893,7 @@ template<typename T> static int mat_put(cv::Mat* m, int row, int col, int count,
return res;
}
template<class ARRAY> static jint java_mat_put(JNIEnv* env, jlong self, jint row, jint col, jint count, ARRAY vals)
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;
try {
@ -1904,7 +1904,7 @@ template<class ARRAY> static jint java_mat_put(JNIEnv* env, jlong self, jint row
if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
int res = mat_put<typename JavaOpenCVTrait<ARRAY>::value_type>(me, row, col, count, values);
int res = mat_put<typename JavaOpenCVTrait<ARRAY>::value_type>(me, row, col, count, offset, values);
env->ReleasePrimitiveArrayCritical(vals, values, JNI_ABORT);
return res;
} catch(const std::exception &e) {
@ -1924,7 +1924,16 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutB
JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutB
(JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jbyteArray vals)
{
return java_mat_put(env, self, row, col, count, vals);
return java_mat_put(env, self, row, col, 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);
JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutBwOffset
(JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jint offset, jbyteArray vals)
{
return java_mat_put(env, self, row, col, count, offset, vals);
}
JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutS
@ -1933,7 +1942,7 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutS
JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutS
(JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jshortArray vals)
{
return java_mat_put(env, self, row, col, count, vals);
return java_mat_put(env, self, row, col, count, 0, vals);
}
JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutI
@ -1942,7 +1951,7 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutI
JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutI
(JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jintArray vals)
{
return java_mat_put(env, self, row, col, count, vals);
return java_mat_put(env, self, row, col, count, 0, vals);
}
JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutF
@ -1951,7 +1960,7 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutF
JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutF
(JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jfloatArray vals)
{
return java_mat_put(env, self, row, col, count, vals);
return java_mat_put(env, self, row, col, count, 0, vals);
}
} // extern "C"