【问题标题】:How to extract specific area of image如何提取图像的特定区域
【发布时间】:2014-06-15 20:25:56
【问题描述】:

我只想计算这张图片的晕影区域,就像我有图片here

如何仅在应用晕影的区域计算或迭代/通过并离开其他区域?我只想将算法应用于应用晕影的区域,我尝试将其设为红色标量并提取它发现红色的区域,但它不起作用,就像不给出结果一样,因为颜色在靠近中心时变得更亮图像。

vignette 通过将图像强度与以下蒙版相乘来使角落和边缘变暗:

这是here的原图

我想blending overlay**only vignette part of** vignette imageoriginal 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);
}

它适用于将晕影图像与原始图像混合,但我只想将晕影图像中的晕影部分与原始图像混合

Required Result

我得到的结果是this

【问题讨论】:

  • 您可以简单地提取您想要的图像部分,对其进行处理,然后将这些像素复制回原始图像吗?另外,请原谅我的无知,但什么是 vignette
  • 我想要应用小插图后的图像部分
  • 申请是什么意思?你真的没有对我说清楚
  • 由于小插图应用于整个图像,所以这个问题没有意义。

标签: image opencv image-processing computer-vision


【解决方案1】:

你有几个错误。 首先,您似乎正在使用颜色在屏幕和多重混合之间进行选择,但您应该使用强度。我认为 Photoshop 可能会在 hsv 颜色空间中进行混合,但在这种情况下,只要您使用 L=(r+g+b)/3 作为强度,rgb 似乎就可以工作。

您的代码还将图像与晕影和图像的 alpha 混合(您问题中的代码是否与您的问题中生成的图像相匹配?)。相反,您需要一个“遮罩”,它等于您想要应用晕影的区域中的晕影,而在您不希望应用晕影的区域等于 0.5。

所以我选择了你提供的小插图(最左边),它有一个 Alpha 通道(左起第二个)和 使用灰色(右二)进行 alpha 混合,以获得用作混合叠加(最右边)中的顶部图像的图像。上面的图像是灰色的,当与其他图像混合时,底部将显示,但不变。之所以如此,是因为在这两行代码中:

_result[j][c] = ((1 - (1 - 2 * (target - 0.5)) * (1 - blend)));
_result[j][c] = 2 * target * blend;

如果 blend = 0.5,则结果设置为目标。

     Vignette              Alpha                 Gray              Blend Image (top)

我已经包含了生成的图像,以及下面的代码。所需图像显示在左侧,生成的图像显示在右侧。据我所知,它们是相同的。 通过在中间不转换为CV_UC3,而是在blend_overlay() 中传递FC3 参数,可以获得准确性的提高。

               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);
}

【讨论】:

  • 实际上图像已经包含小插图,就像我读到的图像是我问题中上面的图像,所以我如何像你写Mat imageMat vignette一样分别阅读它们
  • @AHF 现在我真的不明白你想要达到什么目的。如果您只能访问应用了晕影的图像,而不能访问晕影或原始图像,那么获得解决方案将需要一些假设。您需要 tp 在您的问题中说明您真正想要做什么。 IE。给你提供的图片,你想要什么输出?
  • 我认为给定一个晕影图像,您想重新生成晕影和原始图像?
  • @AHF 如果您链接到这个相关问题,那将会非常有帮助:stackoverflow.com/questions/23220686/… 并且还提到您正在模拟 Photoshop 的 Blendoverlay。另外,我在其他地方看到过混合公式,只是想知道为什么它不是以简化形式编写的?另外,我摆脱了at&lt;&gt;() 像素寻址,因为它非常慢。
  • @AHF alpha 通道在 Vig.png 的第四个通道中提供,小插图是 Vig.png 中的其他三个通道。顶层不等于0.5(即灰色)的任何地方,结果都不会等于底层。您可以尝试其他颜色,但不会得到您指定的结果。
猜你喜欢
  • 2021-09-26
  • 1970-01-01
  • 2015-12-14
  • 2016-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多