Convert OpenCv DFT example from C++ to Android

2

I want to implement follwoing OpenCV example in a Android app:

http://docs.opencv.org/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.html

My code is the foll0wing:

        //First convert Bitmap to Mat
        Mat ImageMat = new Mat ( image.getHeight(), image.getWidth(), CvType.CV_64FC1, new Scalar(4));
        Bitmap myBitmap32 = image.copy(Bitmap.Config.ARGB_8888, true);
        Utils.bitmapToMat(myBitmap32, ImageMat);


        Imgproc.cvtColor(ImageMat, ImageMat, Imgproc.COLOR_RGB2GRAY);

        Mat padded = new Mat(CvType.CV_64FC1);                            //expand input image to optimal size
        int m = Core.getOptimalDFTSize(ImageMat.rows());
        int n = Core.getOptimalDFTSize(ImageMat.cols()); // on the border add zero values
        Imgproc.copyMakeBorder(ImageMat, padded, 0, m - ImageMat.rows(), 0, n - ImageMat.cols(), Imgproc.BORDER_CONSTANT);

        List<Mat> planes = new ArrayList<Mat>();
        planes.add(padded);
        planes.add(Mat.zeros(padded.rows(), padded.cols(), CvType.CV_64FC1));

        Mat complexI = Mat.zeros(padded.rows(), padded.cols(), CvType.CV_64FC1);

        Core.merge(planes, complexI);         // Add to the expanded another plane with zeros

        Core.dft(complexI, complexI);            // this way the result may fit in the source matrix

        // compute the magnitude and switch to logarithmic scale
        // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
        Core.split(complexI, planes);                   // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
        Core.magnitude(planes.get(0), planes.get(1), planes.get(1));// planes[0] = magnitude
        Mat magI = planes.get(0);

        Core.add(magI, Mat.ones(padded.rows(), padded.cols(), CvType.CV_64FC1), magI);                 // switch to logarithmic scale
        Core.log(magI, magI);


        Mat crop = new Mat(magI, new Rect(0, 0, magI.cols() & -2, magI.rows() & -2));

        magI = crop.clone();

        // rearrange the quadrants of Fourier image  so that the origin is at the image center
        int cx = magI.cols()/2;
        int cy = magI.rows()/2;


        Rect q0Rect = new Rect (0, 0, cx, cy);
        Rect q1Rect = new Rect (cx, 0, cx, cy);
        Rect q2Rect = new Rect (0, cy, cx, cy);
        Rect q3Rect = new Rect (cx, cy, cx, cy);

        Mat q0 = new Mat(magI, q0Rect);   // Top-Left - Create a ROI per quadrant
        Mat q1 = new Mat(magI, q1Rect);  // Top-Right
        Mat q2 = new Mat(magI, q2Rect);  // Bottom-Left
        Mat q3 = new Mat(magI, q3Rect); // Bottom-Right

        Mat tmp = new Mat();                           // swap quadrants (Top-Left with Bottom-Right)
        q0.copyTo(tmp);
        q3.copyTo(q0);
        tmp.copyTo(q3);

        q1.copyTo(tmp);                    // swap quadrant (Top-Right with Bottom-Left)
        q2.copyTo(q1);
        tmp.copyTo(q2);

        Core.normalize(magI, magI, 0, 1, Core.NORM_MINMAX);

        Mat realResult = new Mat();
        magI.convertTo(realResult, CvType.CV_64FC1);




        //Then convert the processed Mat to Bitmap
        Bitmap resultBitmap = Bitmap.createBitmap(ImageMat.cols(),  ImageMat.rows(),Bitmap.Config.ARGB_8888);;
        Utils.matToBitmap(ImageMat, resultBitmap);

        //Set member to the Result Bitmap. This member is displayed in an ImageView
        mResult = resultBitmap;

(note: image is the Input Bitmap and mResult is the output bitmap that is shown in a ImageView)

I get the following error:

Error: 08-08 12:17:36.207: A/libc(1594): Fatal signal 11 (SIGSEGV) at 0x0000000a (code=1), thread 1594 (XXXX)

Is anyone able to see my error?

android
opencv
dft
asked on Stack Overflow Aug 8, 2013 by DanS • edited Aug 8, 2013 by Aurelius

1 Answer

2

