Merge pull request #29851 from utibenkei:fix-java-mat-get-put

java: fix Mat get/put JNI for 0D/1D/ND Mats in OpenCV 5 - #29851#29851

## Summary

Fix incorrect behavior of Java `Mat.get()` / `Mat.put()` JNI bindings for
0D (scalar), 1D, and ND `cv::Mat` objects.
The Java JNI layer in `modules/java/generator/src/cpp/Mat.cpp` still assumed
essentially 2D row/col indexing in several get/put code paths. This caused
wrong results or failed access for scalar and 1D Mats, and incorrect bounds
handling for ND Mats accessed via index arrays.
This PR updates the native get/put helpers in `Mat.cpp` and adds regression
tests in `modules/core/misc/java/test/MatTest.java`.

## Problem (before this patch)
### 1. 0D (scalar) Mats
- `Mat::ptr(const int*)` requires `dims >= 1`, so idx-based paths that called
  `m->ptr(idx.data())` directly (e.g. `nGetIdx`, `mat_copy_data`, `PUT_ITEM_IDX`)
  could not access a true 0D Mat correctly.
- `idx2Offset()` always read `indices[0]` without checking `dims <= 0`.
- Row/col helpers always built a 2-element index `{row, col}` instead of an
  empty index vector for 0D Mats.
Although OpenCV 5 supports 0D Mats at the C++ level, the Java wrapper did not
correctly implement idx-based access with an empty index array (`new int[]{}`).
This PR adds explicit JNI support for that case via `mat_elem_ptr()` and
related helpers.
**Example:** For `Mat m = new Mat(new int[]{}, CvType.CV_64F)` (`dims()==0`),
`m.put(new int[]{}, 42.0)` and `m.get(new int[]{}, buf)` could fail or access
the wrong memory.
### 2. 1D Mats (`dims() == 1`)
- Row/col get/put always converted `(row, col)` to `{row, col}` (length 2),
  while a 1D Mat requires a single-element index vector.
- For a 1D Mat, OpenCV 5 represents the shape as `dims == rows == 1` and
  `cols == total() == N`. The Java row/col access path must therefore interpret
  `(row, col)` as the 1D element index represented by `col` (with `row == 0`),
  converting internally to `{col}` via `row_col_to_idx()`.
**Example:** For `Mat m = new Mat(new int[]{10}, CvType.CV_32F)`, calling
`m.put(0, 3, values)` could behave incorrectly because native code treated
the access as `{0, 3}` instead of `{3}`.
### 3. ND Mats (`dims() > 2`) via row/col API
- Row/col get/put only checked `rows` and `cols`, without rejecting Mats with
  `dims > 2`.
- ND Mats must be accessed via idx-based APIs; using row/col on them could
  produce silently wrong results instead of failing early.
### 4. Idx-based API bounds checking
- Old code checked `size[i] <= idx[i]` but did not validate:
  - `idx.length == dims`
  - negative index values
- `nPutDIdx` computed the number of remaining elements with a per-dimension
  product loop (`channels * (size[i] - idx[i]) * ...`). For ND Mats, this did
  not correctly account for the current linear index position when determining
  how many elements remain from the selected subarray onward. The fix uses
  `(total() - idx2Offset(m, idx)) * channels()`, which matches the linear
  layout used by `mat_copy_data()`.

## Changes
- Add `mat_elem_ptr()` to support 0D scalar Mats (`Mat::ptr(const int*)`
  requires `dims >= 1`).
- Add `check_row_col_access()`, `check_idx_access()`, and `row_col_to_idx()`
  to validate access and convert row/col indices according to OpenCV semantics.
- Update `idx2Offset()`, `offset2Idx()`, and `mat_copy_data()` for 0D/1D Mats.
- Route row/col get/put through `row_col_to_idx()` (1D: element index in `col`,
  `row == 0`).
- Restrict row/col APIs to Mats with `dims <= 2`; ND Mats must use idx-based
  APIs (`nGet*Idx`, `nPut*Idx`, `nGetIdx`, `nPutDIdx`).
- Fix remaining-element calculation in `nPutDIdx` to use `idx2Offset()`.

