You have a couple of mistakes. First, you seem to mix color to choose between screen and multiple blends, but you have to use intensity. I think Photoshop can make the mixture in hsv color space, but in this case rgb seems to work as long as you use L = (r + g + b) / 3 for intensity.
Also, your code mixed the image with an alpha mixture of vignette and image (was the code in your question the same as the image generated in your question?). Instead, you want the “mask” to be equal to the vignette in those areas where you want to apply the vignette, and equal to 0.5 in those areas where you do not want it to be applied.
So, I take the vignette that you provided (far left) that has an alpha channel (2 on the left) and make an alpha blend with gray (second on the right) to get the image that will be used as the top image in the blend blend ( in the far right corner). If the top image is gray when mixed with another image, the bottom image will be displayed unchanged. This is 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 turns out that the result is set to target.
Vignette Alpha Gray Blend Image (top)

I included the generated image and code to do this below. The desired image is shown on the 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 by passing FC3 arguments to 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 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); }