Using get() and put() to access pixel values in OpenCV for Java
Solution 1
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.total() * A.channels());
double[] temp = new double[size]; // use double[] instead of byte[]
A.get(0, 0, temp);
for (int i = 0; i < 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 method is way faster than first method.
Solution 2
Found a simple and working solution after a lot of searching-
Mat img = Highgui.imread("Input.jpg"); //Reads image from the file system and puts into matrix
int rows = img.rows(); //Calculates number of rows
int cols = img.cols(); //Calculates number of columns
int ch = img.channels(); //Calculates number of channels (Grayscale: 1, RGB: 3, etc.)
for (int i=0; i<rows; i++)
{
for (int j=0; j<cols; j++)
{
double[] data = img.get(i, j); //Stores element in an array
for (int k = 0; k < ch; k++) //Runs for the available number of channels
{
data[k] = data[k] * 2; //Pixel modification done here
}
img.put(i, j, data); //Puts element back into matrix
}
}
Highgui.imwrite("Output.jpg", img); //Writes image back to the file system using values of the modified matrix
Note: An important point that has not been mentioned anywhere online is that the method put
does not write pixels onto Input.jpg
. It merely updates the values of the matrix img
. Therefore, the above code does not alter anything in the input image. For producing a visible output, the matrix img
needs to be written onto a file i.e., Output.jpg
in this case. Also, using img.get(i, j)
seems to be a better way of handling the matrix elements rather than using the accepted solution above as this helps in visualizing and working with the image matrix in a better way and does not require a large contiguous memory allocation.
gargsl
Updated on July 16, 2022Comments
-
gargsl almost 2 years
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.total() * 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.
Thanks!
-
rmaik about 9 yearsthanks for the good question, can u please explain why u used : (A.total() * A.channels());?? the total( method returns the withd*height, why u multipled by the channel numbers, i know the RGB image has 3 channels...but i need more clarification please
-
gargsl about 9 years@rmaik Each channel has it's own intensity values (red, blue or green) for each pixel. So, total number of those intensity values in an image is equal to number of pixels * total number of channels. So, in this case total() gives you total number of pixels in the image and channel() gives you number of channels.
-
Renaud over 7 yearsIt works but is very very slow. Can take 30sec for a 8MP image on a good computer. Instead you want to read all the data at once in a buffer using Mat.get(0,0, byte[totalNumberOfPixel * bytesPerPixel])