OpenCV实现无缝克隆算法的步骤详解

目录
  • 一、概述
  • 二、函数原型
  • 三、OpenCV源码
    • 1、源码路径
    • 2、源码代码
  • 四、效果图像示例

一、概述

借助无缝克隆算法,您可以从一张图像中复制一个对象,然后将其粘贴到另一张图像中,从而形成一个看起来无缝且自然的构图。

二、函数原型

给定一个原始彩色图像,可以无缝混合该图像的两个不同颜色版本。

void     cv::colorChange (InputArray src, InputArray mask, OutputArray dst, float red_mul=1.0f, float green_mul=1.0f, float blue_mul=1.0f)
src 输入 8 位 3 通道图像
mask 输入 8 位 1 或 3 通道图像
dst 输出与 src 大小和类型相同的图像
red_mul R 通道倍增因子
green_mul G 通道倍增因子
blue_mul B 通道倍增因子

对选区内部的梯度场应用适当的非线性变换,然后用泊松求解器积分,局部修改图像的表观照明。

void     cv::illuminationChange (InputArray src, InputArray mask, OutputArray dst, float alpha=0.2f, float beta=0.4f)
src 输入 8 位 3 通道图像
mask 输入 8 位 1 或 3 通道图像
dst 输出与 src 大小和类型相同的图像
alpha 值范围在 0-2 之间
beta 值范围在 0-2 之间

图像编辑任务涉及全局变化(颜色/强度校正、过滤器、变形)或与选择有关的局部变化。 在这里,我们有兴趣以无缝且轻松的方式实现局部更改,这些更改仅限于手动选择的区域 (ROI)。 变化的程度从轻微的扭曲到完全被新颖的内容替代。

void     cv::seamlessClone (InputArray src, InputArray dst, InputArray mask, Point p, OutputArray blend, int flags)
src 输入 8 位 3 通道图像
dst 输入 8 位 3 通道图像
mask 输入 8 位 1 或 3 通道图像
p 在 dst 图像中指向放置对象的位置
blend 输出与 dst 大小和类型相同的图像
flags 可以是 cv::NORMAL_CLONE、cv::MIXED_CLONE 或 cv::MONOCHROME_TRANSFER 的克隆方法

通过仅保留边缘位置的梯度,在与泊松求解器集成之前,可以洗掉所选区域的纹理,使其内容具有平坦的外观。 这里使用 Canny 边缘检测器。

void     cv::textureFlattening (InputArray src, InputArray mask, OutputArray dst, float low_threshold=30, float high_threshold=45, int kernel_size=3)
src 输入 8 位 3 通道图像
mask 输入 8 位 1 或 3 通道图像
dst 输出与 src 大小和类型相同的图像
low_threshold 范围从 0 到 100
high_threshold 值 > 100
kernel_size 要使用的 Sobel 内核的大小

三、OpenCV源码

1、源码路径

opencv\modules\photo\src\seamless_cloning.cpp

2、源码代码

#include "precomp.hpp"
#include "opencv2/photo.hpp"

#include "seamless_cloning.hpp"

using namespace std;
using namespace cv;

static Mat checkMask(InputArray _mask, Size size)
{
    Mat mask = _mask.getMat();
    Mat gray;
    if (mask.channels() > 1)
        cvtColor(mask, gray, COLOR_BGRA2GRAY);
    else
    {
        if (mask.empty())
            gray = Mat(size.height, size.width, CV_8UC1, Scalar(255));
        else
            mask.copyTo(gray);
    }

    return gray;
}

void cv::seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point p, OutputArray _blend, int flags)
{
    CV_INSTRUMENT_REGION();

    const Mat src  = _src.getMat();
    const Mat dest = _dst.getMat();
    Mat mask = checkMask(_mask, src.size());
    dest.copyTo(_blend);
    Mat blend = _blend.getMat();

    Mat mask_inner = mask(Rect(1, 1, mask.cols - 2, mask.rows - 2));
    copyMakeBorder(mask_inner, mask, 1, 1, 1, 1, BORDER_ISOLATED | BORDER_CONSTANT, Scalar(0));

    Rect roi_s = boundingRect(mask);
    if (roi_s.empty()) return;
    Rect roi_d(p.x - roi_s.width / 2, p.y - roi_s.height / 2, roi_s.width, roi_s.height);

    Mat destinationROI = dest(roi_d).clone();

    Mat sourceROI = Mat::zeros(roi_s.height, roi_s.width, src.type());
    src(roi_s).copyTo(sourceROI,mask(roi_s));

    Mat maskROI = mask(roi_s);
    Mat recoveredROI = blend(roi_d);

    Cloning obj;
    obj.normalClone(destinationROI,sourceROI,maskROI,recoveredROI,flags);
}

