【问题标题】:How to proceed the masked image如何处理蒙版图像
【发布时间】:2014-05-14 22:13:24
【问题描述】:

我正在尝试在图像上绘制椭圆,然后掩盖我所做的区域,如下图所示

每个人都知道lena 的原始图像,所以我不上传它:),我有 lena 的img A 和我上传的面具图像是img Mask,现在我想在图像上执行功能填充区域以外的区域中的蒙版,我如何更改蒙版/填充图像以外区域的颜色,然后我想将 lena 的图像(仅填充椭圆下的区域)放入处理后的图像蒙版(我更改了填充颜色以外的颜色),然后将我屏蔽的 lena 图像放入图像蒙版中,如何执行该任务,opencv 中是否有任何功能可以做到这一点

这个圆形图片变成了继续蒙版图片

我真正想要实现的是

我做的代码是:

void main ()
{
Mat img = imread ("E:\\lena.jpg");
Mat mask = img.clone();
ellipse(mask,Point(img.cols/2,img.rows/2),Size(img.cols/2,img.rows/2),0,0,360,Scalar(255,255,255), CV_FILLED, 8,0);
Mat mask2;
inRange(mask, Scalar(255,255,255), Scalar(255,255,255), mask2);
mask.setTo(Scalar(255,0,0), mask2);
}

编辑 结果.jpg

编辑以获得额外帮助:

