1

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

Rocket
  • 553
  • 8
  • 31
  • Are you saying that result is wrong? According to http://en.wikipedia.org/wiki/Blend_modes#Overlay "Overlay combines Multiply and Screen blend modes.[3] The parts of the top layer where base layer is light become lighter, the parts where the base layer is dark become darker." With your code I would expect the blue component to get lighter and red and green to get darker, and that is consistent with your result image. – Bull Aug 27 '14 at 14:31
  • its actually softmode blending , the image I entered as result is the image I need as my result and that's what I am getting with my code of question (after correction) , but your answer code which you suggest as fast working is not giving me the same result with same formula I use in my question , I want above result image from it (below code of your answer) as the same image I get from photoshop after applying softmode – Rocket Aug 27 '14 at 19:58
  • in simple `Resultant image after result :` is the image i require and `Resultant image after result :` is the image now i am getting , but my code is working slow , that why i prefer the code below you suggest but your code which you suggest as alternate is not showing me the result same as `Resultant image after result :` – Rocket Aug 27 '14 at 20:01

1 Answers1

2

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);
}
Community
  • 1
  • 1
Bull
  • 11,771
  • 9
  • 42
  • 53
  • same as above , not showing output , i am using android ndk , jni – Rocket Aug 18 '14 at 18:25
  • the code in my above question is working slow too , i update my question as well – Rocket Aug 18 '14 at 22:36
  • Your code is slow because of the use of `at()` - it is only appropriate for random access and should not be used for sequential scanning. Scan the image using row pointers, like in my answer, and your program will be as fast as is possible. – Bull Aug 18 '14 at 22:51
  • Code calling is working fine , i tested it many times , when call sow like you mention for test it also work , but its not work with formula code (main code) – Rocket Aug 19 '14 at 10:32
  • its something very much same that i also comented on your good answer that `max(img1, img2, out);` work for me and when i just change it into `min(img1, img2, out);` its not showing me result – Rocket Aug 19 '14 at 10:38
  • I added to my answer an explanation of why `min(img1, img2, out)` doesn't work. I also tried to make it clearer what the original problem is – Bull Aug 22 '14 at 00:24
  • My above code in question works for me when I change it from `0` to `255` , but as I said before its too slow , `min` work for me and its fast as well , The code you provided is not showing result in `Part1` which I prefer for fast result – Rocket Aug 23 '14 at 12:18
  • you code shows exception here : `float target = (float) p1[c] / 255.0f; float blend = (float) p2[c] / 255.0f;` Can you please solve it so i can award the bounty – Rocket Aug 24 '14 at 15:18
  • Could you post the text of the exception message? – Bull Aug 24 '14 at 23:25
  • and if i use it with 3 channel to view the result then following exception occur `Unhandled exception at 0x00a5ce43 in Filters.exe: 0xC0000005: Access violation reading location 0x00000000.` – Rocket Aug 25 '14 at 11:54
  • I fixed a bug in the sow code, I was using a Vec4b* to scan result instead of a Vec4f – Bull Aug 26 '14 at 13:40
  • 1
    It shows huge difference in a result , between my code result and your code result , though the formula is same – Rocket Aug 26 '14 at 17:16
  • @Rocket since you didn't provide test images, expect results or the Java & JNI codes, I have no chance of testing this properly. I can only inspect and view the out image. – Bull Aug 27 '14 at 05:37
  • Now that I understand you are trying to do soft blend, I have updated the code accordingly and it generates the result you expect. – Bull Aug 28 '14 at 00:35