How to extract a specific area of ​​an image

I want to read only the vignette region of this image, for example, I have an image here

How can I count or skip or go only in the place where the vignette is applied and leave another area? I just want to apply the algorithm in the area where the vignette is used, I tried it, how to give scalar red color and the selection area where he found the red color, but it doesn’t work, as if it doesn’t give results, because the color becomes lighter when approaching the center Images.

The vignette darkens corners and edges, increasing the intensity of the image using the following mask: enter image description here

This is the original image here.

I want blending overlay **only vignette part of** vignette image with 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 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 to mix the vignette image with the original image, but I only want to mix part of the vignette with the vignette image with the original image

Desired Result

The result I get is this

+7
image image-processing opencv computer-vision
source share
1 answer

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) 

enter image description here

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 

enter image description here

 #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); } 
+8
source share

All Articles