图像处理美图摄影诗与诗

「OpenCV图像处理」两幅图像的混合、感兴趣区域(ROI)

2019-05-29  本文已影响27人  CPlusPlus图像处理

今天我们来一起学习在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制版的过程,在半导体制造中,许多芯片工艺步骤采用光刻技术,用于这些步骤的图形“底片”称为掩膜(也称作“掩模”),其作用是:在硅片上选定的区域中对一个不透明的图形模板遮盖,继而下面的腐蚀或扩散将只影响选定的区域以外的区域。

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

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

在所有图像基本运算的操作函数中,凡是带有掩膜(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就学习到这里了,喜欢的话,可以给我点个赞哦!!!

上一篇下一篇

猜你喜欢

热点阅读