Home » Android » Improve performance of openCV on Android with native camera in high resolution

Improve performance of openCV on Android with native camera in high resolution

Posted by: admin October 28, 2017 Leave a comment


I’m developing an Android app where I use cameraCaptureSession for grab the camera frames for send to native routine where I will use openCV for license plates recognition.
I need to work with full resolution (5312×2988) because I have to detect far object, but it’s too slow, so I had to resize it for detect a bigger area (a car), and on this area I will detect the license plates in high resolution. With this solution It’s little better, but not enought.
I think that problem is when I write the matrix on the surface, but i don’t know how can do differently.
Here is my code:

JNIEXPORT void JNICALL Java_com_studio_myproject_activity_JNIUtils_nativeDetectPlateNumber
        (JNIEnv * jenv, jobject obj, jint srcWidth, jint srcHeight, jobject srcBuffer, jobject dstSurface, jfloat focalLenght, jfloat sensorHeight)

if(classifierCar.empty() || classifierPlate.empty()) {
    LOGD("Nessun classifier è stato caricato");

uint8_t *srcLumaPtr = reinterpret_cast<uint8_t *>(jenv->GetDirectBufferAddress(srcBuffer));

int dstWidth;
int dstHeight;

cv::Mat mYuv(srcHeight + srcHeight / 2, srcWidth, CV_8UC1, srcLumaPtr);

ANativeWindow *win = ANativeWindow_fromSurface(jenv, dstSurface);

ANativeWindow_Buffer buf;

dstWidth = srcWidth;
dstHeight = srcHeight;

ANativeWindow_setBuffersGeometry(win, dstWidth, dstHeight, 0 /*format unchanged*/);

if (int32_t err = ANativeWindow_lock(win, &buf, NULL)) {
    LOGD("ANativeWindow_lock failed with error code %d\n", err);

uint8_t *dstLumaPtr = reinterpret_cast<uint8_t *>(buf.bits);
Mat dstRgba(dstHeight, buf.stride, CV_8UC4,
            dstLumaPtr);        // TextureView buffer, use stride as width
Mat srcRgba(srcHeight, srcWidth, CV_8UC4);
Mat mGray(dstHeight, dstWidth, CV_8UC4);

// convert YUV -> RGBA
cv::cvtColor(mYuv, srcRgba, CV_YUV2RGBA_NV21);

cv::cvtColor(srcRgba, mGray, COLOR_RGBA2GRAY);

//diminuisco la dimensione dell'immagine
cv::Mat mResized;

cv::resize(mGray, mResized, cvSize(0,0), 0.12, 0.12);

vector<Rect> cars;
classifierCar.detectMultiScale(mResized, cars, 1.1, 3, 2, Size(20, 20), Size(640, 640));

vector<Rect> plates;
cv::Mat croppedImage;

for (int i=0; i< cars.size(); i++){
    int newLeftCar = srcWidth*cars[i].tl().x/(mResized.cols);
    int newTopCar = srcHeight*cars[i].tl().y/(mResized.rows);
    int newRightCar = srcWidth*cars[i].br().x/(mResized.cols);
    int newBottomCar = srcHeight*cars[i].br().y/(mResized.rows);
    Point newTlCar = Point(newLeftCar, newTopCar);
    Point newBrCar = Point(newRightCar, newBottomCar);
    rectangle(srcRgba,newTlCar, newBrCar, Scalar(0, 255, 0, 255),3);

    croppedImage = srcRgba(Rect(newLeftCar, newTopCar, abs(newRightCar-newLeftCar), abs(newBottomCar-newTopCar)));

    classifierPlate.detectMultiScale(croppedImage, plates, 1.1, 3, 2, Size(100, 50), Size(640, 360));

    for(int j=0; j< plates.size(); j++){
        int newLeftPlate = plates[j].tl().x + newLeftCar;
        int newTopPlate = plates[j].tl().y + newTopCar;
        int newRightPlate = plates[j].br().x + newLeftCar;
        int newBottomPlate = plates[j].br().y + newTopCar;
        Point newTlPlate = Point(newLeftPlate, newTopPlate);
        Point newBrPlate = Point(newRightPlate, newBottomPlate);
        rectangle(srcRgba, newTlPlate, newBrPlate, Scalar (255, 0, 0, 255 ), 3);


// copy to TextureView surface
uchar *dbuf;
uchar *sbuf;
dbuf = dstRgba.data;
sbuf = srcRgba.data;
int i;
for (i = 0; i < srcRgba.rows; i++) {
    dbuf = dstRgba.data + i * buf.stride * 4;
    memcpy(dbuf, sbuf, srcRgba.cols * 4);
    sbuf += srcRgba.cols * 4;