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!
Retrieving the pixel contents (ARGB values) of an image − Get the pixel value at every point using the getRGB() method. Instantiate the Color object by passing the pixel value as a parameter. Get the Red, Green, Blue values using the getRed(), getGreen() and getBlue() methods respectively.
To get the pixels of an image, a built-in function named 'flatten' is used. After the image is read, the pixel values are stored in the form of a dataframe. The function 'flatten' is used to convert the three dimensions of an RGB image into a single dimension and get the value of pixels into a dataframe.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With