void cv::colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float red, float green, float blue)
{
    CV_INSTRUMENT_REGION();

    Mat src  = _src.getMat();
    Mat mask = checkMask(_mask, src.size());
    _dst.create(src.size(), src.type());
    Mat blend = _dst.getMat();

    Mat cs_mask = Mat::zeros(src.size(), src.type());
    src.copyTo(cs_mask, mask);

    Cloning obj;
    obj.localColorChange(src, cs_mask, mask, blend, red, green, blue);
}

void cv::illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, float alpha, float beta)
{
    CV_INSTRUMENT_REGION();

    Mat src  = _src.getMat();
    Mat mask = checkMask(_mask, src.size());
    _dst.create(src.size(), src.type());
    Mat blend = _dst.getMat();

    Mat cs_mask = Mat::zeros(src.size(), src.type());
    src.copyTo(cs_mask, mask);

    Cloning obj;
    obj.illuminationChange(src, cs_mask, mask, blend, alpha, beta);

}

void cv::textureFlattening(InputArray _src, InputArray _mask, OutputArray _dst,
                           float low_threshold, float high_threshold, int kernel_size)
{
    CV_INSTRUMENT_REGION();

    Mat src  = _src.getMat();
    Mat mask = checkMask(_mask, src.size());
    _dst.create(src.size(), src.type());
    Mat blend = _dst.getMat();

    Mat cs_mask = Mat::zeros(src.size(), src.type());
    src.copyTo(cs_mask, mask);

    Cloning obj;
    obj.textureFlatten(src, cs_mask, mask, low_threshold, high_threshold, kernel_size, blend);
}

四、效果图像示例

以上就是OpenCV实现无缝克隆算法的步骤详解的详细内容,更多关于OpenCV无缝克隆算法的资料请关注我们其它相关文章!

(0)