【问题讨论】:

    标签: c++ image opencv image-processing computer-vision


    【解决方案1】:

    试试这个:

    int main()
    {
    cv::Mat img = imread ("E:\\lena.jpg");
    cv::Mat mask = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
    cv::ellipse(mask,cv::Point(mask.cols/2,mask.rows/2),cv::Size(mask.cols/2,mask.rows/2),0,0,360,cv::Scalar(255), CV_FILLED, 8,0);
    
    cv::imshow("mask", mask);
    
    cv::Mat result = cv::Mat(img.rows, img.cols, CV_8UC1, img.type());
    result.setTo(cv::Scalar(0,0,0));
    
    img.copyTo(result, mask);
    cv::imshow("result", result);
    cv::waitKey(-1);
    return 0;
    }
    

    输入:

    计算掩码:

    结果:

    idea:创建一个黑色图像并仅将蒙版区域复制到它。 这是img.copyTo(result, mask); 行。 openCV 掩码是与图像大小相同的 1 通道 CV_8U 图像。

    如果您一般只想在遮罩区域中操作像素,您可以这样做:

    loop over y and x coordinate of the image
        if(mask.at<unsigned char>(cv::Point(x,y)) != 0)
            manipulate the pixel in img
        else
            do not manipulate the pixel
    

    这是另一个例子,你可以看到不同的东西: 1.如果有前景蒙版,如何创建背景蒙版 2.如何只循环前景/背景并在这些像素上执行一些任务 3. 如何从图像中复制,使用蒙版

    int main()
    {
    // load image:
    cv::Mat img = cv::imread ("lena.jpg");
    
    // create the foreground mask in form of an ellipse:
    cv::Mat foregroundMask = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
    cv::ellipse(foregroundMask,cv::Point(foregroundMask.cols/2,foregroundMask.rows/2),cv::Size(foregroundMask.cols/2,foregroundMask.rows/2),0,0,360,cv::Scalar(255), CV_FILLED, 8,0);
    
    cv::Mat foreground = img.clone();
    
    // create the background mask which is just everything that is not foreground
    cv::imshow("mask", foregroundMask);
    cv::Mat backgroundMask = 255-foregroundMask;
    
    // create a background and give it some color. this could be another loaded image instead.
    cv::Mat background = cv::Mat(img.rows, img.cols, img.type());
    // give the background some color. here white for example.
    background.setTo(cv::Scalar(255,255,255));
    
    // do some computation on the background image, but only where the background mask is not zero!
    for(int y=0; y<backgroundMask.rows; ++y)
        for(int x=0; x<backgroundMask.cols; ++x)
        {
            cv::Point pixelPos(x,y);
            if(backgroundMask.at<unsigned char>(pixelPos))
            {
                // manipulate the background
                // I choose to set every 8th pixel in a random color, you could do any filter or something:
                if(x%8 == 0)
                {
                    // create random color
                    cv::Vec3b randomColor(rand()%255, rand()%255, rand()%255);
                    // use .at<Vec3b> for 24 bit BGR values
                    background.at<cv::Vec3b>(pixelPos) = randomColor;
                }
            }
            else
            {
                // you could process any pixel here which is NOT in your background mask, but I'll process foreground explicitly later
            }
        }
    
    
    // just in case that you want to modify the foreground too, here's an example:
    for(int y=0; y<foregroundMask.rows; ++y)
            for(int x=0; x<foregroundMask.cols; ++x)
            {
                cv::Point pixelPos(x,y);
                if(foregroundMask.at<unsigned char>(pixelPos))
                {
                    // manipulate the background
                    // for example, set every 12th row to blue color:
                    if(y%12 == 0)
                    {
                        // create random color
                        cv::Vec3b blueColor(255, 0, 0);
                        // use .at<Vec3b> for 24 bit BGR values
                        foreground.at<cv::Vec3b>(pixelPos) = blueColor;
                    }
                }
                else
                {
                    // you could process any pixel here which is NOT in your foreground mask, but I've processed background explicitly earlier
                }
            }
    
    
    cv::imshow("modified background", background);
    cv::imshow("modified foreground", foreground);
    
    // this is how to copy something using masks:
    
    cv::Mat result;
    // copy background masked pixel from background image to the result:
    background.copyTo(result, backgroundMask);
    // copy foreground masked pixel from foreground image to the result:
    foreground.copyTo(result, foregroundMask);
    
    
    cv::imshow("result", result);
    cv::waitKey(-1);
    return 0;
    }
    

    图片是这样的:

    像以前一样输入:

    前景蒙版:它只是我们绘制的椭圆:

    背景掩码:这就是所有不是前景的东西:

    在我的示例中,原始背景图像只是一张白色图像。 这是修改后的背景图片,其中一些被蒙版的背景图片被修改了,所有不在背景蒙版中的东西都没有被修改(见代码):

    现在是修改后的前景图像,看到没有被掩蔽为前景的像素没有被修改

    最后在使用 .copyTo() 和使用掩码之后:

    您可以很容易地看到,您甚至不必复制两个图像,如果您将一个图像复制到另一个图像中并且可以进行许多其他简单的简化,那么该代码只是为了演示如何以多种不同方式使用掩码。

    希望对你有所帮助,理解代码后你可以做任何你想做的事=)

    【讨论】:

    • 如果我不想计算 maska 背景不是黑色,我只希望它是原始背景!只是填充的椭圆
    • 然后按照图像后面的说明进行操作,循环遮罩并仅在设置遮罩的原始图像像素中操作(设置颜色)。或者(可能更有效):cv::Mat mask2 = 255-mask; background.copyTo(img, mask2) 然后您只将背景复制到图像。
    • 或:img.copyTo(backgroundImage, mask);
    • 可能你没有注意到我在问题中的第一张图片,它的填充区域是蓝色的,但背景是这样的,现在我想在它原来的背景上应用进一步的过滤算法,在应用之后对其进行过滤,我将修复该图像中的蒙版图像,希望您现在明白我的意思
    • 好的,你想在你的蒙版不是蓝色的地方编辑图像(例如使用一些过滤器)并且图像的其余部分(你的蒙版是蓝色的)不应该改变?我仍然不确定您的结果应该是什么样子。
    猜你喜欢
    • 2017-12-11
    • 1970-01-01
    • 1970-01-01
    • 2013-10-23
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 2017-12-08
    相关资源
    最近更新 更多