Search code examples
opencvimage-processingandroid-ndkjava-native-interfacecomputer-vision

image shows result in VS2010 but not showing output in Android using OpenCV


My code works in Visual Studio using OpenCV. But its not showing output in an Android NDK application, and its not showing an error

Below is my code.

void sow(Mat& img1, Mat& img2, Mat& out)
{
    Mat result(img1.size(), CV_32FC4);                           

    img2 = Mat(img1.size(), img1.type(), Scalar(186, 44, 28, 0));

    for (int i = 0; i < img1.size().height; ++i){
        for (int j = 0; j < img1.size().width; ++j){

            for (int c = 0; c<img1.channels(); c++){                // Iterate through colors

                //Formula 
                float target = (float)img1.at<uchar>(i, 4 * j + c) / 255.;
                float blend = (float)img2.at<uchar>(i, 4 * j + c) / 255.;
                if (blend > 0.5){
                    result.at<float>(i, 4 * j + c) = ((1 - (1 - target) * (1 - 2 * (blend - 0.5))));
                }
                else{
                    result.at<float>(i, 4 * j + c) = (target * (2 * blend));
                }
            }
        }
    }
    result.convertTo(out, CV_8UC4, 255);

}

It works for me in Visual Studio with an 8UC3 image, but not with an 8UC4 image in Android. Other than n output in imageview, there is no error.

The same thing works for me in Android when I change the formula, but this formula works for me on Visual Studio . Some images work for me when I have the same code but different formula's in

if (blend > 0.5)
{
    result.at<float>(i, 4 * j + c) = ((1 - (1 - target) * (1 - 2 * (blend - 0.5))));
}
else
{
    result.at<float>(i, 4 * j + c) = (target * (2 * blend));
}

And they are showing output.

In the same way when I use :

void BL(Mat& img1, Mat& img2, Mat& out)
{
    img2 = Mat(img1.size(), img1.type(), Scalar(186, 44, 28, 0));
    max(img1, img2, out);
}

it shows output but when I use max(img1, img2, out); in the same code its not showing output. And they all are working in Visual Studio but not in Android using NDK. I tested my JNI and it is work correctly, the Java code is correct too.

input image : enter image description here

Resultant image after result :

enter image description here


Solution

  • Part 1

    I think your problem is setting alpha to 0 (transparent) in this line:

    img2 = Mat(img1.size(), img1.type(), Scalar(186, 44, 28, 0));
    

    Change it to

    img2 = Mat(img1.size(), img1.type(), Scalar(186, 44, 28, 255));
    

    Since the only difference is the alpha channel, that is the first place to look. If either img1 or img2 has 0 alpha your result will be completely transparent! The suggested way to handle this, according to this question, is result.alpha = 1 - (1 - target.alpha) * (1 - blend.alpha)

    Try this:

     void sow(Mat& img1, Mat& img2, Mat& out)
    {
        Mat result(img1.size(), CV_32FC4);                           
    
        img2 = Mat(img1.size(), img1.type(), Scalar(186, 44, 28, 255));
    
        for (int i = 0; i < img1.rows; ++i)
        {
            Vec4b* i1 = img1.ptr<Vec4b>(i);
            Vec4b* i2 = img2.ptr<Vec4b>(i);
            Vec4f* r  = result.ptr<Vec4f>(i);
    
            for (int j = 0; j < img1.cols; ++j)
            {
                Vec4b p1 = i1[j];
                Vec4b p2 = i2[j];
                Vec4f& pr = r[j];
    
                // Blend overlay color channels
                for (int c = 0; c < 3; ++c)
                { 
                    //Formula 
                    float target = (float) p1[c] / 255.0f;
                    float blend = (float) p2[c] / 255.0f;
                    if (blend > 0.5)
                    {
                        pr[c] = 1 - (1 - target) * (1 - 2 * (blend - 0.5f));
                    }
                    else
                    {
                        pr[c] = target * 2 * blend;
                    }
                }
                // Alpha channel
                float target_alpha  = (float) p1[3] / 255.0f;
                float blend_alpha = (float) p2[3] / 255.0f;
                pr[3] = 1 - (1 - target_alpha) * (1 - blend_alpha);
            }
        }
        result.convertTo(out, CV_8UC4, 255);
    }
    

    With your input image this generates your desired result:

    enter image description here


    Also, the problem might be with your JNI code, check that the code calling sow() works correctly, just return img1 & img2:

    void sow(Mat& img1, Mat& img2, Mat& out)
    {
        img1.copyTo(out);
    }
    

    BTW, except for img2 the call by reference on those Mats is superfluous. E.g.

    void sow(Mat img1, Mat& img2, Mat out)
    {
        img2 = Mat(img1.size(), img1.type(), Scalar(186, 44, 28, 255));
        img2.copyTo(out);
    }
    

    Part 2 The reason that

    void BL(Mat& img1, Mat& img2, Mat& out)
    {
        img2 = Mat(img1.size(), img1.type(), Scalar(186, 44, 28, 0));
        min(img1, img2, out);
    }
    

    doesn't display anything is that the alpha channel in out is always set to 0 (completely transparent). Change the alpha to 255 in img2 and it should work:

    void BL(Mat& img1, Mat& img2, Mat& out)
    {
        img2 = Mat(img1.size(), img1.type(), Scalar(186, 44, 28, 255));
        min(img1, img2, out);
    }