相关推荐

  • OpenCV实现双边滤波算法

    本文实例为大家分享了OpenCV实现双边滤波算法的具体代码,供大家参考,具体内容如下 一.双边滤波 双边滤波是一种综合考虑滤波器内图像空域信息和滤波器内图像像素灰度值相似性的滤波算法,可以实现在保留区域信息的基础上实现对噪声的去除.对局部边缘的平滑.双边滤波对高频率的波动信号起到平滑的作用,同时保留大幅值变化的信号波动,进而实现对保留图像中边缘信息的作用.双边滤波具有美颜效果. 二.C++代码 #include <opencv2\opencv.hpp> #include <iostrea

  • 利用OpenCV实现质心跟踪算法

    目录 质心跟踪算法步骤 项目结构 使用 OpenCV 实现质心跟踪 实现对象跟踪驱动程序脚本 限制和缺点 目标跟踪的过程: 1.获取对象检测的初始集 2.为每个初始检测创建唯一的ID 3.然后在视频帧中跟踪每个对象的移动,保持唯一ID的分配 本文使用OpenCV实现质心跟踪,这是一种易于理解但高效的跟踪算法. 质心跟踪算法步骤 步骤1:接受边界框坐标并计算质心 质心跟踪算法假设我们为每一帧中的每个检测到的对象传入一组边界框 (x, y) 坐标. 这些边界框可以由任何类型的对象检测器(颜色阈值 +

  • C++ OpenCV实现图像双三次插值算法详解

    目录 前言 一.图像双三次插值算法原理 二.C++ OpenCV代码 1.计算权重矩阵 2.遍历插值 3. 测试及结果 前言 近期在学习一些传统的图像处理算法,比如传统的图像插值算法等.传统的图像插值算法包括邻近插值法.双线性插值法和双三次插值法,其中邻近插值法和双线性插值法在网上都有很详细的介绍以及用c++编写的代码.但是,网上关于双三次插值法的原理介绍虽然很多,也有对应的代码,但是大多都不是很详细.因此基于自己对原理的理解,自己编写了图像双三次插值算法的c++ opencv代码,在这里记录一

  • C++ OpenCV实现白平衡之完美反射算法

    目录 实现原理 功能函数代码 C++测试代码 测试效果 实现原理 白平衡的意义在于,对在特定光源下拍摄时出现的偏色现象,通过加强对应的补色来进行补偿,使白色物体能还原为白色. 完美反射算法是白平衡各种算法中较常见的一种,比灰度世界算法更优.它假设图像世界中最亮的白点是一个镜面,能完美反射光照:基于白点,将三通道的数值进行适当地调整,以达到白平衡效果:除此之外,还需要统计最亮的一定区间的三通道均值,该均值与该通道最大值的差距决定了该通道调整的力度. 通俗的讲,若图像中绿色分量最大值是255,但是绿

  • C++结合OpenCV实现RRT算法(路径规划算法)

    目录 1.RRT算法简介 2.算法整体框架流程 2.1 rand点的建立 2.2 near和new点的建立 2.3 安全性检查 2.4 算法结束判断 3.RRT代码框架 3.1 主函数 3.2 地图数据的获取 3.3 RRT算法的实现 3.3.1 起点入树 3.3.2 rand点的获取 3.3.3 near点的获取 3.3.4 new点的获取 3.3.5 安全性检测 3.4 可视化显示 4. 代码运行过程 1.RRT算法简介 代码链接:RRT动图展示 RRT 2.算法整体框架流程 RRT算法整体

  • C++ OpenCV实现白平衡之灰度世界算法

    目录 实现原理 功能函数代码 C++测试代码 测试效果 实现原理 白平衡的意义在于,对在特定光源下拍摄时出现的偏色现象,通过加强对应的补色来进行补偿,使白色物体能还原为白色. 灰度世界算法是白平衡各种算法中最基本的一种.它假设图像世界具备丰富色彩,红蓝绿三通道的灰度值在平均后趋近一致,该值作为“灰色”:若各通道均值偏离“灰色”,则将其进行补偿,使其回归“灰色”,进而实现白平衡的效果. 通俗的讲,若图像中绿色较强,蓝色和红色较弱,则用了灰度世界算法后,绿色会适当减弱,蓝色和红色会适当加强,这样就使

  • OpenCV实现无缝克隆算法的步骤详解

    目录 一.概述 二.函数原型 三.OpenCV源码 1.源码路径 2.源码代码 四.效果图像示例 一.概述 借助无缝克隆算法,您可以从一张图像中复制一个对象,然后将其粘贴到另一张图像中,从而形成一个看起来无缝且自然的构图. 二.函数原型 给定一个原始彩色图像,可以无缝混合该图像的两个不同颜色版本. void cv::colorChange (InputArray src, InputArray mask, OutputArray dst, float red_mul=1.0f, float gr

  • OpenCV实现图像去噪算法的步骤详解

    目录 一.函数参考 1.Primal-dual算法 2.非局部均值去噪算法 三.OpenCV源码 1.源码路径 2.源码代码 四.效果图像示例 一.函数参考 1.Primal-dual算法 Primal-dual algorithm是一种用于解决特殊类型的变分问题的算法(即找到一个函数来最小化一些泛函). 特别是由于图像去噪可以看作是变分问题,因此可以使用原始对偶算法进行去噪,这正是该算法所实现的. cv::denoise_TVL1 (const std::vector< Mat > &

  • Python使用Numpy实现Kmeans算法的步骤详解

    目录 Kmeans聚类算法介绍: 1.聚类概念: 2.Kmeans算法: 定义: 大概步骤: Kmeans距离测定方式: 3.如何确定最佳的k值(类别数): 手肘法: python实现Kmeans算法: 1.代码如下: 2.代码结果展示: 聚类可视化图: 手肘图: 运行结果: 文章参考: Kmeans聚类算法介绍: 1.聚类概念: 将物理或抽象对象的集合分成由类似的对象组成的多个类的过程被称为聚类.由聚类所生成的簇是一组数据对象的集合,这些对象与同一个簇中的对象彼此相似,与其他簇中的对象相异.

  • Python opencv相机标定实现原理及步骤详解

    相机标定相机标定的目的 获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像. 相机标定的输入 标定图像上所有内角点的图像坐标,标定板图像上所有内角点的空间三维坐标(一般情况下假定图像位于Z=0平面上). 相机标定的输出 摄像机的内参.外参系数. 拍摄的物体都处于三维世界坐标系中,而相机拍摄时镜头看到的是三维相机坐标系,成像时三维相机坐标系向二维图像坐标系转换.不同的镜头成像时的转换矩阵不同,同时可能引

  • Python实现K-means聚类算法并可视化生成动图步骤详解

    K-means算法介绍 简单来说,K-means算法是一种无监督算法,不需要事先对数据集打上标签,即ground-truth,也可以对数据集进行分类,并且可以指定类别数目 牧师-村民模型 K-means 有一个著名的解释:牧师-村民模型: 有四个牧师去郊区布道,一开始牧师们随意选了几个布道点,并且把这几个布道点的情况公告给了郊区所有的村民,于是每个村民到离自己家最近的布道点去听课. 听课之后,大家觉得距离太远了,于是每个牧师统计了一下自己的课上所有的村民的地址,搬到了所有地址的中心地带,并且在海

  • 用Python实现简单的人脸识别功能步骤详解

    前言 让我的电脑认识我,我的电脑只有认识我,才配称之为我的电脑! 今天,我们用Python实现简单的人脸识别技术! Python里,简单的人脸识别有很多种方法可以实现,依赖于python胶水语言的特性,我们通过调用包可以快速准确的达成这一目的.这里介绍的是准确性比较高的一种. 一.首先 梳理一下实现人脸识别需要进行的步骤: 流程大致如此,在此之前,要先让人脸被准确的找出来,也就是能准确区分人脸的分类器,在这里我们可以用已经训练好的分类器,网上种类较全,分类准确度也比较高,我们也可以节约在这方面花

  • Python基于纹理背景和聚类算法实现图像分割详解

    目录 一.基于纹理背景的图像分割 二.基于K-Means聚类算法的区域分割 三.总结 一.基于纹理背景的图像分割 该部分主要讲解基于图像纹理信息(颜色).边界信息(反差)和背景信息的图像分割算法.在OpenCV中,GrabCut算法能够有效地利用纹理信息和边界信息分割背景,提取图像目标物体.该算法是微软研究院基于图像分割和抠图的课题,它能有效地将目标图像分割提取,如图1所示[1]. GrabCut算法原型如下所示: mask, bgdModel, fgdModel = grabCut(img,

  • 对python中Librosa的mfcc步骤详解

    1.对语音数据归一化 如16000hz的数据,会将每个点/32768 2.计算窗函数:(*注意librosa中不进行预处理) 3.进行数据扩展填充,他进行的是镜像填充("reflect") 如原数据为 12345 -> 填充为4的,左右各填充4 即:5432123454321 即:5432-12345-4321 4.分帧 5.加窗:对每一帧进行加窗, 6.进行fft傅里叶变换 librosa中fft计算,可以使用.net中的System.Numerics MathNet.Nume

  • Angular6封装http请求的步骤详解

    最近抽空学习了一下Angular6,之前主要使用的是vue,所以免不了的也想对Angular6提供的工具进行一些封装,今天主要就跟大家讲一下这个http模块. 之前使用的ajax库是axios,可以设置baseurl,公共头部:集中捕捉错误等,由于Angular6的依赖注入机制,是不能通过直接修改http模块暴露的变量来封装的,但是通过官方文档我们知道可以通过拦截器(HttpInterceptor)来实现这一功能. 拦截器可以拦截请求,也可以拦截响应,那么通过拦截请求就可以实现 设置baseur

  • 使用git迁移Laravel项目至新开发环境的步骤详解

    对于如何创建一个Laravel项目,相信对新接触Laravel的朋友并不存在太多的问题,但是今天我们要来看一下如何将已有的Laravel项目迁移(复制)到新的开发环境. 我们需要用到的工具是git,如果你不知道git是什么,这里有一个传送门,看完之后再回来: http://github.com 简单说来,git就是Github开发的VCS(Version Control System),即版本控制系统.如果你使用过SVN,那么你应该很清楚版本控制是什么. 本文的示例环境是Ubuntu 16.04

随机推荐