## Behavior notes
| API | 0D Mat (`dims==0`) | 1D Mat (`dims==1`) | 2D Mat | ND Mat (`dims>2`) |
|-----|-------------------|-------------------|--------|-------------------|
| `get/put(int[] idx, ...)` | supported (`idx.length == 0`; added by this PR) | supported (`idx.length == 1`) | supported | supported |
| `get/put(row, col, ...)` | supported (`row=0`, `col=0`) | supported (index in `col`, `row=0`) | supported | rejected at JNI layer return 0; |
| `get(row, col)` | supported | supported | supported | rejected at JNI layer return 0; |
| `get(int[] idx)` | supported | supported | supported | supported |

## Test plan
Added regression tests in `MatTest.java`:
- `testGetPut0DMat` — idx and row/col get/put on a scalar Mat (`new int[]{}`)
- `testGetPut1DMat` — idx and row/col get/put on `new Mat(new int[]{5}, ...)`
- `testGetPut1DMatDoubleArray` — bulk double put/get via idx on a 1D Mat
- `testGetPut3DMat` — row/col API rejected for 3D Mat; idx API works

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
utibenkei
2026-10-30 16:45:13 +09:00
committed by GitHub
parent 1e5aa6d307
commit 9d40b84107
2 changed files with 174 additions and 51 deletions

View File

