5

I am currently translating a bit of c++ code to Java, for an Android-application. I have stumbled upon a tricky bit of c++ code however (also c++ is not my main language). Below is the c++-code. This function calculates the image gradients in an openCV imageFrame (in gray scale).

cv::Mat computeMatXGradient(const cv::Mat &mat) {
  cv::Mat out(mat.rows,mat.cols,CV_64F);

  for (int y = 0; y < mat.rows; ++y) {
    const uchar *Mr = mat.ptr<uchar>(y);
    double *Or = out.ptr<double>(y);

    Or[0] = Mr[1] - Mr[0];
    for (int x = 1; x < mat.cols - 1; ++x) {
      Or[x] = (Mr[x+1] - Mr[x-1])/2.0;
    }
    Or[mat.cols-1] = Mr[mat.cols-1] - Mr[mat.cols-2];
  }
}

In this snippet, I don't know how to interpret the first two lines in the first loop:

    const uchar *Mr = mat.ptr<uchar>(y);
    double *Or = out.ptr<double>(y);

What is being done here, and how could I translate it to Java-code? I have looked into the 'mat.ptr<>()' function, but that wasn't very helpful either. (Documentation can be found here.) Basic information about pointers (like here) I've already read into, but I still don't get how to read the lines above. Apart from the pointers used, I'm also not quite sure how to handle the 'uchar'-type that is being used. How does that translate to Java?

The entire code can be found here.

I've already looked into ways of implementing the Gradient-function of Matlab from scratch, but that seems a lot harder. (Yes, there are already topics about that (e.x. here), but this thread doesn't provide an actual answer on how to do it.)

I really hope someone can explain how to handle the c++-structures above, in Java. I did all the possible research I could do so far, but I just can't get my head around how to do it in Java. Thanks in advance!

EDIT; In the end I've been able to get it working by just using a double for-loop. The code is below. It is much less efficient however. On a galaxy tab4 the process-rate is only about 1 frame per second. I wasn't expecting to get perfect results, but I had hoped it would be a bit faster. Does anyone know if the code below can be done more efficiently? Even the smallest change will be great, because there are like six of those double for-loops in the algorithm.

private static Mat computeXGradient (Mat mat) {
    //Mat output = new Mat(mat.rows(), mat.cols(), CvType.CV_64F);
    Mat output = new Mat(mat.rows(), mat.cols(), CvType.CV_32F);
    for (byte y = 0; y < mat.rows(); ++y) {
        Mat mr = mat.row(y);
        output.put(y,0, mr.get(0,1)[0] - mr.get(0,0)[0]);
        for (byte x = 1; x < mat.cols() - 1; ++x) {
            output.put(y,x, (mr.get(0,x+1)[0] - mr.get(0,x-1)[0])/2.0);
        }
    }
    return output;
}

I already implemented multi-threading (with actual forcing of using more processors), and as you can see I also scaled down the size of the Mat-objects I am working with.

EDIT; after adjusting the resolution, the frame-rate went up to a very acceptable level. Hopefully this change will not affect the spatial performance too much, but we will see about that.

Community
  • 1
  • 1
  • btw, [Sobel](http://docs.opencv.org/java/org/opencv/imgproc/Imgproc.html#Sobel(org.opencv.core.Mat,%20org.opencv.core.Mat,%20int,%20int,%20int)) is available from pure java, you probably do not need any jni magic here. – berak Apr 18 '15 at 18:49

1 Answers1

1

mat.ptr(y) fetches row y from the matrix.

Likewise, out.ptr(y) fetches row y from the output matrix.

As far as translation, you might either create a Row class in Java, or just return an array from the ptr function.

If you don't have the Matrix classes already provided, you might make Row a generic type, like this library did. (eg. Row<Integer>)

uchar (unsigned char) roughly translates to byte in Java. It's an 8 bit (signed) integer value. If you want to ensure you can use the entire 0-255 range, use an int instead.

Barett
  • 5,826
  • 6
  • 51
  • 55
  • 1
    Be prepared for surprises. uchar does not translate 1:1 to Java's byte, which is a signed(!) 8-bit quantity. – laune Apr 18 '15 at 17:46
  • Thanks for the answer! In the end it turned out I could just do a double for-loop and get the first entry in the Array stored at (y,x). You're answer helped me getting there ;) It does turn out to be terribly inefficient in JAVA however. Could that have something to do with why one would use pointers in C(++)? Are they more efficient? – Mastermind1992 Apr 25 '15 at 20:56
  • Hard to say why your double for loop in Java seems less efficient than equivalent code in C++ without seeing the code. There isn't anything implicit in the language itself that would cause a significant difference. – Barett Apr 27 '15 at 18:36
  • Hi, I added the for-loop I came up with in Java in my original post. I should have mentioned I am running my code on an Android (galaxy tab4) device and that I'm building an eye-tracker. I still expected better results than I am getting right now however (.5 fps). I know, for example, that in a study done in 2011 a similar algorithm hit about 1.5fps on an iPad2. – Mastermind1992 Apr 28 '15 at 01:39