zoukankan      html  css  js  c++  java
  • 图像叠加和混合(OpenCV4)

      本篇随笔主要介绍:如何使用OpenCV定义感兴趣区域ROI;如何使用addWeighted函数进行退选哪个混合操作;如何将ROIaddWeighted函数结合来使用,对指定区域图像混合操作。

    Region of interest

      定义ROI有两种方法:一是使用矩形区域(Rect),它指定了矩形的左上角坐标(构造函数前两个参数)和矩形的长宽(构造函数的后两个参数)。C/C++描述如下:

    // 定义一个Mat类型并给其设定ROI区域
    Mat imageROI;
    // 方法1
    imageROI=image(Rect(500,250,logo.cols,logo.rows));
    

      另外一种定义ROI的方式是指定感兴趣的行或列的范围(Range)。代码可重写为:

    // 方法二
    imageROI=image(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));
    

      其代码如下:

    bool  ROI_AddImage()
    {
    
        // 【1】读入图像
        Mat srcImage1 = imread("dota_pa.jpg");
        Mat logoImage = imread("dota_logo.jpg");
        if (!srcImage1.data) { printf("读取srcImage1错误~! 
    "); return false; }
        if (!logoImage.data) { printf("读取logoImage错误~! 
    "); return false; }
    
        // 【2】定义一个Mat类型并给其设定ROI区域
        Mat imageROI = srcImage1(Rect(200, 250, logoImage.cols, logoImage.rows));
    
        // 【3】加载掩模(必须是灰度图)
        Mat mask = imread("dota_logo.jpg", 0);
    
        //【4】将掩膜拷贝到ROI
        logoImage.copyTo(imageROI, mask);
    
        // 【5】显示结果
        namedWindow("<1>利用ROI实现图像叠加示例窗口");
        imshow("<1>利用ROI实现图像叠加示例窗口", srcImage1);
    
        return true;
    }
    ROI_AddImage

    线性混合

      线性混合是典型的二元的像素操作,其理论公式:g(x)=(1-a)fa(x)+af3(x)。可通过在范围0到1之间改变alpha值来对两幅图像(f0(x)和f1(x))或两段视频产生时间上的画面叠化(cross-dissolve)效果。

    addWeighted()函数

       这个函数作用是计算两个数组(图像)的加权和。原型如下:

    void addWeighted(InputArray src1, double alpha, InputArray src2,
                                  double beta, double gamma, OutputArray dst, int dtype = -1);
    // 表达式:
    dst=src1[I]*alpha+src2[I]*beta+gamma;

      总的演示代码如下:

    #pragma once
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <iostream>
    
    using namespace cv;
    using namespace std;
    
    //----------------------------------【ROI_AddImage( )函数】----------------------------------
    // 函数名:ROI_AddImage()
    //    描述:利用感兴趣区域ROI实现图像叠加
    //----------------------------------------------------------------------------------------------
    bool  ROI_AddImage()
    {
    
        // 【1】读入图像
        Mat srcImage1 = imread("dota_pa.jpg");
        Mat logoImage = imread("dota_logo.jpg");
        if (!srcImage1.data) { printf("读取srcImage1错误~! 
    "); return false; }
        if (!logoImage.data) { printf("读取logoImage错误~! 
    "); return false; }
    
        // 【2】定义一个Mat类型并给其设定ROI区域
        Mat imageROI = srcImage1(Rect(200, 250, logoImage.cols, logoImage.rows));
    
        // 【3】加载掩模(必须是灰度图)
        Mat mask = imread("dota_logo.jpg", 0);
    
        //【4】将掩膜拷贝到ROI
        logoImage.copyTo(imageROI, mask);
    
        // 【5】显示结果
        namedWindow("<1>利用ROI实现图像叠加示例窗口");
        imshow("<1>利用ROI实现图像叠加示例窗口", srcImage1);
    
        return true;
    }
    
    
    
    //---------------------------------【LinearBlending()函数】-------------------------------------
    // 函数名:LinearBlending()
    // 描述:利用cv::addWeighted()函数实现图像线性混合
    //--------------------------------------------------------------------------------------------
    bool  LinearBlending()
    {
        //【0】定义一些局部变量
        double alphaValue = 0.5;
        double betaValue;
        Mat srcImage2, srcImage3, dstImage;
    
        // 【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
        srcImage2 = imread("mogu.jpg");
        srcImage3 = imread("rain.jpg");
    
        if (!srcImage2.data) { printf("读取srcImage2错误! 
    "); return false; }
        if (!srcImage3.data) { printf("读取srcImage3错误! 
    "); return false; }
    
        // 【2】进行图像混合加权操作
        betaValue = (1.0 - alphaValue);
        addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);
    
        // 【3】显示原图窗口
        imshow("<2>线性混合示例窗口【原图】", srcImage2);
        imshow("<3>线性混合示例窗口【效果图】", dstImage);
    
        return true;
    
    }
    
    //---------------------------------【ROI_LinearBlending()】-------------------------------------
    // 函数名:ROI_LinearBlending()
    // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义
    //              感兴趣区域ROI,实现自定义区域的线性混合
    //--------------------------------------------------------------------------------------------
    bool  ROI_LinearBlending()
    {
    
        //【1】读取图像
        Mat srcImage4 = imread("dota_pa.jpg", 1);
        Mat logoImage = imread("dota_logo.jpg");
    
        if (!srcImage4.data) { printf("读取srcImage4错误~! 
    "); return false; }
        if (!logoImage.data) { printf("读取logoImage错误~! 
    "); return false; }
    
        //【2】定义一个Mat类型并给其设定ROI区域
        Mat imageROI;
        //方法一
        imageROI = srcImage4(Rect(200, 250, logoImage.cols, logoImage.rows));
        //方法二
        //imageROI= srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));
    
        //【3】将logo加到原图上
        addWeighted(imageROI, 0.5, logoImage, 0.3, 0., imageROI);
    
        //【4】显示结果
        imshow("<4>区域线性图像混合示例窗口", srcImage4);
    
        return true;
    }
    ImageBending
    #include "ImageBlending.h"
    
    int main()
    {
        // system("color 6F");
        int end = 0;
        Mat srcImage1 = imread("dota_pa.jpg");
        Mat logoImage = imread("dota_logo.jpg");
        imshow("原图1", srcImage1);
        imshow("原图2", logoImage);
    
        if (ROI_AddImage() && LinearBlending() && ROI_LinearBlending())
        {
            cout << "运行成功,得出了需要的图像";
        }
    
        waitKey(end);
        return 0;
    }
    main

      运行结果如下(详见附录):

      

    多通道图像混合与分离 

      上述的处理是单通道的图像叠加和混合,接下来将会展示多通道图像的分离和混合。为了更好地观察一些图像处理的特征,有时需要对RGB三个颜色通道的分量进行分别显示和调整。

      【通道分离:split()函数】 split函数可将一个多通道数组分离成几个单通道数组。

    C++ : void split(const Mat& src, Mat *mvbegin);
    C++ : void split(InputArray m, OutputArrayOfArrays mv);
    

      其公式:mv[c](I)=src(I)c

    //【2】把一个3通道图像转换成3个单通道图像
    	split(srcImage, channels);//分离色彩通道
    //【3】将原图的蓝色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
    	imageBlueChannel = channels.at(0);
    //【3】将原图的绿色通道的引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
    	imageGreenChannel = channels.at(1);
    //【3】将原图的红色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
    	imageRedChannel = channels.at(2);
    

      【通道合并:merge()函数】 该函数是split()函数的逆向操作——将多个数组合并成一个多通道的数组。

    C++ : void merge(const Mat*mv, size_tcount, OutputArray dst)
    C++ : void merg(InputArrayOfArrays mv, OutputArray dst)
    

      总的演示代码如下:

    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <iostream>
    
    using namespace cv;
    using namespace std;
    
    bool  MultiChannelBlending();
    
    int main()
    {
        // system("color 9F");
        int key = 0;
    
        if (MultiChannelBlending())
        {
            cout << "运行成功,得出了需要的图像!";
        }
    
        waitKey(key);
        return 0;
    }
    
    
    //-----------------------------【MultiChannelBlending( )函数】--------------------------------
    //    描述:多通道混合的实现函数
    //-----------------------------------------------------------------------------------------------
    bool  MultiChannelBlending()
    {
        //【0】定义相关变量
        Mat srcImage;
        Mat logoImage;
        vector<Mat> channels;
        Mat  imageBlueChannel;
    
        //=================【蓝色通道部分】=================
        //    描述:多通道混合-蓝色分量部分
        //============================================
    
        // 【1】读入图片
        logoImage = imread("dota_logo.jpg", 0);
        srcImage = imread("dota_jugg.jpg");
    
        if (!logoImage.data) { printf("Oh,no,读取logoImage错误~! 
    "); return false; }
        if (!srcImage.data) { printf("Oh,no,读取srcImage错误~! 
    "); return false; }
    
        //【2】把一个3通道图像转换成3个单通道图像
        split(srcImage, channels);//分离色彩通道
    
        //【3】将原图的蓝色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
        imageBlueChannel = channels.at(0);
        //【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中
        addWeighted(imageBlueChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0,
            logoImage, 0.5, 0, imageBlueChannel(Rect(500, 250, logoImage.cols, logoImage.rows)));
    
        //【5】将三个单通道重新合并成一个三通道
        merge(channels, srcImage);
    
        //【6】显示效果图
        namedWindow(" <1>游戏原画+logo蓝色通道");
        imshow(" <1>游戏原画+logo蓝色通道", srcImage);
    
    
        //=================【绿色通道部分】=================
        //    描述:多通道混合-绿色分量部分
        //============================================
    
        //【0】定义相关变量
        Mat  imageGreenChannel;
    
        //【1】重新读入图片
        logoImage = imread("dota_logo.jpg", 0);
        srcImage = imread("dota_jugg.jpg");
    
        if (!logoImage.data) { printf("读取logoImage错误~! 
    "); return false; }
        if (!srcImage.data) { printf("读取srcImage错误~! 
    "); return false; }
    
        //【2】将一个三通道图像转换成三个单通道图像
        split(srcImage, channels);//分离色彩通道
    
        //【3】将原图的绿色通道的引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
        imageGreenChannel = channels.at(1);
        //【4】将原图的绿色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageGreenChannel中
        addWeighted(imageGreenChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0,
            logoImage, 0.5, 0., imageGreenChannel(Rect(500, 250, logoImage.cols, logoImage.rows)));
    
        //【5】将三个独立的单通道重新合并成一个三通道
        merge(channels, srcImage);
    
        //【6】显示效果图
        namedWindow("<2>游戏原画+logo绿色通道");
        imshow("<2>游戏原画+logo绿色通道", srcImage);
    
    
    
        //=================【红色通道部分】=================
        //    描述:多通道混合-红色分量部分
        //============================================
    
        //【0】定义相关变量
        Mat  imageRedChannel;
    
        //【1】重新读入图片
        logoImage = imread("dota_logo.jpg", 0);
        srcImage = imread("dota_jugg.jpg");
    
        if (!logoImage.data) { printf("Oh,no,读取logoImage错误~! 
    "); return false; }
        if (!srcImage.data) { printf("Oh,no,读取srcImage错误~! 
    "); return false; }
    
        //【2】将一个三通道图像转换成三个单通道图像
        split(srcImage, channels);//分离色彩通道
    
        //【3】将原图的红色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
        imageRedChannel = channels.at(2);
        //【4】将原图的红色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageRedChannel中
        addWeighted(imageRedChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0,
            logoImage, 0.5, 0., imageRedChannel(Rect(500, 250, logoImage.cols, logoImage.rows)));
    
        //【5】将三个独立的单通道重新合并成一个三通道
        merge(channels, srcImage);
    
        //【6】显示效果图
        namedWindow("<3>游戏原画+logo红色通道 ");
        imshow("<3>游戏原画+logo红色通道 ", srcImage);
    
        return true;
    }
    MultiChannelImageBlending

      运行结果如下:
      

    参考文献

    [1] 毛星云.OpenCV3编程入门[M].电子工业出版社.北京.2015.2.   


    附录

     

     

      


      

  • 相关阅读:
    python 安装pillow
    rapidminer 数据导入及几个算子简单应用
    Fiddler高级用法-设置断点
    Linux 操作MySQL常用命令行
    VMWare虚拟机提示:另一个程序已锁定文件的一部分,打不开磁盘...模块"Disk"启动失败的解决办法
    解决VMware15 centos7 桥接模式ssh突然不能访问的问题
    新媒体运营需要什么能力?需要具备哪些运营技能?
    运营分为哪几类?具体的工作职责是什么?
    Centos7 yum安装MySQL5.7.25
    Centos7防火墙添加端口
  • 原文地址:https://www.cnblogs.com/jianle23/p/13787049.html
Copyright © 2011-2022 走看看