@@ -994,6 +994,88 @@ public class MatTest extends OpenCVTestCase {
}
}
public void testGetPut0DMat() {
Mat m = new Mat(new int[]{}, CvType.CV_64F);
assertEquals(0, m.dims());
assertEquals(1, m.total());
double[] buf = new double[1];
assertEquals(1, m.put(new int[]{}, 42.0));
assertEquals(8, m.get(new int[]{}, buf));
assertEquals(42.0, buf[0], EPS);
assertArrayEquals(new double[]{42.0}, m.get(new int[]{}), EPS);
assertEquals(1, m.put(0, 0, 99.0));
assertArrayEquals(new double[]{99.0}, m.get(0, 0), EPS);
try {
m.get(new int[]{0}, buf);
fail("Expected IllegalArgumentException (Incorrect number of indices)");
} catch (IllegalArgumentException e) {
// expected
}
}
public void testGetPut1DMat() {
Mat m = new Mat(new int[]{5}, CvType.CV_32F);
assertEquals(1, m.dims());
assertEquals(5, m.total());
assertEquals(1, m.rows());
assertEquals(5, m.cols());
float[] data = new float[]{10, 20, 30, 40, 50};
assertEquals(20, m.put(new int[]{0}, data));
float[] read = new float[5];
assertEquals(20, m.get(new int[]{0}, read));
assertTrue(Arrays.equals(data, read));
assertEquals(1, m.put(new int[]{2}, 99.0f));
assertArrayEquals(new double[]{99.0}, m.get(new int[]{2}), EPS);
assertEquals(1, m.put(0, 1, 77.0f));
assertArrayEquals(new double[]{77.0}, m.get(0, 1), EPS);
float[] single = new float[1];
assertEquals(4, m.get(0, 3, single));
assertEquals(40.0f, single[0], EPS);
assertEquals(20, m.put(0, 0, data));
assertEquals(20, m.get(0, 0, read));
assertTrue(Arrays.equals(data, read));
try {
m.get(new int[]{0, 0}, new float[1]);
fail("Expected IllegalArgumentException (Incorrect number of indices)");
} catch (IllegalArgumentException e) {
// expected
}
}
public void testGetPut1DMatDoubleArray() {
Mat m = new Mat(new int[]{4}, CvType.CV_64F);
assertEquals(1, m.dims());
assertEquals(3, m.put(new int[]{1}, 1.0, 2.0, 3.0));
double[] buf = new double[3];
assertEquals(24, m.get(new int[]{1}, buf));
assertArrayEquals(new double[]{1.0, 2.0, 3.0}, buf, EPS);
}
public void testGetPut3DMat() {
Mat m = new Mat(new int[]{2, 2, 2}, CvType.CV_32F, new Scalar(0));
assertEquals(3, m.dims());
float[] buf = new float[1];
assertEquals(0, m.put(0, 0, 1.0f));
assertEquals(0, m.get(0, 0, buf));
assertNull(m.get(0, 0));
assertEquals(4, m.put(new int[]{1, 0, 1}, new float[]{3.14f}));
assertEquals(4, m.get(new int[]{1, 0, 1}, buf));
assertEquals(3.14f, buf[0], EPS);
assertArrayEquals(new double[]{3.14}, m.get(new int[]{1, 0, 1}), EPS);
}
public void testRelease() {
assertFalse(gray0.empty());
assertTrue(gray0.rows() > 0);

View File

@@ -2139,7 +2139,15 @@ namespace {
#undef JOCvT
}
// Element pointer that also supports 0D scalar Mats (OpenCV Mat::ptr(const int*) requires dims >= 1).
static uchar* mat_elem_ptr(cv::Mat* m, const int* idx) {
if (!m || !m->data) return nullptr;
if (m->dims <= 0) return m->data;
return m->ptr(idx);
}
static size_t idx2Offset(cv::Mat* mat, std::vector<int>& indices) {
if (mat->dims <= 0) return 0;
size_t offset = indices[0];
for (int dim=1; dim < mat->dims; dim++) {
offset = offset*mat->size[dim] + indices[dim];
@@ -2148,9 +2156,15 @@ static size_t idx2Offset(cv::Mat* mat, std::vector<int>& indices) {
}
static void offset2Idx(cv::Mat* mat, size_t offset, std::vector<int>& indices) {
if (mat->dims <= 0) {
indices.clear();
return;
}
if ((int)indices.size() != mat->dims)
indices.resize(mat->dims);
for (int dim=mat->dims-1; dim>=0; dim--) {
indices[dim] = offset % mat->size[dim];
offset = (offset - indices[dim]) / mat->size[dim];
indices[dim] = (int)(offset % mat->size[dim]);
offset = (offset - (size_t)indices[dim]) / mat->size[dim];
}
}
@@ -2163,31 +2177,66 @@ static bool updateIdx(cv::Mat* mat, std::vector<int>& indices, size_t inc) {
return reachedEnd;
}
// row/col APIs only address Mats with dims <= 2 (0D/1D/2D). ND Mats must use idx APIs.
// Matches OpenCV Mat::ptr(row,col) semantics: for dims<=1, row must be 0 and col is the index.
static bool check_row_col_access(const cv::Mat* me, int row, int col) {
if (!me) return false;
if (me->dims > 2) return false;
if (row < 0 || col < 0) return false;
if (me->rows <= row || me->cols <= col) return false;
return true;
}
static bool check_idx_access(const cv::Mat* me, const std::vector<int>& idx) {
if (!me) return false;
if ((int)idx.size() != me->dims) return false;
for (int i = 0; i < me->dims; i++) {
if (idx[i] < 0 || me->size[i] <= idx[i]) return false;
}
return true;
}
// Convert (row, col) to a dims-length index vector (OpenCV ptr(row,col) convention).
static std::vector<int> row_col_to_idx(const cv::Mat* m, int row, int col) {
if (m->dims <= 0)
return std::vector<int>();
if (m->dims == 1)
return std::vector<int>(1, col);
int indicesArray[] = { row, col };
return std::vector<int>(indicesArray, indicesArray+2);
}
template<typename T> static int mat_copy_data(cv::Mat* m, std::vector<int>& idx, int count, char* buff, bool isPut) {
if(! m) return 0;
if(! buff) return 0;
if(! m->data) return 0;
if ((int)idx.size() != m->dims) return 0;
size_t countBytes = count * sizeof(T);
size_t countBytes = (size_t)count * sizeof(T);
size_t remainingBytes = (size_t)(m->total() - idx2Offset(m, idx))*m->elemSize();
countBytes = (countBytes>remainingBytes)?remainingBytes:countBytes;
int res = (int)countBytes;
if (countBytes == 0) return 0;
if( m->isContinuous() )
if( m->isContinuous() || m->dims <= 1 )
{
uchar* data = mat_elem_ptr(m, idx.data());
if (!data) return 0;
if (isPut) {
memcpy(m->ptr(idx.data()), buff, countBytes);
memcpy(data, buff, countBytes);
} else {
memcpy(buff, m->ptr(idx.data()), countBytes);
memcpy(buff, data, countBytes);
}
} else {
size_t blockSize = m->size[m->dims-1] * m->elemSize();
size_t firstPartialBlockSize = (m->size[m->dims-1] - idx[m->dims-1]) * m->step[m->dims-1];;
size_t firstPartialBlockSize = (m->size[m->dims-1] - idx[m->dims-1]) * m->step[m->dims-1];
for (int dim=m->dims-2; dim>=0 && blockSize == m->step[dim]; dim--) {
blockSize *= m->size[dim];
firstPartialBlockSize += (m->size[dim] - (idx[dim]+1)) * m->step[dim];
}
size_t copyCount = (countBytes<firstPartialBlockSize)?countBytes:firstPartialBlockSize;
uchar* data = m->ptr(idx.data());
uchar* data = mat_elem_ptr(m, idx.data());
if (!data) return 0;
while(countBytes>0){
if (isPut) {
memcpy(data, buff, copyCount);
@@ -2198,7 +2247,8 @@ template<typename T> static int mat_copy_data(cv::Mat* m, std::vector<int>& idx,
countBytes -= copyCount;
buff += copyCount;
copyCount = countBytes<blockSize?countBytes:blockSize;
data = m->ptr(idx.data());
data = mat_elem_ptr(m, idx.data());
if (!data) break;
}
}
return res;
@@ -2211,8 +2261,7 @@ template<typename T> static int mat_put_idx(cv::Mat* m, std::vector<int>& idx, i
template<typename T> static int mat_put(cv::Mat* m, int row, int col, int count, int offset, char* buff)
{
int indicesArray[] = { row, col };
std::vector<int> indices(indicesArray, indicesArray+2);
std::vector<int> indices = row_col_to_idx(m, row, col);
return mat_put_idx<T>(m, indices, count, offset, buff);
}
@@ -2224,7 +2273,7 @@ template<class ARRAY> static jint java_mat_put(JNIEnv* env, jlong self, jint row
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
if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
if(!check_row_col_access(me, row, col)) return 0; // indexes out of range / dims > 2
char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
int res = mat_put<typename JavaOpenCVTrait<ARRAY>::value_type>(me, row, col, count, offset, values);
@@ -2248,9 +2297,7 @@ template<class ARRAY> static jint java_mat_put_idx(JNIEnv* env, jlong self, jint
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;
}
if (!check_idx_access(me, idx)) 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);
@@ -2370,7 +2417,7 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutD
LOGD("%s", method_name);
cv::Mat* me = (cv::Mat*) self;
if(!me || !me->data) return 0; // no native object behind
if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
if(!check_row_col_access(me, row, col)) return 0; // indexes out of range / dims > 2
int rest = ((me->rows - row) * me->cols - col) * me->channels();
if(count>rest) count = rest;
@@ -2417,7 +2464,7 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutD
}
// 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); }
#define PUT_ITEM_IDX(T, I) { T*dst = (T*)mat_elem_ptr(me, 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);
@@ -2431,14 +2478,10 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutDIdx
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;
if (!check_idx_access(me, idx)) return 0; // indexes out of range
if (count <= 0) return 0;
size_t rest = (me->total() - idx2Offset(me, idx)) * (size_t)me->channels();
if ((size_t)count > rest) count = (jint)rest;
int res = count;
double* values = (double*)env->GetPrimitiveArrayCritical(vals, 0);
double* src = values;
@@ -2475,8 +2518,7 @@ template<typename T> static int mat_get_idx(cv::Mat* m, std::vector<int>& idx, i
template<typename T> static int mat_get(cv::Mat* m, int row, int col, int count, char* buff)
{
int indicesArray[] = { row, col };
std::vector<int> indices(indicesArray, indicesArray+2);
std::vector<int> indices = row_col_to_idx(m, row, col);
return mat_get_idx<T>(m, indices, count, buff);
}
@@ -2487,7 +2529,7 @@ template<class ARRAY> static jint java_mat_get(JNIEnv* env, jlong self, jint row
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
if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
if(!check_row_col_access(me, row, col)) return 0; // indexes out of range / dims > 2
char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
int res = mat_get<typename JavaOpenCVTrait<ARRAY>::value_type>(me, row, col, count, values);
@@ -2510,9 +2552,7 @@ template<class ARRAY> static jint java_mat_get_idx(JNIEnv* env, jlong self, jint
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;
}
if (!check_idx_access(me, idx)) return 0;
char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
int res = mat_get_idx<typename JavaOpenCVTrait<ARRAY>::value_type>(me, idx, count, values);
@@ -2629,21 +2669,22 @@ JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_Mat_nGet
try {
LOGD("%s", method_name);
cv::Mat* me = (cv::Mat*) self;
if(! self) return 0; // no native object behind
if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
if(! self || !me->data) return 0; // no native object behind
if(!check_row_col_access(me, row, col)) return 0; // indexes out of range / dims > 2
jdoubleArray res = env->NewDoubleArray(me->channels());
if(res){
jdouble buff[CV_CN_MAX];//me->channels()
uchar* elem = me->ptr(row, col);
int i;
switch(me->depth()){
case CV_8U: for(i=0; i<me->channels(); i++) buff[i] = *((unsigned char*) me->ptr(row, col) + i); break;
case CV_8S: for(i=0; i<me->channels(); i++) buff[i] = *((signed char*) me->ptr(row, col) + i); break;
case CV_16U: for(i=0; i<me->channels(); i++) buff[i] = *((unsigned short*)me->ptr(row, col) + i); break;
case CV_16S: for(i=0; i<me->channels(); i++) buff[i] = *((signed short*) me->ptr(row, col) + i); break;
case CV_32S: for(i=0; i<me->channels(); i++) buff[i] = *((int*) me->ptr(row, col) + i); break;
case CV_32F: for(i=0; i<me->channels(); i++) buff[i] = *((float*) me->ptr(row, col) + i); break;
case CV_64F: for(i=0; i<me->channels(); i++) buff[i] = *((double*) me->ptr(row, col) + i); break;
case CV_8U: for(i=0; i<me->channels(); i++) buff[i] = *((unsigned char*) elem + i); break;
case CV_8S: for(i=0; i<me->channels(); i++) buff[i] = *((signed char*) elem + i); break;
case CV_16U: for(i=0; i<me->channels(); i++) buff[i] = *((unsigned short*)elem + i); break;
case CV_16S: for(i=0; i<me->channels(); i++) buff[i] = *((signed short*) elem + i); break;
case CV_32S: for(i=0; i<me->channels(); i++) buff[i] = *((int*) elem + i); break;
case CV_32F: for(i=0; i<me->channels(); i++) buff[i] = *((float*) elem + i); break;
case CV_64F: for(i=0; i<me->channels(); i++) buff[i] = *((double*) elem + i); break;
}
env->SetDoubleArrayRegion(res, 0, me->channels(), buff);
}
@@ -2667,24 +2708,24 @@ JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_Mat_nGetIdx
try {
LOGD("%s", method_name);
cv::Mat* me = (cv::Mat*) self;
if(! self) return 0; // no native object behind
if(! self || !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
}
if (!check_idx_access(me, idx)) return 0; // indexes out of range
jdoubleArray res = env->NewDoubleArray(me->channels());
if(res){
jdouble buff[CV_CN_MAX];//me->channels()
uchar* elem = mat_elem_ptr(me, idx.data());
if (!elem) return 0;
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;
case CV_8U: for(i=0; i<me->channels(); i++) buff[i] = *((unsigned char*) elem + i); break;
case CV_8S: for(i=0; i<me->channels(); i++) buff[i] = *((signed char*) elem + i); break;
case CV_16U: for(i=0; i<me->channels(); i++) buff[i] = *((unsigned short*)elem + i); break;
case CV_16S: for(i=0; i<me->channels(); i++) buff[i] = *((signed short*) elem + i); break;
case CV_32S: for(i=0; i<me->channels(); i++) buff[i] = *((int*) elem + i); break;
case CV_32F: for(i=0; i<me->channels(); i++) buff[i] = *((float*) elem + i); break;
case CV_64F: for(i=0; i<me->channels(); i++) buff[i] = *((double*) elem + i); break;
}
env->SetDoubleArrayRegion(res, 0, me->channels(), buff);
}