AHF*_*AHF 7 opencv image image-processing computer-vision
我想只计算此图像的晕影区域,就像我在这里有图像一样
我如何仅在应用了小插图的区域中计算或迭代/通过并离开其他区域?我只想在应用晕影的区域上应用算法,我试着将标量设置为红色并提取出发现红色的区域,但是它不起作用就像没有给出结果,因为当朝向中心时颜色变浅图像.
的晕影变暗通过用下面的掩码图像强度乘以角落和边缘:

这是原始图像在这里
我想blending overlay在**only vignette part of** vignette image与original image
这是我的混合叠加代码
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);
}
Run Code Online (Sandbox Code Playgroud)
它适用于将晕影图像与原始图像混合,但我只想将晕影图像中的晕影部分与原始图像混合
我得到的结果是这个
你有几个错误.首先,您似乎使用颜色进行混合以在屏幕和多重混合之间进行选择,但您应该使用强度.我认为photoshop可能会在hsv色彩空间中进行混合,但在这种情况下,rgb似乎与你使用L =(r + g + b)/ 3的强度一样长.
此外,您的代码是将图像与晕影和图像的alpha混合混合(您问题中的代码是否与您问题中生成的图像相匹配?).相反,你想要一个"面具",它等于你想要应用晕影的区域中的晕影,并且在你不希望它应用的区域等于0.5.
所以我拍摄你提供的小插图(最左边)有一个alpha通道(左起第2个)并用灰色(右边第二个)进行alpha混合,以获得一个图像用作混合叠加中的顶部图像(最右边) ).如果顶部图像是灰色的,当与另一个图像混合时,底部将显示不变.这是因为在这两行代码中:
_result[j][c] = ((1 - (1 - 2 * (target - 0.5)) * (1 - blend)));
_result[j][c] = 2 * target * blend;
Run Code Online (Sandbox Code Playgroud)
如果blend = 0.5,则可以将结果设置为target.
Vignette Alpha Gray Blend Image (top)
Run Code Online (Sandbox Code Playgroud)

我已经包含了生成的图像,以及下面的代码.所需图像显示在左侧,生成的图像显示在右侧.据我所知,他们是一样的.通过不转换到CV_UC3中间,但通过FC3参数,可以获得准确性的提高blend_overlay().
Required Generated
Run Code Online (Sandbox Code Playgroud)

#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);
}
Run Code Online (Sandbox Code Playgroud)