美文网首页互联网@时事传播想法
OpenCV系列三 --- 两幅图像的混合、感兴趣区域(ROI)

OpenCV系列三 --- 两幅图像的混合、感兴趣区域(ROI)

作者: 307656af5a04 | 来源:发表于2019-04-15 05:30 被阅读70次

    今天我们来一起学习在OpenCV中如何定义感兴趣区域ROI,如何使用addWeighted函数对两幅图像进行混合,以及将ROI和addWeighted函数结合起来使用,对指定区域进行图像混合操作。

    一、图像的混合

    1、addWeighted函数详解

    功能:计算两幅图像的加权和。

    公式:
    dst = src1 * alpha + src2 * beta + gamma;

    函数原型:

    void addWeighted(InputArray src1, 
    double alpha, InputArray src2, 
    double beta, double gamma, 
    OutputArray dst, int dtype = -1);
    

    (1)第一个参数,src1,表示需要加权的第一个数组,常常填一个Mat类型的图像;

    (2)第二个参数,alpha,表示第一个数组的权重;

    (3)第三个参数,src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数;

    (4)第四个参数,beta,表示第二个数组的权重值;

    (5)第五个参数,dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数;

    (6)第六个参数,gamma,一个加到权重总和上的标量值,看上面的公式就会理解了;

    (7)第七个参数,dtype,输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。

    2、createTrackbar()函数

    功能:它创建一个可以调整数值的轨迹条,并将轨迹条附加到指定的窗口上。

    函数原型:

    int createTrackbar(
        const String& trackbarname, 
        const String& winname,
        int* value, int count,
        TrackbarCallback onChange = 0,
        void* userdata = 0);
    

    (1)第一个参数,const string&类型的trackbarname,表示轨迹条的名字,用来代表我们创建的轨迹条;

    (2)第二个参数,const string&类型的winname,填窗口的名字,表示这个轨迹条会依附到哪个窗口上,即对应namedWindow()创建窗口时填的某一个窗口名;

    (3)第三个参数,int* 类型的value,一个指向整型的指针,表示滑块的位置,并且在创建时,滑块的初始位置就是该变量当前的值;

    (4)第四个参数,int类型的count,表示滑块可以达到的最大位置的值,滑块最小的位置的值始终为0;

    (5)第五个参数,TrackbarCallback类型的onChange,首先注意他有默认值0,这是一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调,并且这个函数的原型必须为void XXXX(int,void*);其中第一个参数是轨迹条的位置,第二个参数是用户数据(看下面的第六个参数)。如果回调是NULL指针,表示没有回调函数的调用,仅第三个参数value有变化;

    (6)第六个参数,void*类型的userdata,它也有默认值0。这个参数是用户传给回调函数的数据,用来处理轨迹条事件,如果使用的第三个参数value实参是全局变量的话,完全可以不去管这个userdata参数。

    3、线性混合操作
    线性混合操作是一种典型的二元(两个输入)的像素操作,它的理论公式是这样的:

    线性混合操作

    我们通过在范围0到1之间改变alpha值,来对两幅图像(f0(x)和f1(x))或两段视频(同样为(f0(x)和f1(x))产生时间上的画面叠化(cross-dissolve)效果,就像幻灯片放映和电影制作中的那样,即在幻灯片翻页时设置的前后页缓慢过渡叠加效果,以及电影情节过渡时经常出现的画面叠加效果。

    实例:

    #include <opencv2/imgcodecs.hpp>
    #include <opencv2/highgui.hpp>
    #include <iostream>
    using namespace cv;
    using std::cout;
    
    const int alpha_slider_max = 100;
    int alpha_slider;
    double alpha;
    double beta;
    Mat src1;
    Mat src2;
    Mat dst;
    
    static void on_trackbar(int, void*)
    {
        alpha = (double)alpha_slider \
            / alpha_slider_max;
        beta = (1.0 - alpha);
        // 对两幅图像进行混合
        addWeighted(src1, alpha, src2, 
            beta, 0.0, dst);
        // 显示图像
        imshow("Linear Blend", dst);
    }
    
    int main(void)
    {
        // 输入两幅图像
        src1 = imread("1.png");
        src2 = imread("3.png");
        if (src1.empty()) 
        { 
            cout << "Error loading src1 \n"; 
            return -1; 
        }
        if (src2.empty()) 
        { 
            cout << "Error loading src2 \n"; 
            return -1; 
        }
        alpha_slider = 0;
        // Create Window
        namedWindow("Linear Blend", 
           WINDOW_AUTOSIZE); 
        char TrackbarName[50];
        // 滑动条的名字
        sprintf_s(TrackbarName,
         "Alpha x %d", alpha_slider_max);
    
        // 创建一个滑动条
        createTrackbar(TrackbarName,
        "Linear Blend", 
            &alpha_slider, alpha_slider_max, 
            on_trackbar);
    
        // 滑动条事件
        on_trackbar(alpha_slider, 0);  
    
        waitKey(0);
        return 0;
    }
    

    运行结果:


    两幅图像的混合

    二、感兴趣的区域(ROI)

    在图像处理领域,我们常常需要设置感兴趣区域(ROI,region of interest),来专注或者简化我们的工作过程 。也就是从图像中选择的一个图像区域,这个区域是我们图像分析所关注的重点。我们圈定这个区域,以便进行进一步处理。而且,使用ROI指定我们想读入的目标,可以减少处理时间,增加精度,给图像处理来带不小的便利。

    定义ROI方法

    1、使用表示矩阵区域的Rect。

    它指定矩阵的左上角坐标(构造函数的前两个参数)和矩阵的长宽(构造函数的后两个参数)以定义一个矩阵区域。

    Mat image = imread("1.png");
    // 定义一个Mat类型并给定其设定的区域
    //Rect四个形参分别是:x坐标,y坐标,长,高;
    //注意(x,y)指的是矩形的左上角点
    Mat imageROI = image(Rect(100, 200, 
    100, 300));
    
    2、指定感兴趣行或列的范围(Range)

    Range是指从起始索引到终止索引(不包括终止索引)的一连段连续序列。cv::Range可以用来定义Range。

    Mat image = imread("src.png");
    Mat blend_roi = imread("blend_roi.png");
    Mat imageROI = image(Range(250, 
    250 + blend_roi.rows), Range(200, 
    200 + blend_roi.cols));
    
    3、图像掩膜

    在有些图像处理的函数中有的参数里面会有mask参数,即此函数支持掩膜操作,首先何为掩膜以及有什么用。

    数字图像处理中的掩膜的概念是借鉴于PCB制版的过程,在半导体制造中,许多芯片工艺步骤采用光刻技术,用于这些步骤的图形“底片”称为掩膜(也称作“掩模”),其作用是:在硅片上选定的区域中对一个不透明的图形模板遮盖,继而下面的腐蚀或扩散将只影响选定的区域以外的区域。

    图像掩膜与其类似,用选定的图像、图形或物体,对处理的图像(全部或局部)进行遮挡,来控制图像处理的区域或处理过程。

    数字图像处理中,掩模为二维矩阵数组,有时也用多值图像,图像掩模主要用于:

    • 提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。

    • 屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。

    • 结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。

    • 特殊形状图像的制作。

    在所有图像基本运算的操作函数中,凡是带有掩膜(mask)的处理函数,其掩膜都参与运算(输入图像运算完之后再与掩膜图像或矩阵运算)。

    实例:

    #include <opencv2/imgcodecs.hpp>
    #include <opencv2/highgui.hpp>
    #include <iostream>
    using namespace cv;
    
    int main(void)
    {
        //【1】读入图像
        Mat srcImage1 = imread("1.png");
        Mat logoImage = imread("2.png");
        if (!srcImage1.data) 
        { 
            printf("image error! \n"); 
            return false; 
        }
        if (!logoImage.data) 
        { 
            printf("image error! \n"); 
            return false; 
        }
    
        //【2】定义一个Mat类型并给其设定ROI区域
        Mat imageROI = srcImage1(Rect(50, 50, 
            logoImage.cols, logoImage.rows));
    
        //【3】加载掩模(必须是灰度图)
        Mat mask = imread("dota_logo.jpg", 0);
    
        //【4】将掩膜拷贝到ROI
        logoImage.copyTo(imageROI, mask);
    
        //【5】显示结果
        namedWindow("Display");
        imshow("Display", srcImage1);
    
        waitKey(0);
        return 0;
    }
    

    运行结果:

    设置ROI区域

    三、对指定区域进行图像混合操作

    实例:

    #include <opencv2/imgcodecs.hpp>
    #include <opencv2/highgui.hpp>
    #include <iostream>
    using namespace cv;
    
    int main(void)
    {
        //【0】定义一些局部变量
        double alphaValue = 0.5;
        double betaValue;
        Mat image, blend_roi;
    
        //【1】读取图像 ( 两幅图片
        // 需为同样的类型和尺寸 )
        image = imread("1.png");
        blend_roi = imread("2.png");
    
        if (!image.data)
        {
            printf("image error! \n"); 
            return false; 
        }
        if (!blend_roi.data)
        { 
           printf("image error! \n");
           return false;
        }
        
        //【2】定义一个Mat类型并给其设定ROI区域
        Mat imageROI;
        //方法一
        imageROI = image(Rect(50, 50, 
        blend_roi.cols, blend_roi.rows));
        //【2】做图像混合加权操作
        betaValue = (1.0 - alphaValue);
        addWeighted(imageROI, alphaValue, 
        blend_roi, betaValue, 0.0, imageROI);
    
        //【3】创建并显示原图窗口
        namedWindow("效果图", 1);
        imshow("效果图", image);
    
        waitKey(0);
        return 0;
    }
    

    运行结果:

    对指定区域进行图像混合操作

    好了,今天的OpenCV就学习到这里了,喜欢的话,可以给我点个赞哦!!!

    相关文章

      网友评论

        本文标题:OpenCV系列三 --- 两幅图像的混合、感兴趣区域(ROI)

        本文链接:https://www.haomeiwen.com/subject/qdhewqtx.html