I want to count only the vignette area of this image , like i have the image here
How I can count or iterate/pass through only in the area where vignette is applied and leave the other area ? I only want to apply the algorithm on the area where vignette is applied , I tried it like give scalar to red color and extract area where it found the red color but its not working like not giving the results because color become lighter when coming towards centre of the image.
The vignette darkens the corners and edges by multiplying the image intensity with the following mask:
This is the original image here
I want to blending overlay
the **only vignette part of** vignette image
with the original image
Here is my code for blending overlay
void blending_overlay(Mat& img1 , Mat& img2 , Mat& out)
{
Mat result(img1.size(), CV_32FC3);
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++){
float target = (float)img1.at<uchar>(i, 3*j+c)/255. ;
float blend = (float)img2.at<uchar>(i, 3*j+c)/255. ;
if(target > 0.5){
result.at<float>(i, 3*j+c) = ((1 - (1-2*(target-0.5)) * (1-blend)));
}
else{
result.at<float>(i, 3*j+c) = ((2*target) * blend);
}
}
}
}
result.convertTo(out,CV_8UC3,255);
}
int main( int argc, char** argv )
{
Mat Img1=imread("D:\\Vig.png",-1); // the vignete in the question
Mat Img2=imread("D:\\i.png"); // the iamge in the question
cv::resize(Img1,Img1,Img2.size());
Img1.convertTo(Img1,CV_32FC4,1.0/255.0);
Img2.convertTo(Img2,CV_32FC3,1.0/255.0);
vector<Mat> ch;
split(Img1,ch);
Mat mask = ch[3].clone(); // here's the vignette
ch.resize(3);
Mat I1,I2,result;
cv::multiply(mask,ch[0],ch[0]);
cv::multiply(mask,ch[1],ch[1]);
cv::multiply(mask,ch[2],ch[2]);
merge(ch,I1);
vector<Mat> ch2(3);
split(Img2, ch2);
cv::multiply(1.0-mask,ch2[0],ch2[0]);
cv::multiply(1.0-mask,ch2[1],ch2[1]);
cv::multiply(1.0-mask,ch2[2],ch2[2]);
merge(ch2,I2);
I1.convertTo(I1,CV_8UC3,255);
I2.convertTo(I2,CV_8UC3,255);
result=I1+I2; // The image with the vignette in the question
result.convertTo(result,CV_8UC4,255);
Mat result2;
Mat mask2;
Mat image = imread ("D:\\i.png"); // image in the question
blending_overlay(image,result,result2,mask2);
imshow("Image",result2);
waitKey(0);
}
It works for blending vignette image with the original image but I only want to blend the vignette part from vignette image with the original image
Required Result
The result i am getting is this
We first create a binary mask from a specified ROI, which returns a matrix containing only 1 or 0. To return the selected portion of the image, we perform a logical AND of the binary mask matrix with the image using logical indexing. The resulting image will contain the extracted portion.
You have a couple of mistakes. Firstly you seem to be blending using the color to choose between the screen and multiply blends, but you should use the intensity. I think photoshop might do the blend in hsv colorspace, but in this case rgb seems to work as longs as you use L=(r+g+b)/3 for the intensity.
Also your code was blending the image with and alpha blend of the vignette and the image (did the code in you question match the image generated in your question?). Instead you want a "mask" that equals the vignette in the areas where you want the vignette applied, and equals 0.5 in areas where you don't want it applied.
So I take the vignette you provided (far left) which has an alpha channel (2nd from left) and do an alpha blend with gray (second from right) to get an image to use as the top image in a blend overlay (far right). Where the top image is gray, when is blended with the other image, the bottom will show though unchanged. This is so because in these two lines of code:
_result[j][c] = ((1 - (1 - 2 * (target - 0.5)) * (1 - blend)));
_result[j][c] = 2 * target * blend;
if blend = 0.5, it works out that result is set to target.
Vignette Alpha Gray Blend Image (top)
I have included the image generated, and the code to do it below. The required image is shown on left, and the generated image is shown on the right. As far as I can see they are the same.
An improvement in accuracy could be obtained by not converting to CV_UC3
in the middle, but passing FC3
arguments in blend_overlay()
.
Required Generated
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream> // std::cout
#include <vector> // std::vector
using namespace std;
using namespace cv;
void blending_overlay2(Mat& bot, Mat& top, Mat& out)
{
Mat result(bot.size(), CV_32FC3);
// Extract the calculate I = (r + g + b) / 3
Mat botf;
bot.convertTo(botf, CV_32FC3, 1.0 / 255.0);
std::vector<cv::Mat> planes(3);
cv::split(botf, planes);
cv::Mat intensity_f((planes[0] + planes[1] + planes[2]) / 3.0f);
cv::Mat L;
intensity_f.convertTo(L, CV_8UC1, 255.0);
//cv::imshow("L", L);
for(int i = 0; i < bot.size().height; ++i)
{
// get pointers to each row
cv::Vec3b* _bot = bot.ptr<cv::Vec3b>(i);
cv::Vec3b* _top = top.ptr<cv::Vec3b>(i);
cv::Vec3f* _result = result.ptr<cv::Vec3f>(i);
uchar* _L = L.ptr<uchar>(i);
// now scan the row
for(int j = 0; j < bot.size().width; ++j)
{
for (int c=0; c < bot.channels(); c++)
{
float target = float(_bot[j][c]) / 255.0f;
float blend = float(_top[j][c]) / 255.0f;
if(_L [j] > 128)
{
_result[j][c] = 2 * (blend + target - target * blend) - 1;
// Why isn't the below line simplified like above?
//_result[j][c] = ((1 - (1 - 2 * (target - 0.5)) * (1 - blend)));
}
else
{
_result[j][c] = 2 * target * blend;
}
}
}
}
result.convertTo(out, CV_8UC3, 255);
}
int main( int argc, char** argv )
{
Mat Img1=cv::imread("kqw0D.png",-1); // the vignete in the question
Mat Img2=cv::imread("i.png"); // the iamge in the question
Mat image = Img2.clone();
cv::resize(Img1,Img1,Img2.size());
Img1.convertTo(Img1,CV_32FC4,1.0/255.0);
Img2.convertTo(Img2,CV_32FC3,1.0/255.0);
// split off the alpha channel from the vignette
vector<Mat> ch;
split(Img1,ch);
Mat alpha = ch[3].clone(); // here's the vignette
Mat alpha_u;
alpha.convertTo(alpha_u,CV_8UC1,255);
imshow("alpha",alpha);
// drop the alpha channel from vignette
ch.resize(3);
// pre-mutiply each color channel by the alpha
// and merge premultiplied color channels into 3 channel vignette I1
Mat I1;
cv::multiply(alpha, ch[0], ch[0]);
cv::multiply(alpha, ch[1], ch[1]);
cv::multiply(alpha, ch[2], ch[2]);
merge(ch, I1);
// Now make the vignette = 0.5 in areas where it should not be "applied"
Mat I2;
vector<Mat> ch2;
cv::Mat half = cv::Mat::ones(Img2.rows, Img2.cols, CV_32FC1) * 0.5;
cv::multiply(1.0f - alpha, half, half);
ch2.push_back(half);
ch2.push_back(half);
ch2.push_back(half);
//split(Img2, ch2);
//cv::multiply(1.0f - alpha, ch2[0], ch2[0]);
//cv::multiply(1.0f - alpha, ch2[1], ch2[1]);
//cv::multiply(1.0f - alpha, ch2[2], ch2[2]);
merge(ch2, I2);
// result = alpha * vignette + (1 - alpha) * gray;
Mat top;
top=I1+I2;
// make I1 8 bit images again
I1.convertTo(I1,CV_8UC3,255);
I2.convertTo(I2,CV_8UC3,255);
top.convertTo(top,CV_8UC3,255);
//imshow("I1",I1);
//imshow("I2",I2);
//imshow("top",top);
Mat result2;
blending_overlay2(image,top, result2);
imshow("Voila!", result2);
imwrite("voila.png", result2);
waitKey(0);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With