OpenCV实现"你的名字"滤镜
这是一个比较有意思的demo,用到了播送融合,具体效果见下图:

文件结构如图所示

主程序代码
#include"stdafx.h"
#include<opencv2/photo.hpp>
#include"HSL.hpp"
using namespace std;
using namespace cv;
const string window_name = "photo";
static Mat src;
static HSL hsl;
static int color = 0;
static int hue = 180;
static int saturation = 100;
static int brightness = 100;
#define VP vector<Point>
//寻找最大的轮廓
VP FindBigestContour(Mat src) {
int imax = 0; //代表最大轮廓的序号
int imaxcontour = -1; //代表最大轮廓的大小
std::vector<std::vector<Point>>contours;
findContours(src, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); i++) {
int itmp = contourArea(contours[i]);//这里采用的是轮廓大小
if (imaxcontour < itmp) {
imax = i;
imaxcontour = itmp;
}
}
return contours[imax];
}
//提高饱和度
Mat EnhanceSaturation(Mat temp)
{
Mat matDst;
Mat Img_out(temp.size(), CV_32FC3);
temp.convertTo(Img_out, CV_32FC3);
Mat Img_in(temp.size(), CV_32FC3);
temp.convertTo(Img_in, CV_32FC3);
// define the iterator of the input image
MatIterator_<Vec3f> inp_begin, inp_end;
inp_begin = Img_in.begin<Vec3f>();
inp_end = Img_in.end<Vec3f>();
// define the iterator of the output image
MatIterator_<Vec3f> out_begin, out_end;
out_begin = Img_out.begin<Vec3f>();
out_end = Img_out.end<Vec3f>();
// increment (-100.0, 100.0)
float Increment = 50.0 / 100.0; //饱和度参数调整
float delta = 0;
float minVal, maxVal;
float t1, t2, t3;
float L, S;
float alpha;
for (; inp_begin != inp_end; inp_begin++, out_begin++)
{
t1 = (*inp_begin)[0];
t2 = (*inp_begin)[1];
t3 = (*inp_begin)[2];
minVal = std::min(std::min(t1, t2), t3);
maxVal = std::max(std::max(t1, t2), t3);
delta = (maxVal - minVal) / 255.0;
L = 0.5*(maxVal + minVal) / 255.0;
S = std::max(0.5*delta / L, 0.5*delta / (1 - L));
if (Increment > 0)
{
alpha = max(S, 1 - Increment);
alpha = 1.0 / alpha - 1;
(*out_begin)[0] = (*inp_begin)[0] + ((*inp_begin)[0] - L * 255.0)*alpha;
(*out_begin)[1] = (*inp_begin)[1] + ((*inp_begin)[1] - L * 255.0)*alpha;
(*out_begin)[2] = (*inp_begin)[2] + ((*inp_begin)[2] - L * 255.0)*alpha;
}
else
{
alpha = Increment;
(*out_begin)[0] = L * 255.0 + ((*inp_begin)[0] - L * 255.0)*(1 + alpha);
(*out_begin)[1] = L * 255.0 + ((*inp_begin)[1] - L * 255.0)*(1 + alpha);
(*out_begin)[2] = L * 255.0 + ((*inp_begin)[2] - L * 255.0)*(1 + alpha);
}
}
Img_out /= 255;
Img_out.convertTo(matDst, CV_8UC3, 255);
return matDst;
}
int _tmain(int argc, _TCHAR* argv[])
{
Mat matSrc = imread("../src3.jpg");
Mat matCloud = imread("../cloud2.jpg");
Mat temp; Mat matDst; Mat mask;
vector<Mat> planes;
/************************************************************************/
/* 1.背景(天空)分割 */
/************************************************************************/
cvtColor(matSrc, temp, COLOR_BGR2HSV);
split(temp, planes);
equalizeHist(planes[2], planes[2]);//对v通道进行equalizeHist
merge(planes, temp);
inRange(temp, Scalar(100, 43, 46), Scalar(124, 255, 255), temp);
erode(temp, temp, Mat());//形态学变换,填补内部空洞
dilate(temp, temp, Mat());
mask = temp.clone();//将结果存入mask
/************************************************************************/
/* 2.再融合,以1的结果mask,直接将云图拷贝过来(之前需要先做尺度变换) */
/************************************************************************/
//寻找白色区域最大外接矩形的代码
VP maxCountour = FindBigestContour(mask);
Rect maxRect = boundingRect(maxCountour);
if (maxRect.height == 0 || maxRect.width == 0)
maxRect = Rect(0, 0, mask.cols, mask.rows);//特殊情况
matDst = matSrc.clone();
//注意这里的mask 需要和matCloud同样尺寸
mask = mask(maxRect);
resize(matCloud, matCloud, maxRect.size());
//seamless clone
//中间位置为蓝天的背景位置
Point center = Point((maxRect.x + maxRect.width) / 2, (maxRect.y + maxRect.height) / 2);
Mat normal_clone;
Mat mixed_clone;
Mat monochrome_clone;
seamlessClone(matCloud, matSrc, mask, center, normal_clone, NORMAL_CLONE);
seamlessClone(matCloud, matSrc, mask, center, mixed_clone, MIXED_CLONE);
seamlessClone(matCloud, matSrc, mask, center, monochrome_clone, MONOCHROME_TRANSFER);
/************************************************************************/
/* 3.卡通画处理 */
/************************************************************************/
//双边滤波
bilateralFilter(normal_clone, temp, 5, 10.0, 2.0);
//彩色直方图均衡,将RGB图像转到YCbCr分量,然后对Y分量上的图像进行直方图均衡化
cvtColor(temp, temp, COLOR_BGR2YCrCb);
split(temp, planes);
equalizeHist(planes[0], planes[0]);
merge(planes, temp);
cvtColor(temp, temp, COLOR_YCrCb2BGR);
//提高图像饱和度
matDst = EnhanceSaturation(temp);
imshow("原始图", matSrc);
imshow("结果图", matDst);
cv::waitKey();
getchar();
return 0;
}
其他包含的库文件放到我的链接:https://i-beta.cnblogs.com/files
OpenCV实现"你的名字"滤镜的更多相关文章
- [转] Matlab与C++混合编程,添加OpenCV库
原文地址 峰回璐转 最近在做运动医学软件优化工作,此款软件框架及算法语言全由matlab实现,虽然matlab矩阵运算.数值计算能力强大,但速度让人难以忍 受.软件立刻移植到C++上又不太实际,故采用 ...
- Matlab与C++混合编程,添加OpenCV库
最近在做运动医学软件优化工作,此款软件框架及算法语言全由matlab实现,虽然matlab矩阵运算.数值计算能力强大,但速度让人难以忍受.软件立刻移植到C++上又不太实际,故采用联合编程的方式,速度难 ...
- Ubuntu系统---编译opencv程序的几种方式g++、Makefile、Cmake
Ubuntu系统---编译opencv程序的几种方式g++.Makefile.Cmake 先建立一个工程(一个文件夹),写好xxx.cpp文件,可以是多个: //----------opencv.cp ...
- Poisson Blending(Seamless clone)研究和实现
Poisson Blending 实现了非常棒的效果,可以看 <自己动手,实现“你的名字”滤镜> http://www.cnblogs.com/jsxyhelu/p/7216795.htm ...
- studio 配置 opencv3.1
环境 win10 android studio2.0 OpenCV-3.1.0-android-sdk android-ndk-r10e-windows-x86_64 jdk-8u102-window ...
- vs2017 dlib19.3 opencv3.41 C++ 环境配置 人脸特征点识别
身为一个.net程序员经过两天的采坑终于把人脸特征检测的项目跑通了,然后本文将以dlib项目中人脸特征检测工程为例,讲解dlib与opencv 在vs2017 C++ 项目中的编译与运行路径配置. 1 ...
- 高反差保留滤镜学习OpenCV:滤镜系列(11)——高反差保留
这几周笔者几篇文章介绍了改高反差保留滤镜的文章. 关联文章的地址 高反差保留就是高通滤波 r=(pix[x,y]-avg(R))/128 pix[x,y]*r+128*(1-r) #include & ...
- opencv滤镜-使用opencv实现各种图像滤镜特效
图像处理-滤镜 链接:https://mangoroom.cn/opencv/image-processing-filter.html opencv滤镜-实现晕影vignetting效果 链接:htt ...
- 学习OpenCV:滤镜系列(15)——羽化(模糊边缘)
============================================== 版权所有:小熊不去实验室CSDN博客 ================================== ...
随机推荐
- 通过ip查询相关网络位置信息
结果:
- Java学习:泛型简介
泛型 泛型:是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型 泛型也可以看出是一个变量,用来接受数据类型 E e : Element 元素 T t : Type 类型 Array ...
- SQL系列(十三)—— 关于表的DDL
前面的文章一直都在讲述关于DML方面的SQL Statement.这篇文章来说说表方面的DDL: CREATE 创建表 ALTER 修改表 DROP 删除表 CREATE 1.语法 CREATE TA ...
- 【leetcode-49】字母异位词分组
给定一个字符串数组,将字母异位词组合在一起.字母异位词指字母相同,但排列不同的字符串. 示例: 输入: ["eat", "tea", "tan&quo ...
- 封装:WPF中可以绑定的BindPassWord控件
原文:封装:WPF中可以绑定的BindPassWord控件 一.目的:本身自带的PassWord不支持绑定 二.Xaml部分 <UserControl x:Class="HeBianG ...
- mysql数据库事务
事务: 一个或者一组sql语句组成一个执行的单元,这个单元要么全都执行,要么都不执行.也就是每个sql语句相互依赖.如果中间有一条出现错误则整个单元将回滚.(回滚就是刚刚的操作都撤销) 事务的属性: ...
- 浅浅的叙WPF之数据驱动与命令
之前一直开发Winfrom程序,由于近一段时间转开发Wpf程序,刚好拜读刘铁锰<深入浅出WPF>对此有一些理解,如有误导指出,还望斧正!!! 说道WPF数据驱动的编程思想,MVVM,是为W ...
- Vue学习之动画小结(六)
一.Vue中实现动画的方式:https://cn.vuejs.org/v2/guide/transitions.html Vue 在插入.更新或者移除 DOM 时,提供多种不同方式的应用过渡效果.包括 ...
- Java 之 线程池
一.线程池思想概述 如果使用线程的时候就去创建一个线程,这样实现起来非常简便,但是会出现一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低 ...
- spring中WebApplicationContext、DispatcherServlet与web容器的ServletContext关系梳理
学习源码过程中,对各种context(上下文)表示很懵逼.特地留此一篇. 1.要了解各个上下文之间的关系.首先走一遍spring在web容器(tomcat)中的启动过程 a) ServletConte ...