10

我是使用 OpenCV for JAVA 的初学者。我想访问图像矩阵的单个像素值。由于 OpenCV 的 JAVA jar 没有提供像 C++ 这样的好功能,我遇到了一些麻烦。经过大量搜索,我发现了两种不同的方法来做到这一点,尽管它们没有得到正确的解释(甚至在文档中也没有)。我们可以使用 get() 和 put() 函数或将 mat 数据转换为原始 java 类型(如数组)来做到这一点。我都尝试了,但得到了不同的输出结果!请帮助解释我做错了什么。我是用错了它们还是其他一些愚蠢的问题。我还是一个新手,所以如果这是一个愚蠢的问题,请原谅。:)

案例 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);
    }

案例 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);

现在根据我的理解,他们都应该做同样的事情。它们都访问单个像素值(所有 3 个通道)并将其减半。运行后我没有收到任何错误。但是,在这两种情况下,我得到的输出图像是不同的。有人可以解释一下是什么问题吗?可能我不明白 get() 函数是如何工作的?是因为 byte() 强制转换吗?请帮忙。

谢谢!

4

2 回答 2

9

这是因为 byte() 强制转换而发生的。我在第二种情况下将 mat image 的数据类型更改为 *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);

仅供参考,我也做了一些时间测量,使用第二种方法比第一种方法快得多。

于 2013-06-11T16:51:58.437 回答
1

经过大量搜索,找到了一个简单且有效的解决方案-

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

注意:网上任何地方都没有提到的重要一点是该方法put不会将像素写入Input.jpg. 它只是更新矩阵的值img。因此,上面的代码不会改变输入图像中的任何内容。为了产生可见的输出,img需要将矩阵写入文件,即Output.jpg在这种情况下。此外,使用img.get(i, j)似乎是处理矩阵元素的更好方法,而不是使用上面公认的解决方案,因为这有助于以更好的方式可视化和使用图像矩阵,并且不需要大量的连续内存分配。

于 2015-10-19T20:40:52.257 回答