3

I have developed an application to detect head gestures using OpenCV optic flow. I want to optimize my calculation method. Because currently it is very slow. Could you suggest me better, fast, efficient way to do it?

Currently I am comparing X and Y coordinates of every feature points between two frames to decide optic flow direction. I want to decrease number of features to check to find optic flow direction. Select the minimal feature points that best represent the feature set.

Here is my code:

    @Override
    public Mat onCameraFrame(Mat inputFrame) {
        up.value = 0;
        down.value = 0;
        left.value = 0;
        right.value = 0;
        pq.clear();

        // start the timing counter to put the frame rate on screen
        // and make sure the start time is up to date, do
        // a reset every 10 seconds
        if (lMilliStart == 0)
            lMilliStart = System.currentTimeMillis();

        if ((lMilliNow - lMilliStart) > 10000) {
            lMilliStart = System.currentTimeMillis();
            lFrameCount = 0;
        }

        inputFrame.copyTo(mRgba);
        sMatSize.width = mRgba.width();
        sMatSize.height = mRgba.height();

        switch (viewMode) {

        case VIEW_MODE_OPFLOW:

            if (mMOP2fptsPrev.rows() == 0) {

                // Log.d("Baz", "First time opflow");
                // first time through the loop so we need prev and this mats
                // plus prev points
                // get this mat
                Imgproc.cvtColor(mRgba, matOpFlowThis, Imgproc.COLOR_RGBA2GRAY);

                // copy that to prev mat
                matOpFlowThis.copyTo(matOpFlowPrev);

                // get prev corners
                Imgproc.goodFeaturesToTrack(matOpFlowPrev, MOPcorners, iGFFTMax, 0.05, 20);
                mMOP2fptsPrev.fromArray(MOPcorners.toArray());

                // get safe copy of this corners
                mMOP2fptsPrev.copyTo(mMOP2fptsSafe);
            } else {
                // Log.d("Baz", "Opflow");
                // we've been through before so
                // this mat is valid. Copy it to prev mat
                matOpFlowThis.copyTo(matOpFlowPrev);

                // get this mat
                Imgproc.cvtColor(mRgba, matOpFlowThis, Imgproc.COLOR_RGBA2GRAY);

                // get the corners for this mat
                Imgproc.goodFeaturesToTrack(matOpFlowThis, MOPcorners, iGFFTMax, 0.05, 20);
                mMOP2fptsThis.fromArray(MOPcorners.toArray());

                // retrieve the corners from the prev mat
                // (saves calculating them again)
                mMOP2fptsSafe.copyTo(mMOP2fptsPrev);

                // and save this corners for next time through
                mMOP2fptsThis.copyTo(mMOP2fptsSafe);
            }

            /*
             * Parameters: prevImg first 8-bit input image nextImg second input
             * image prevPts vector of 2D points for which the flow needs to be
             * found; point coordinates must be single-precision floating-point
             * numbers. nextPts output vector of 2D points (with
             * single-precision floating-point coordinates) containing the
             * calculated new positions of input features in the second image;
             * when OPTFLOW_USE_INITIAL_FLOW flag is passed, the vector must
             * have the same size as in the input. status output status vector
             * (of unsigned chars); each element of the vector is set to 1 if
             * the flow for the corresponding features has been found,
             * otherwise, it is set to 0. err output vector of errors; each
             * element of the vector is set to an error for the corresponding
             * feature, type of the error measure can be set in flags parameter;
             * if the flow wasn't found then the error is not defined (use the
             * status parameter to find such cases).
             */
            Video.calcOpticalFlowPyrLK(matOpFlowPrev, matOpFlowThis, mMOP2fptsPrev, mMOP2fptsThis, mMOBStatus, mMOFerr);

            cornersPrev = mMOP2fptsPrev.toList();
            cornersThis = mMOP2fptsThis.toList();
            byteStatus = mMOBStatus.toList();

            y = byteStatus.size() - 1;

            for (x = 0; x < y; x++) {
                if (byteStatus.get(x) == 1) {
                    pt = cornersThis.get(x);
                    pt2 = cornersPrev.get(x);
                    double m = Math.abs(pt2.y - pt.y ) / Math.abs(pt2.x - pt.x);

                    double distance= Math.sqrt(Math.pow((pt.x - pt2.x),2) + Math.pow((pt.y - pt2.y),2));

                    if(distance < NOISE)
                        continue;

                    if (pt.x < pt2.x && pt2.y < pt.y)

                        if (m > 1)
                            up.value++;
                        else
                            right.value++;

                    else if (pt.x < pt2.x && pt2.y == pt.y)
                        right.value++;

                    else if (pt.x < pt2.x && pt2.y > pt.y)
                        if (m > 1)
                            down.value++;
                        else
                            right.value++;

                    else if (pt.x == pt2.x && pt2.y > pt.y)
                        down.value++;

                    else if (pt.x > pt2.x && pt2.y > pt.y)
                        if (m > 1)
                            down.value++;
                        else
                            left.value++;

                    else if (pt.x > pt2.x && pt2.y == pt.y)
                        left.value++;

                    else if (pt.x > pt2.x && pt2.y < pt.y)
                        if (m > 1)
                            up.value++;
                        else
                            left.value++;

                    else if (pt.x == pt2.x && pt2.y < pt.y)
                        up.value++;

                    Core.circle(mRgba, pt, 5, colorRed, iLineThickness - 1);
                    Core.line(mRgba, pt, pt2, colorRed, iLineThickness);
                }
            }//end of for

            Direction r1, r2, r3;

            if(up.value == 0 && left.value == 0 && right.value == 0 && down.value == 0) {
                string = String.format("Direction: ---");
                showTitle(string, 3, colorRed);

            }else{

                if (left.value < right.value) {
                    r1 = right;
                } else r1 = left;

                if (up.value < down.value) {
                    r2 = down;
                } else r2 = up;

                if (r1.value < r2.value) {
                    r3 = r2;
                } else r3 = r1;

                string = String.format("Direction: %s", r3.name);

                for (HeadGestureListener listener : listeners) {
                    listener.onHeadGestureDetected(r3.name);
                }

                showTitle(string, 3, colorRed);
            }

            //Log.d("Mukcay",pq.poll().name );
            // Log.d("Baz", "Opflow feature count: "+x);
            if (bDisplayTitle)
                showTitle("Optical Flow", 1, colorGreen);
                break;
        }

        // get the time now in every frame
        lMilliNow = System.currentTimeMillis();

        // update the frame counter
        lFrameCount++;

        if (bDisplayTitle) {
            string = String.format("FPS: %2.1f", (float) (lFrameCount * 1000) / (float) (lMilliNow - lMilliStart));
            showTitle(string, 2, colorGreen);
        }

        if (System.currentTimeMillis() - lMilliShotTime < 1500)
            showTitle(sShotText, 3, colorRed);

        return mRgba;
    }
Mukaddes
  • 307
  • 2
  • 12
  • Stuck record here - [*this is how you can nail down*](http://stackoverflow.com/a/378024/23771) where the problem is. Then, hopefully you can see how to fix it. – Mike Dunlavey May 19 '14 at 21:17
  • I am not looking for that kind of optimization. I need a better technique to calculate optic flow direction. Thanks anyway, it was an interesting question. – Mukaddes May 19 '14 at 22:32

1 Answers1

0

you could try this code to check the timings on your problem size:

http://graphics.berkeley.edu/papers/Tao-SAN-2012-05/

(the code link is right at the bottom of the page)

But it really depends on what you mean by fast. For some relative timings of different methods you can check here:

http://www.cvlibs.net/datasets/kitti/eval_stereo_flow.php?benchmark=flow

cheers

QED
  • 808
  • 8
  • 11
  • I cant post another link because of credits. But this looks faster, and works on around abot 15% of pixels [link](http://www.nue.tu-berlin.de/menue/forschung/projekte/rlof/) – QED May 24 '14 at 00:21