Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Android+CV4.3.0: Why did NDK run 50% slower to detect the faces??

Kotlin: 17fps

fun drawFaceRectangle() {
    faceRects = MatOfRect()

    // image width & height
    val scrW = grayMat.width().toDouble()
    val scrH = grayMat.height().toDouble()

    val scale = getRatio(Size(scrW, scrH), 480) + 1
    val neighbor = 3

    rotateImage()

    faceDetector!!.detectMultiScale(
        grayMat, // image
        faceRects, // array
        scale, // scale
        neighbor, // min neighbors
        0, // flags,
        Size(30.0, 30.0), // min size
        Size(scrW, scrH) // max size
    )

    for (rect in faceRects!!.toArray()) {
        val x = rect.x.toDouble()
        val y = rect.y.toDouble()
        val rw = rect.width.toDouble() // rectangle width
        val rh = rect.height.toDouble() // rectangle height

        val w = x + rw
        val h = y + rh

        when (screenRotation) {
            0-> {
                rectFace(y, x, h, w, RED)
                drawDot(y, x, GREEN)
            }
            90-> {
                rectFace(x, y, w, h, RED)
                drawDot(x, y, GREEN)
            }
            180-> {
                // fix height
                val yFix = scrW - y
                val hFix = yFix - rh

                rectFace(yFix, x, hFix, w, YELLOW)
                drawDot(yFix, x, BLUE)
            }
            270-> {
                // fix height
                val yFix = scrH - y
                val hFix = yFix - rh

                rectFace(x, yFix, w, hFix, YELLOW)
                drawDot(x, yFix, BLUE)
            }
        }
    }
}

ndk: 9fps

void drawFaceRectangle(
    Mat &rgba,
    Mat &gray,
    String path,
    double ratio,
    int rotation) {
// width and height of frame
float scrW = (float)rgba.size().width;
float scrH = (float)rgba.size().height;

vector<cv::Rect> faces;
double scale = 1.0+ratio;
int neighbor = 3;

// fix orientation so it can be detected
rotateGray(gray, rotation);

/*
 * void detectMultiScale (
 * InputArray image,
 * std::vector< Rect > &objects,
 * double scaleFactor=1.1,
 * int minNeighbors=3,
 * int flags=0,
 * Size minSize=Size(),
 * Size maxSize=Size())
Detects objects of different sizes in the input image.
 The detected objects are returned as a list of rectangles.
 */
faceDetector.detectMultiScale(
        gray, // image
        faces, // array
        scale, // scale
        neighbor, // min neighbors
        0, // flags,
        Size(30, 30), // min size
        Size((int)scrW, (int)scrH) // max size
);

for (int i=0; i<faces.size(); i++) {
    Rect rect = faces[i];

    float x = (float)rect.x;
    float y = (float)rect.y;        
    float rw = (float)rect.width;
    float rh = (float)rect.height;

    float w = x + rw;
    float h = y + rh;
    float yFix, hFix;

    // draw rectangle
    switch (rotation) {
        case 0:
            rectFace(rgba, y, x, h, w, RED);
            drawDot(rgba, y, x, GREEN);
            break;

        case 90:
            rectFace(rgba, x, y, w, h, RED);
            drawDot(rgba, x, y, GREEN);
            break;

        case 180:
            // fix height
            yFix = scrW - y;
            hFix = yFix - rh;
            rectFace(rgba, yFix, x, hFix, w, YELLOW);
            drawDot(rgba, yFix, x, BLUE);
            break;

        case 270:
            // fix height
            yFix = scrH - y;
            hFix = yFix - rh;
            rectFace(rgba, x, yFix, w, hFix, YELLOW);
            drawDot(rgba, x, yFix, BLUE);
            break;

        default:
            string msg = "Error: wrong rotation data -- " +
                         to_string(rotation);
            lge(msg.c_str());
            break;
    }
}

}

You see, they are same function. The timing are much different.

    override fun onCameraFrame(inputFrame: CvCameraViewFrame?): Mat {
    if (pCounter == 1000) {
        evalPerfomance()
        finish()
    }
    // start time
    frameStart = System.currentTimeMillis()

    imageMat = inputFrame!!.rgba()

    if (!javaEnabled) {
        // C++
        /*
        if (!OpenCvNativeCall().convertGray(
                imageMat.nativeObjAddr,
                grayMat.nativeObjAddr
            )
        ) {
            throw CvException("Data is corrupted!")
        }
        */

        if (!OpenCvNativeCall().faceDetection(
                imageMat.nativeObjAddr,
                480,
                screenRotation,
                faceModel!!.absolutePath)) {
            longMsg(this, "Failed to load Face Detector!!!")
        }
    } else {
        grayMat = inputFrame!!.gray()

        // detect face rectangle
        drawFaceRectangle()
    }

    postText("$pCounter", 100.0, 100.0, YELLOW)

    // end time
    frameEnd = System.currentTimeMillis()
    frameRecord[pCounter] = frameEnd - frameStart
    pCounter++

    return imageMat
}


    fun evalPerfomance() {
    val avg = frameRecord.average()
    lgd("Java Enable? $javaEnabled ... Runtime average = $avg ms")
}

The logcat came back with NDK is much slower.

7204-7204 D/MYLOG MainActivity: OpenCV started...
7204-7204 I/MYLOG MainActivity: OpenCV Loaded Successfully!
7204-7204 D/MYLOG MainActivity: OpenCV started...
7204-7204 D/MYLOG MainActivity: CameraView turned ON...
7204-7204 D/MYLOG MainActivity:  System Ui Visibility Change
7204-7239 D/MYLOG MainActivity: Java Enable? true ... Runtime average = 39.043 ms
7510-7510 D/MYLOG MainActivity: OpenCV started...
7510-7510 I/MYLOG MainActivity: OpenCV Loaded Successfully!
7510-7510 D/MYLOG MainActivity: OpenCV started...
7510-7510 D/MYLOG MainActivity: CameraView turned ON...
7510-7510 D/MYLOG MainActivity:  System Ui Visibility Change
7510-7547 D/MYLOG MainActivity: Java Enable? false ... Runtime average = 88.269 ms

How can I make the C++ code faster? (OpenCV library 4.3.0)