I copied the code and got it to work on Android. There's a few changes I've made, not sure all are necessary but here they are:

  1. having the dst and src the same is ok in C++ but I'm not sure Java implementation is as tolerant. I tend to always create different objects for these to avoid any conflicts
  2. The 'padded' Mat object: I've initialised with the size:

    Mat padded = new Mat(new Size(n, m), CvType.CV_64FC1)
    
  3. Mat complexI should be of type CV_64FC2 I think.

  4. I set the upper bound variable for the Core.normalize call to 255
  5. I convert the results back to a CV_8UC1 so I can display on my implementation.

Here is the code I've been using:

    private Mat getDFT(Mat singleChannel) {

    singleChannel.convertTo(image1, CvType.CV_64FC1);

    int m = Core.getOptimalDFTSize(image1.rows());
    int n = Core.getOptimalDFTSize(image1.cols()); // on the border
                                                    // add zero
                                                    // values
                                                    // Imgproc.copyMakeBorder(image1,
                                                    // padded, 0, m -
                                                    // image1.rows(), 0, n

    Mat padded = new Mat(new Size(n, m), CvType.CV_64FC1); // expand input
                                                            // image to
                                                            // optimal size

    Imgproc.copyMakeBorder(image1, padded, 0, m - singleChannel.rows(), 0,
            n - singleChannel.cols(), Imgproc.BORDER_CONSTANT);

    List<Mat> planes = new ArrayList<Mat>();
    planes.add(padded);
    planes.add(Mat.zeros(padded.rows(), padded.cols(), CvType.CV_64FC1));

    Mat complexI = Mat.zeros(padded.rows(), padded.cols(), CvType.CV_64FC2);

    Mat complexI2 = Mat
            .zeros(padded.rows(), padded.cols(), CvType.CV_64FC2);

    Core.merge(planes, complexI); // Add to the expanded another plane with
                                    // zeros

    Core.dft(complexI, complexI2); // this way the result may fit in the
                                    // source matrix

    // compute the magnitude and switch to logarithmic scale
    // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
    Core.split(complexI2, planes); // planes[0] = Re(DFT(I), planes[1] =
                                    // Im(DFT(I))

    Mat mag = new Mat(planes.get(0).size(), planes.get(0).type());

    Core.magnitude(planes.get(0), planes.get(1), mag);// planes[0]
                                                        // =
                                                        // magnitude

    Mat magI = mag;
    Mat magI2 = new Mat(magI.size(), magI.type());
    Mat magI3 = new Mat(magI.size(), magI.type());
    Mat magI4 = new Mat(magI.size(), magI.type());
    Mat magI5 = new Mat(magI.size(), magI.type());

    Core.add(magI, Mat.ones(padded.rows(), padded.cols(), CvType.CV_64FC1),
            magI2); // switch to logarithmic scale
    Core.log(magI2, magI3);

    Mat crop = new Mat(magI3, new Rect(0, 0, magI3.cols() & -2,
            magI3.rows() & -2));

    magI4 = crop.clone();

    // rearrange the quadrants of Fourier image so that the origin is at the
    // image center
    int cx = magI4.cols() / 2;
    int cy = magI4.rows() / 2;

    Rect q0Rect = new Rect(0, 0, cx, cy);
    Rect q1Rect = new Rect(cx, 0, cx, cy);
    Rect q2Rect = new Rect(0, cy, cx, cy);
    Rect q3Rect = new Rect(cx, cy, cx, cy);

    Mat q0 = new Mat(magI4, q0Rect); // Top-Left - Create a ROI per quadrant
    Mat q1 = new Mat(magI4, q1Rect); // Top-Right
    Mat q2 = new Mat(magI4, q2Rect); // Bottom-Left
    Mat q3 = new Mat(magI4, q3Rect); // Bottom-Right

    Mat tmp = new Mat(); // swap quadrants (Top-Left with Bottom-Right)
    q0.copyTo(tmp);
    q3.copyTo(q0);
    tmp.copyTo(q3);

    q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
    q2.copyTo(q1);
    tmp.copyTo(q2);

    Core.normalize(magI4, magI5, 0, 255, Core.NORM_MINMAX);

    Mat realResult = new Mat(magI5.size(), CvType.CV_8UC1);

    magI5.convertTo(realResult, CvType.CV_8UC1);

    return realResult;
}

Here is an example of the results; the background is the original image; bottom left is the single channel version passed to the function and top right is the image returned by the function.

enter image description here

answered on Stack Overflow Dec 27, 2013 by timegalore • edited Dec 29, 2013 by timegalore

User contributions licensed under CC BY-SA 3.0