zoukankan      html  css  js  c++  java
  • opencv笔记2:图像ROI


    time:2015年 10月 03日 星期六 12:03:45 CST

    opencv笔记2:图像ROI


    ROI

    ROI意思是Region Of Interests,感兴趣区域,是一个图中的一个子区域。
    OpenCV中定义的ROI是矩形的。
    ROI的用处包括而不限于:提取出ROI区域做进一步处理(比如人脸识别、车牌识别);将另一张图片贴放到ROI区域。
    这里以第二种用处为例,将一个logo图像添加到一张大图上指定的ROI区域。

    图像贴放

    粗略想想,包括这四个步骤

    • 定义大图和小图
    • 在大图上定义ROI区域
    • 小图贴放到ROI区域
    • 显示新的大图

    这里在fedora22下使用dnf(yum)安装了opencv3.0,如下代码可以运行良好

    #include <iostream>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    int main() {
        //【1】定义大图和小图
        //【2】在大图上定义ROI区域
        //【3】小图贴放到ROI区域
        //【4】显示新的大图
    
        //【1】定义大图和小图
        Mat srcImage = imread("/home/chris/workspace/clion/dota_pa.jpg");
        Mat logoImage = imread("/home/chris/workspace/clion/dota_ss.png");
        if(!srcImage.data){
            cerr << "读取srcImage错误!" << endl;
            exit;
        }
        if(!logoImage.data){
            cerr << "读取logoImage错误!" << endl;
            exit;
        }
    
        //【2】在大图上定义ROI区域
        Mat imageROI = srcImage(Rect(20, 25, logoImage.cols, logoImage.rows));
    
        //【3】小图贴放到ROI区域
        logoImage.copyTo(imageROI);
    
        //【4】显示新的大图
        imshow("利用ROI实现图像叠加示例窗口", srcImage);
        waitKey(0);
        destroyAllWindows();
        return 0;
    }
    

    这里copyTo()函数中只用到一个参数,浅墨的教程上有第二个参数:图像掩模(mask),我尝试了下,发现不用mask也没关系,mask的定义也不一定要是灰度图(即imread第二个参数设定为0)。对此,我表示不理解,反正能用就好了。

    图像线性混合

    直接把logo图替换掉ROI区域的做法通常不是很好,如果能把两者各按一定比例进行混合就显得更好些,这需要用到图像混合技术。
    图像线性混合,其实就是不同图片(这里以两张图为例),各自按照一定比例系数进行相加,没什么神奇的地方:

    result = alpha*src1 + beta*src2 + gamma
    

    使用函数addWeighted(src1, alpha, src2, beta, gamma, dstImage, dtype=-1)
    这里dtype参数,是输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。

    OK,粗略想下线性混合的步骤:

    • 定义两幅图像
    • 定义权重和偏置量等参数
    • 按参数做图像混合
    • 显示结果

    上代码:

    #include <iostream>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    int main() {
        //【1】定义两幅图像
        //【2】定义权重和偏置量等参数
        //【3】按参数做图像混合
        //【4】显示结果
    
        //【1】定义两幅图像
        Mat srcImage1 = imread("/home/chris/workspace/clion/mogu.jpg");
        Mat srcImage2 = imread("/home/chris/workspace/clion/rain.jpg");
    
        //【2】定义权重和偏置量等参数
        double alpha = 0.5; //第一幅图的权重
        double beta = 1- alpha; //第二幅图的权重
        double gamma = 0.0; //偏置量
    
        //【3】按参数做图像混合
        Mat dstImage; //目标图像,存放结果
        addWeighted(srcImage1, alpha, srcImage2, beta, gamma, dstImage);
    
        //【4】显示结果
        imshow("线性混合结果", dstImage);
        waitKey(0);
        destroyAllWindows();
    
        return 0;
    
    }
    

    好吧,其实这东西很简单。应用到ROI区域,对应的代码为:

    #include <iostream>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    int main() {
        //【1】定义两幅图像
        //【2】定义ROI区域
        //【3】定义权重和偏置量等参数
        //【4】按参数做图像混合
        //【5】显示结果
    
        //【1】定义两幅图像
        Mat srcImage1 = imread("/home/chris/workspace/clion/dota_pa.jpg");
        Mat srcImage2 = imread("/home/chris/workspace/clion/dota_ss.png");
    
        //【2】定义ROI区域
        Mat imageROI = srcImage1(Rect(20, 25, srcImage2.cols, srcImage2.rows));
    
        //【3】定义权重和偏置量等参数
        double alpha = 0.5; //第一幅图的权重
        double beta = 1- alpha; //第二幅图的权重
        double gamma = 0.0; //偏置量
    
        //【4】按参数做图像混合
        addWeighted(imageROI, alpha, srcImage2, beta, gamma, imageROI);
    
        //【5】显示结果
        imshow("线性混合结果", srcImage1);
        waitKey(0);
        destroyAllWindows();
    
        return 0;
    
    }
    

    多通道的分离和混合

    既然前面把图像混合讲到了,那么按照通道进行混合也就可以做了!比如要把看起来是白色的logo图,和指定背景图上ROI区域混合,并且希望logo图显示为红色。这就需要ROI图本身为红色通道,logo图读取为灰度图像(保证都是单通道),然后混合,这之后由于ROI区域就是原图中的一个通道上的一个区域,原图像的红色通道变化了,现在把三个通道重新合并回去,就能够得到想要的效果图了。

    粗略想下,步骤为:

    • 定义义两幅图像
    • 分离通道
    • 在通道图上定义ROI区域
    • 定义权重和偏置量等参数
    • 按参数做图像混合
    • 合并通道
    • 显示结果

    对应的代码为:

    #include <iostream>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    int main() {
        //义两幅图像
        //【2】分离通道
        //【3】在通道图上定义ROI区域
        //【4】定义权重和偏置量等参数
        //【5】按参数做图像混合
        //【6】合并通道
        //【7】显示结果
    
        //【1】定义两幅图像
        Mat srcImage = imread("/home/chris/workspace/clion/dota_pa.jpg");
        Mat logoImage = imread("/home/chris/workspace/clion/dota_logo.jpg", 0);
    
        //【2】分离通道
        vector<Mat> channels;
        split(srcImage, channels);
    
        //【3】在通道图上定义ROI区域
        Mat redChannelImage = channels.at(2);
        Mat imageROI = redChannelImage(Rect(50, 25, logoImage.cols, logoImage.rows));
    
        //【4】定义权重和偏置量等参数
        double alpha = 1.0;
        double beta = 0.5;
        double gamma = 0.0;
    
        //【5】按参数做图像混合
        addWeighted(imageROI, alpha, logoImage, beta, gamma, imageROI);
    
        //【6】合并通道
        merge(channels, srcImage);
    
        //【7】显示结果
        imshow("0通道", srcImage);
        waitKey(0);
        destroyAllWindows();
    
        return 0;
    
    }
    
  • 相关阅读:
    JavaScript与C# Windows应用程序交互
    用DateTime.ToString(string format)输出不同格式的日期
    时间间隔与暂停
    C#中比较两个时间的时间差
    lambda函数的用法
    Tornado笔记
    DjangoWeb应用开发实战笔记
    再看装饰器
    描述符
    flask简单代码回顾
  • 原文地址:https://www.cnblogs.com/zjutzz/p/4854172.html
Copyright © 2011-2022 走看看