自己動手,實現“你的名字”濾鏡


    我喜歡《你的名字》這個故事,前一段時間在微信上使用過它的濾鏡,實現的效果很驚艷,應該類似於下面的這些結果
    
    這三幅圖應該都是手機版本制作的,它們一個比較顯著的特點是分辨率比較相似。如何實現類似的效果了?(注意后面兩圖天上的雲是相同的)
    首先我想到的是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和色卡制作
色調轉換的意義,在於使得全圖具有更多的“卡通”意味在厘米,畢竟我們想要實現的最終效果想要類似“你的名字”。那么什么是“動漫”的效果?這是一個見仁見智的問題。我找到一些做得較好的轉換
巧用Photoshop濾鏡將肖像照片變成卡通特效_天極軟件 巧用Photoshop濾鏡將肖像照片變成卡通特效_天極軟件
103126cmxj9137zh5j7n1h.jpg 103130jjg4gy4upgiynxmj.jpg
總的來說,卡通的效果是“顏色更加鮮艷”“細節比較少”等,是一個比較主觀的定義;對於”你的名字“這個效果來說,應該還有一個色調的變換
那么,就以表面模糊、彩色直方圖均衡以及色相調整這些比較容易實現的方法來達到目的。
 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進行了全局的處理,所以和原圖的差距比較大,反而造成了新的誤差,所以可能直接適用於圖像拼接不適合。





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM