


這三幅圖應該都是手機版本制作的,它們一個比較顯著的特點是分辨率比較相似。如何實現類似的效果了?(注意后面兩圖天上的雲是相同的)
首先我想到的是Prisma的實現方法,這種實現方法,最后得到的是紋理的轉換,效果應該說非常好,但是依賴於深度學習,目前這個方面掌握的不是很明確。而且顯然上面三圖不是紋理轉換。

繼續尋找,主要參考《
實現<你的名字>同款濾鏡,python+opencv》等相關資料。
一、問題分析

對於這樣一副圖片,如果想變成《你的名字》這種效果,需要做以下事情
(一)背景(天空)分割,替換后再融合
在自然界的圖片中,很難出現動漫中大多大多的雲彩。首先需要將
背景(天空)分割出來,替換成動漫的天空,並且在很好地融合回去。
需要實現的技術:1.
背景(天空)分割;2.再融合。需要准備的材料:1.大塊的動漫雲圖
(二)前景色調轉換
為了實現漫畫中具有卡通意味的前景色調,需要對前面切割下來的前景圖片進行色調轉換。
需要實現的技術:3.LUT和色塊制作
(三)程序框架
需要實現的技術:基於GOMfcTemplate2,實現圖像的輸入輸出、濾鏡操作的參數選擇等基礎操作
二、材料准備
1.大朵的雲。先找到一副自然界中的雲。

再准備(制作)一幅動漫的雲和一副星空的圖片.


三、算法實驗
1.
背景(天空)分割,采用材料中的方法,修改形態學部分
/************************************************************************/
/* 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());
imshow(
"原始圖",matSrc);
對於這幅圖來說,效果不錯(右上角明顯的是錯誤,而塔中間的一個很小的空洞,最后生成的效果應該可以忽略不計)

2.再融合
以此為mask,直接將雲圖拷貝過來(之前需要先做尺度變換,就是resize) 距離變換?
cvtColor(temp,mask,COLOR_BGR2GRAY);
//將結果存入mask
resize(matCloud,matCloud,matSrc.size());
matCloud.copyTo(matSrc,mask);

這個時候看圖片,還是有很多瑕疵的,特別是下方護欄的邊緣的地方。但是對於這樣的圖片,其前景和背景的分割,主要部分的效果還是非常不錯的;
所以采用seamlessclone,得到以下結果
//seamless clone
Point center(matSrc.cols
/
2,matSrc.rows
/
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);
NORMAL_CLONE

MIXED_CLONE

MONOCHROME_TRANSFER

相比較之下,
MIXED_CLONE對原圖紋理的保存更好一些,對有錯誤的地方的進行了很好地遮蓋。
3.LUT和色卡制作
色調轉換的意義,在於使得全圖具有更多的“卡通”意味在厘米,畢竟我們想要實現的最終效果想要類似“你的名字”。那么什么是“動漫”的效果?這是一個見仁見智的問題。我找到一些做得較好的轉換




總的來說,卡通的效果是“顏色更加鮮艷”“細節比較少”等,是一個比較主觀的定義;對於”你的名字“這個效果來說,應該還有一個色調的變換
那么,就以表面模糊、彩色直方圖均衡以及色相調整這些比較容易實現的方法來達到目的。
step1.雙邊濾波

step2.彩色直方圖

step3.飽和度調整

/************************************************************************/
/* 3.卡通畫處理 */
/************************************************************************/
//雙邊濾波
bilateralFilter(mixed_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);
//提高飽和度
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);
算法部分各種結果展現





現在看來,結果還是不很想”你的名字“的效果,但是美化的效果是有的。存在比較大的硬傷就是天空算法中,會找到一些邊界,比如。

為什么會出現這種情況?因為seamlessClone只是clone算法,而不是融合算法,所以需要后續優化。
四、工程實現
基於GOMfcTemplate2,實現圖像的輸入輸出、濾鏡操作的參數選擇等基礎操作
下一步,還需要繼續研究清楚各種算法的原理,得到更好的結果。

2017年7月25日19:18:45 前面的問題沒有解決完,耽擱了幾天:
一個是最上面邊緣的不和諧過渡問題,我重新學習了一下《實現<你的名字>同款濾鏡》,他的解決方法更好,主要是在seamless的時候,不是全圖融合,而是找出輪廓后再融合。
//2017年7月25日 添加尋找白色區域最大外接矩形的代碼
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();
resize(matCloud,matCloud,matDst.size());
matCloud.copyTo(matDst,mask);
//為seamless准備材料
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);
這個時候,結果就更是perfect了,和原文一樣,我采用
NORMAL_CLONE
的方法,目前的結果為

而在曾經出現過問題的地方,有所收斂

好看多了

修改代碼的時候需要注意mask的修改,這點在代碼里面說明了,自己看。
二個是,我感覺現在前景雖然對比度提高,顏色鮮艷,但明顯不是動漫的感覺呀。漫畫的效果肯定是有一些論文的,
依稀記得《master opencv with practical projects》第一章實現cartoon效果,

但是這個效果也太隨意了(這篇文章在作者一定是個爸爸,媽媽是不會放自己小孩這樣的圖片的)。找到它的代碼進行修改

應該還可以進一步提高,但是這個效果很有意思,開源之,大家可以一起來看。
2017年7月28日19:21:27
進一步思考,這種融合效果能否用於圖像拼接?進行了一些常識
Mat matreult
=
Mat(normal_clone.rows
+
30
,matCloud.cols,CV_8UC3,Scalar(
0
));
Mat halfTop
= matreult(Rect(
0,
0,maxRect.width,
30));
Mat halfDown
= matreult(Rect(
0,
30,normal_clone.cols,normal_clone.rows));
matTop.copyTo(halfTop);
normal_clone.copyTo(halfDown);
Mat matNormal
= matreult.clone();
mixed_clone.copyTo(halfDown);
Mat matMixed
= matreult.clone();
monochrome_clone.copyTo(halfDown);
Mat matMonochrome
= matreult.clone();

可以看到,在邊緣部分,由於meanlessclone進行了全局的處理,所以和原圖的差距比較大,反而造成了新的誤差,所以可能直接適用於圖像拼接不適合。