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 :
Resultant image after result :
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:
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);
}