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. :)
我是JAVA使用OpenCV的初学者。我想访问图像矩阵的单个像素值。由于OpenCV的JAVA jar没有提供像c++这样的好函数,我遇到了一些麻烦。在大量的搜索之后,我发现了两种不同的方法,尽管它们没有得到正确的解释(甚至在文档中也没有)。我们可以使用get()和put()函数,也可以将mat数据转换为基本的java类型(如数组)。我两者都试过了,但是得到的输出结果不同!请帮忙解释一下我做错了什么。是我用错了还是其他愚蠢的问题?我还是一个新手,所以请原谅我这个愚蠢的问题。:)
CASE 1: Using get() function
案例1:使用get()函数
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
例2:使用数组
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.
照我的意思,他们二人都当这样行。它们都访问单个像素值(所有3个通道),并使其减半。我在跑步之后没有任何错误。但是,在这两种情况下,我得到的输出图像是不同的。谁能解释一下是什么问题吗?可能我不明白get()函数是如何工作的?是因为字节()强制转换吗?请帮助。
Thanks!
谢谢!
2 个解决方案
#1
9
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图像的数据类型改为*CV_64FC3*,这样我就可以使用double[]而不是byte[],从而解决了问题。
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.
顺便说一下,我也做了一些时间测量,第二种方法比第一种方法快得多。
#2
1
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.
注意:在网上没有提到的重要一点是,put方法不会将像素写到Input.jpg上。它仅仅更新矩阵img的值。因此,上面的代码不会改变输入映像中的任何内容。为了产生一个可见的输出,矩阵img需要被写入到一个文件中。,在本例中为Output.jpg。此外,使用img。get(i, j)似乎是处理矩阵元素的一种更好的方法,而不是使用上面已接受的解决方案,因为这有助于以更好的方式可视化和处理图像矩阵,并且不需要大的连续内存分配。
#1
9
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图像的数据类型改为*CV_64FC3*,这样我就可以使用double[]而不是byte[],从而解决了问题。
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.
顺便说一下,我也做了一些时间测量,第二种方法比第一种方法快得多。
#2
1
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.
注意:在网上没有提到的重要一点是,put方法不会将像素写到Input.jpg上。它仅仅更新矩阵img的值。因此,上面的代码不会改变输入映像中的任何内容。为了产生一个可见的输出,矩阵img需要被写入到一个文件中。,在本例中为Output.jpg。此外,使用img。get(i, j)似乎是处理矩阵元素的一种更好的方法,而不是使用上面已接受的解决方案,因为这有助于以更好的方式可视化和处理图像矩阵,并且不需要大的连续内存分配。