7

少し前にO'Reillyの「LearningOpenCV」という本を手に入れました。それ以来、そこにあるすべてのサンプルコードをOpenCVからJavaCVに変換するのに忙しく、通常は自分で少し変更を加えています。その間、私は可能な限り純粋なOpenCV(C言語)コードを維持し、Javaを避けようとしています。たとえば、Java Swingを介してではなく、JavaCVのOpenCVhighguiパッケージを介してすべてのインターフェイス要素を直接実装しました。これを行うことで、OpenCVライブラリといくつかのCを比較的短い順序で学習し、後で純粋なOpenCVに切り替えることにした場合にCに簡単に変換できる便利な関数のライブラリを確立したいと思っています。

とにかく、私はCの知識がほとんどなく、ポインタを扱うときに問題が発生することがあります。この本では、3チャネルマトリックスを反復処理するための最適な手段として、次のコードを推奨しています。

float sum( const CvMat* mat ) {
    float s = 0.0f;
    for(int row=0; row<mat->rows; row++ ) {
        const float* ptr = (const float*)(mat->data.ptr + row * mat->step);
        for( col=0; col<mat->cols; col++ ) {
            s += *ptr++;
        }
    }
    return( s );
}

このコードに含まれている説明は次のとおりです。

行列へのポインタを計算するときは、行列要素のデータが和集合であることに注意してください。したがって、このポインターを逆参照するときは、正しいポインター型を取得するために、共用体の正しい要素を指定する必要があります。そのポインタをオフセットするには、行列のステップ要素を使用する必要があります。前述のように、ステップ要素はバイト単位です。安全のために、ポインタ演算をバイト単位で実行してから、適切な型(この場合はfloat)にキャストするのが最善です。CVMat構造には、古いIplImage構造との互換性のために高さと幅の概念がありますが、代わりに、より最新の行と列を使用します。最後に、単に最初から始めて、読み取るたびにそのポインタをインクリメントするのではなく、すべての行に対してptrを再計算することに注意してください。これは過剰に見えるかもしれませんが、

ただし、JavaCVへの変換に問題があります。ptrフィールド(ポインタ)はfloatのようで、混乱します。それは実際には「ポインタ」ではなく、各ピクセルの値が追加される値だと思いますか?それとも、実際にはポインタであり、s値は、指定された行内のすべての列の合計を求めますか?

とにかく、誰かが私のために同等のループのJavaCVコードを投稿してくれたらありがたいです。CvMatのすべてのピクセルにアクセスする方法は他にもあることは知っていますが、AFAIKでは、それらはすべて効率が悪いか、不正確です。

4

2 に答える 2

6

提供する特定の例は、次のようにJavaに最適に変換されます。

float sum(CvMat mat) {
    final int rows = mat.rows();
    final int cols = mat.cols();
    final int step = mat.step()/4;
    FloatBuffer buf = mat.getFloatBuffer();
    float s = 0.0f;
    for (int row = 0; row < rows; row++) {
        buf.position(row * step);
        for (int col = 0; col< cols; col++) {
            s += buf.get();
        }
    }
    return s;
}
于 2012-04-15T05:26:58.130 に答える
0

これが私が最終的に試行錯誤して得た変種です。3チャネルの行列を反復処理し、非常に単純なフィルターを適用するため(Samuelの例では、グレースケール値の合計がすでに適切にカバーされていると思います)。

static IplImage setSaturate_sv(IplImage imgIn) {
    IplImage imgOut = cvCloneImage(imgIn);
    ByteBuffer pointer = imgOut.getByteBuffer();

    int height = imgIn.height();
    int width = imgIn.width();
    int widthStep = imgIn.widthStep();
    int nChannels = imgIn.nChannels();
    int rowIndex;

    for (int row = 0; row < height; row++) {
        rowIndex = row * widthStep;
        for (int col = 0; col < width; col++) {
            pointer.put((rowIndex + (col * nChannels) + 1), (byte)255);
            pointer.put((rowIndex + (col * nChannels) + 2), (byte)255);
            pointer.put((rowIndex + (col * nChannels) + 3), /* leave alone */);
        }
    }
    return imgOut;
}   
于 2012-05-05T07:18:52.823 に答える