Using get() and put() to access pixel values in JAVA

asked 2013-06-10 19:36:12 -0600

gargsl gravatar image

updated 2017-10-08 11:34:46 -0600

I am a beginner in using OpenCV for JAVA. I want to access individual pixel values of an image matrix. Since, JAVA jar for OpenCV doesn't offer nice functions like C++, I ran into some trouble. After lot of searching, I found out two different methods to do that though they are not explained properly (not even in documentation). We can do that either using get() and put() functions or by converting the mat data into a primitive java type such as arrays. I tried both but getting different output results! Please help explaining what am I doing wrong. Am I using them wrong or some other silly problem. I am still a newbie so please forgive if its a stupid question. :)

CASE 1: Using get() function

Mat A = Highgui.imread(image_addr); \\"image_addr" is the address of the image
Mat C = A.clone();
Size sizeA = A.size();
for (int i = 0; i < sizeA.height; i++)
    for (int j = 0; j < sizeA.width; j++) {
        double[] data = A.get(i, j);
        data[0] = data[0] / 2;
        data[1] = data[1] / 2;
        data[2] = data[2] / 2;
        C.put(i, j, data);

CASE 2: Using Array

Mat A = Highgui.imread(image_addr); \\"image_addr" is the address of the image
Mat C = A.clone();
int size = (int) ( * A.channels());
byte[] temp = new byte[size];
A.get(0, 0, temp);
for (int i = 0; i < size; i++)
   temp[i] = (byte) (temp[i] / 2);
C.put(0, 0, temp);

Now according to my understanding they both should do the same thing. They both access the individual pixel values (all 3 channels) and making it half. I am getting no error after running. But, the output image I am getting is different in these two cases. Can someone please explain what is the issue? May be I don't understand exactly how get() function works? Is it because of the byte() casting? Please help.


edit retag flag offensive close merge delete


As you mentioned already: It is probably due to the byte cast. Could you clarify why you use such a tricky approach to set and get values ?

keltik gravatar imagekeltik ( 2013-06-11 02:42:13 -0600 )edit

As far as I know, there is no other way of working directly with pixels in java openCV. But, I started working with it just two days back so might not be aware of any existing other methods. I wanted to try out both these two methods to know the performance of these two approaches. Please let me know if you know of any other easy way of doing this.

gargsl gravatar imagegargsl ( 2013-06-11 11:57:13 -0600 )edit

Posting the answer here as its not letting me answer my own question. It was happening because of byte() casting. I changed the data type of mat image in second case to CV_64FC3 so that I can use double[] instead of byte[] and it solved the problem.

Mat A = Highgui.imread(image_addr); \\"image_addr" is the address of the image
Mat C = A.clone();
A.convertTo(A, CvType.CV_64FC3); \\New line added. 
int size = (int) ( * A.channels());
double[] temp = new double[size]; \\ use double[] instead of byte[]
A.get(0, 0, temp);
for (int i = 0; i &lt; size; i++)
   temp[i] = (temp[i] / 2);  \\ no more casting required.
C.put(0, 0, temp);

FYI, I also did some time measurement and using second methos is way faster than first method.

gargsl gravatar imagegargsl ( 2013-06-11 11:59:30 -0600 )edit

One more note: Using second method is possible only if the matrix is continuous. We can check this by isContinuous() flag. Though, this will be the case most of the time, its a good idea to do a check before.

gargsl gravatar imagegargsl ( 2013-06-11 12:20:59 -0600 )edit

When ROIs are used (Mat.submat()), the resulting Mat is not continuous. This means when we use ROIs, we would not be able to read the image in one call, but we would have to do one get per row.

Update: Actually, it does work with ROIs (submat). Mat.get must be doing some magic inside, in order to retrieve only the relevant pixels.

Jose Gómez gravatar imageJose Gómez ( 2013-11-13 13:34:25 -0600 )edit