web-dev-qa-db-ja.com

get()とput()を使用して、OpenCVのピクセル値にアクセスしますJava

私はOpenCVforJavaの使用の初心者です。画像マトリックスの個々のピクセル値にアクセスしたい。 Java jar forOpenCVはC++のような素晴らしい関数を提供していないので、私はいくつかの問題に遭遇しました。多くの検索の結果、適切に説明されていませんが、それを行うための2つの異なる方法を見つけました。 (ドキュメントにもありません)get()関数とput()関数を使用するか、マットデータを配列などのプリミティブ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つのチャネルすべて)にアクセスし、半分にします。実行してもエラーは発生しません。しかし、私が得ている出力画像は、これら2つの場合で異なります。誰かが問題を説明できますか? get()関数がどのように機能するのか正確に理解していないのでしょうか? byte()キャストが原因ですか?助けてください。

ありがとう!

10
gargsl

これは、byte()のキャストが原因で発生していました。 2番目のケースのマットイメージのデータ型を* CV_64FC3 *に変更して、byte []の代わりにdouble []を使用できるようにしたところ、問題が解決しました。

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

参考までに、私も時間測定を行いました。2番目の方法を使用すると、最初の方法よりもはるかに高速です。

9
gargsl

多くの検索の後、シンプルで実用的なソリューションを見つけました-

_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)を使用することは、上記の受け入れられたソリューションを使用するよりも、マトリックス要素を処理するためのより良い方法のようです。これは、画像マトリックスをより適切に視覚化して操作するのに役立ち、大きな連続を必要としないためです。メモリ割り当て。

1
CrakC