首頁 web前端 PS教程 Photoshop 油畫效果濾鏡

Photoshop 油畫效果濾鏡

Feb 18, 2017 pm 01:33 PM

  本濾鏡是我採用PS SDK 開發而成,而濾鏡的演算法具體是由誰提出的可能不詳,我是參考了FilterExplorer 的源碼(VC 6),本演算法的主要參考來源是該專案中的Filters.cpp, 作者是Jason Waltman (18, April, 2001) 。另國內另一個用C#語言編寫的軟體 PhotoSprite (Version 3.0 ,2006,由 聯駿 編寫)其中的油畫濾鏡的演算法應該也是引用自了前者(或其他同源程式碼)。在研究此濾鏡演算法時,我主要參考的是前者的 C++ 程式碼,本文對此演算法的概念性描述屬於我的理解和解讀。但該演算法的效率並不高,我將該演算法的效率大大提高,關於模板尺寸的時間複雜度從O ( n^2 ) 改進為線性複雜度O ( n ),關於像素數量的複雜度的常數係數大幅減小,對相同測試樣本(某個1920 * 1200 像素RGB 影像)相同參數的處理速度從大約35 秒降低到大約3 秒,處理速度大概提高到10 ~ 12倍左右(粗略估算)。

    本文主要是發布 Photoshop 油畫效果濾鏡(OilPaint)。演算法並非我提出,可以參考本文的參考資料。該濾鏡在用 C# 開發的國產軟體 PhotoSprite 中可以看到。 2010 年曾有人請求我幫忙開發該濾鏡,現在我花了大概幾天時間將其開發出來並免費提供。

 

    (1)對油畫濾鏡的演算法的概念性描述

 

    這是我透過閱讀 FilterExplorer 原始碼後所理解的。此濾鏡有兩個參數,一個是模板半徑(radius),則模板尺寸是(radius * 2 + 1)*(radius * 2 + 1)大小,也就是以當前像素為中心,向外擴展radius 個像素的矩形區域,作為一個搜尋範圍,我們暫時將它稱為「模板」(實際上該演算法並不是例如高斯模糊,自定濾鏡那種標準模板法,僅僅是處理過程類似,因此我才能實現稍後介紹的優化)。

    另一個參數是光滑度(smoothness),實際上他是灰度桶的個數。我們假設把像素的灰階/亮度( 0 ~ 255 )均勻的分成smoothness 個區間,則每個區間我們在此稱它為一個桶(bucket),這樣我們就有很多個桶,暫時稱之為桶陣列(buckets)。

    此演算法遍歷圖上的每個像素,針對當前位置(x, y) 像素,將模板範圍內的所有像素灰度化,即把圖像變成灰度圖像,然後把像素值進一步離散化,即根據像素的灰度落入的區間,把模板內的像素依序投入到對應的桶子中。然後從這些桶子中找到一個落入像素個數最多的桶,並對該桶中的所有像素求出顏色平均值,作為位置 (x, y) 的結果值。

    上面的演算法描述,用下面的示意圖來表示。中間的影像是從原圖灰度化+離散化(相當於 Photoshop 中的色調分離)的結果,小方框表示的是模板。下方表示的是桶陣列(8 個桶,即把0~255的灰階值離散化成 8 個區間段)。

 

    Photoshop 油画效果滤镜

 

    (2)對完成的生活程式碼的效率的改善濾中並不難,我大概花了1 ~ 2 天的業餘時間就基本調試成功了。但是在閱讀老外的源碼時,我明顯感覺到原有程式碼的效率不夠高。此演算法遍歷一次影像即可完成,對每個像素的處理是常數時間,因此針對像素數量(影像長度*影像寬度)是O(n)複雜度,但是原有程式碼的常係數較大,例如,每次計算像素結果時,都要重新計算模板範圍內像素的灰度,並把它投入桶中,實際上造成大量的重複性計算。

 

    2.1 為此,我的第一個改進是在PS 中把當前的整個圖像貼片進行灰度化並離散化(投入桶中),這樣在用模板遍歷貼片時,就不需要重複性的計算灰階並離散化了。這樣大概把演算法的運行速度提高了一倍左右(針對某個樣本,處理速度從20多秒提高到10秒左右)。

 

    2.2 但這樣對速度的增加仍不夠顯著。因此我進行另一項更重要的最佳化,即把針對模板尺寸的複雜度從平方降到線性複雜度。這個依據是,考慮模板在目前行間從左向右逐格移動,模板中部像素(相鄰兩個模板的交集)在結果中的統計資料是不變的。只有最左側一列移出模板,最右側一列進入模板,因此我們在遍歷圖像時就不必管模板中部像素,只需要處理模板的兩個邊緣即可。如下圖所示(半徑為2,模板尺寸是 5 * 5 像素):

 

    Photoshop 油画效果滤镜

 

    當到達貼片右側邊緣時,我們不是類似回車換行那樣重新復位到行首,而是把模板向下移動一行,進入下一條尾部,然後再向左平移,這樣一個模板的行進軌跡就成為一個蛇形迂迴步進的軌跡。當這樣改進以後,我們遍歷像素的時候就只需要處理模板的兩個邊緣像素。這樣,就把針對模板尺寸(參數中的半徑)從O(n^2)降低到O(n),從而使該演算法的運算速度大大提高,結合優化2.1 ,最終使演算法的運算速度大概提高了11 倍(該數值只是粗略估算,未經過大量樣本測試),優化後的演算法對大圖像的處理時間也是變得可以接受的。

 

    【注意】我能做到這樣的優化的原因是該濾鏡算法並不是標準的模板算法,它的本質是求模板範圍內的統計信息,即結果和像素的模板坐標無關。這就好像是我們想得到某個局部範圍的人口數,男女比例等資訊一樣。因此我們按以上方法進行優化。

 

    模板移動的軌跡是蛇形迂迴步進,例如:

 

    → → → → → → →

                            ↓

    ← ← ← ← ← ← ←

    ↓

    → → ...

 

    下面我將給出本濾鏡的核心演算法的程式碼,位於algorithm.cpp 中的全部程式碼:

 

    2.3 原有代碼對半徑的範圍限制是(1 ~ 5),由於我優化了程式碼,所以我把半徑的區間可以大大提高,我把半徑設定到100 時我發現半徑太大沒什麼意義,因為基本上已經看不出原圖是什麼了。

 

    【總結】改進後的程式碼的更具技巧性和挑戰性,包括大量底層的指針操作和不同矩形(輸入貼片,輸出貼片,模板)之間的坐標定位,代碼可讀性上可能略有降低,但只要理解上面的原理,程式碼依然是具有較好的可讀性的。此外,我還對該演算法的改進想到,把模板從矩形改為“圓形”,以及在遍歷圖像時,使模板半徑和桶數這兩個參數隨機抖動,但這些改進都會使2.2 中提到的最佳化失效,會使演算法的速度又降回較低的水平。

 

    (3)用多執行緒技術提高縮圖顯示效率,避免影響UI 執行緒的交互性

 

   教程  在參考的參數上顯示在略圖的參數之前參考圖中的第四篇文章,在此不再敘述。這裡我講解的是更新縮圖時對 UI 互動的改進,以及縮放平移技術。

    下圖是在 Photoshop 中呼叫此濾鏡時,彈出的參數設定對話框。使用者可以拖曳滑桿控制項(TrackBar,又稱 Slider),也可以直接在後面的文字方塊中輸入來改變參數。縮圖將實時性的更新已反應新參數。原來的濾鏡實作中,我把更新縮圖的處理放在和對話框UI的相同執行緒內。這樣做的話就會引入下面的問題,當用戶很快的拖動滑桿控制時,由於參數改變的速度很快,而UI 線程可能正忙於處理縮圖數據而短期被“阻塞”,使其不能立即回應後續的控制事件,即表現為滑桿控制的拖曳不夠流暢,有跳躍,頓挫,遲鈍感,對滑鼠拖曳的回饋不夠靈敏。

 

    

 

    為了改進該問題,不影響UI 執行緒完成執行緒在完成的處理縮圖時略圖對話方塊更新其視圖。當拖曳 Trackbar 時,UI 執行緒會以很快的頻率收到控制項通知,好像「浪湧」一樣,這要求後續到達的 UI 事件能讓正在執行的執行緒任務很快的中途中止並退出。

    我把濾鏡演算法提取出來作為一個共享的函數,這樣濾鏡的實際處理和更新縮圖可以共享這個函數。在 PS 實際呼叫濾鏡,以及更新縮圖期間,實際上都要求濾鏡演算法定期偵測「任務取消」事件。例如,當 PS 呼叫濾鏡時,如果使用者按下 ESC 鍵,就會立即放棄一個比較耗時的濾鏡操作。在更新縮圖時,如果發生 UI 事件的突波,同樣要求處理執行緒能夠迅速中止。

    在濾鏡的核心演算法函數中,我定期檢測「任務取消」事件,由於在PS 呼叫濾鏡時的測試取消和更新縮圖時測試取消的方法不同,因此在濾鏡演算法函數中,我增加了一個回呼函數參數(TestAbortProc)。這樣,在PS 呼叫濾鏡實際處理時,使用的是PS 內建的回調函數去偵測取消事件,在更新對話框的縮圖時,我用自己提供的一個回調函數來偵測取消事件(該函數偵測一個布爾變數來獲知是否有新的UI 事件等待處理)。

    縮圖的處理,我使用的是單線程。即每個新的UI 事件到來時,都要檢測縮圖處理線程是否正在運行,如果是,我置有新的UI 事件的標記,然後等待線程退出,等上一個線程退出後我才會啟動新的線程,這樣處理縮圖的線程永遠只有一個,而不會在UI 事件連續到來時開啟過多的線程,這樣做的好處是邏輯清晰,容易控制,不會讓我們陷入線程太多無法維護的麻煩之中。缺點是,儘管線程定期檢測取消事件,但線程中止還是需要少量時間的,這導致UI 線程依然可能存在微小的“停頓感”,但它是微不足道的,比起在UI 線程裡來更新縮圖已取得本質的提升。

    改進以後,可以用很快的速度拖曳參數對話框上的兩個滑竿,儘管這個濾鏡核心演算法的運算量較大,但我們能看到,參數對話框依然具有流暢的響應。

 

    (4)縮圖的縮放和平移功能

 

    其實不管縮放圖還是平移,更新縮放的資料本身並不難圖。難點主要在縮圖的平移,因為涉及滑鼠交互,這需要非常紮實的 windows 程式設計技巧和對 windows 程式底層機制的理解。 

    縮圖的拖曳有以下兩種方式:

 

    4.1 直接拖曳結果圖片。

    這又分為兩種方法。其一是比較完美的拖曳效果,但以浪費一定空間和時間為代價,編碼也具有一定挑戰性。即把縮圖的輸入資料外擴成 9 倍大小,並在記憶體中得到結果圖。顯示的時候僅僅顯示的是結果圖的中央部分。拖曳時,縮圖中不會出現空白部分。

    另一種方法是在拖曳時把當前結果圖進行快照(截圖),然後拖曳時,僅僅把截圖結果貼到螢幕對應位置上。這樣的效率較高,但缺點是拖曳時能看到縮圖旁邊有空白部分。這種方法常用語更新視圖的成本較大的情況,例如向量圖繪製等。我在這個濾鏡中實現的方法屬於這種方法。

 

    4.2 拖曳圖片為原始輸入圖片。

    即拖曳時,使用的圖片是原始數據,而不是結果圖片,這也是降低更新數據成本的一種折中方式。例如在 Photoshop 內建的濾鏡高斯模糊中,就是採用這種方法。當拖曳縮圖時,顯示的縮圖是原圖,僅在滑鼠釋放以後,才顯示成預覽效果。這樣做是比較經濟且有效的。因為我們要求原始資料的成本不高,但用濾鏡處理一次縮圖的成本較高。

    這裡額外提一點技術上的細節,要注意,由於鼠標可能移動到客戶區以外(成為負數),這時不能直接使用LOWORD ( lParam ) 和HIWORD ( lParam )  去獲得客戶區坐標(因為WORD是無符號數),使用前應該它們轉換成有符號數(short)。正確的方法是使用 windowsx.h 頭檔中的巨集:GET_X_LPARAM 和 GET_Y_LPARAM。

 

    (5)此濾鏡的下載連接(附件中含有我寫的PS 插件安裝工具,可簡化用戶安裝)

      插件 [該插件最近

    //我開發的PS 插件最新合集(含ICO,OilPaint,DrawTable 等)

            http://files.cnblogs.com/hoodlum1980/P〜3/P〜.  安裝後並重啟Photoshop 以後:

    在菜單:濾鏡- hoodlum1980 - OilPaint 中呼叫此濾鏡。

    在選單:幫助 - 關於增效工具 - OilPaint... 中可以看到關於對話框(和我開發的 ICO 文件格式插件的關於對話框的外觀幾乎一致)。

    在選單:幫助 - 系統資訊 中可以看到「OilPaint」一項是否已載入及其版本資訊。

 

    (6)一些不太重要的補充說明

 

    6.1 我採用的輸出貼片大小是128 *Photo 128   6.1 我採用的輸出貼片大小是128 *Photoshop 128*28 上的像素。的每一次步進表示完成了一個輸出貼片。輸入貼片通常大於等於輸出貼片,輸入貼片大小和濾鏡參數中的半徑是相關的(在四個方向上向外擴模板半徑的像素距離)。

    6.2 在濾鏡核心演算法中,為了提高對取消事件的靈敏度,在當前行中我每處理16個像素就檢測一次取消(行中像素索引 & 0x0F == 0x0F)。在每行處理結束後(列循環中)也偵測一次取消。但這個檢測頻率略顯過於頻繁了,過於頻繁可能會增加函數呼叫的成本開銷。

    6.3 採用相同影像,相同參數,我對我的濾鏡,FilterExplorer,PhotoSprite 三種軟體分別處理,然後再在 Photoshop 中比較。由於我的演算法是參考 FilterExplorer 的源碼,並在它的演算法上改進而來,因此我的演算法和 FilterExplorer 是等效的,只是效率更高,因此結果完全相同。但我的濾鏡以及FilterExplorer的結果,同 PhotoSprite 相比較整體效果非常接近,但結果有細微的不同。我查看了下 PhotoSprite 的程式碼發現,這是在圖像灰度化的演算法的差異造成的(當我把 PhotoSprite 的灰度化演算法調整為和 FilterExplorer 中相同後,處理結果就變成相同了)。

    在PhotoSprite 中,對像素灰度化所採用的方法是:
    gray = ( byte ) ( ( 19661 * R + 38666 * G + 7209 .  在 FilterExplorer / 我開發的濾鏡中,對像素灰階化所採用的方法是:

    gray = ( byte ) ( 0.3 * R + 0.59 * G + 0.11 * B ) ;

倠🀋〣中浮點〟〜〜〜〜〜〜〜〜〟〜〟〜〜〜〜〟〜〜〜〜〟〜〟〜〜〜〜〜〟〜〜〜、〟〜〜〟㟣㟜〜〟㟣㟜〜 㟜〜〟〜〜〜〜〟㟀㟜〜〼轉換成了整數乘法,效率可能會有一點點提高吧,但在此表現並不顯著。


 

    (7)參考資料

 

    7.1  FilterExplorer 原始碼。

    7.2  Photoshop 6.0 SDK Documents。

    7.3  FillRed 和 IcoFormat 插件原始碼,by hoodlum1980( myself )。

 

    (8)修正歷史

 

    8.01 [H] 固定記憶體的空間在「空間化」中,分配灰階圖大小的記憶體大小時,修復空間錯誤的記憶體在空間化時,分配錯誤。大小)的BUG。此 BUG 容易在以下條件下被觸發:文件尺寸太小,或半徑參數很小且光滑度參數很大,這些因素可能導致某個貼片過小。這時由於灰階桶空間的分配小於實際需求的大小,則可能後續程式碼發生記憶體越界,進而使 PS 進程意外終止。 2011-1-19  19:01。 

    8.02 [M] 新增縮圖縮放按鈕和功能,且優化了放大縮小按鈕處理時的程式碼,降低放大縮小時的閃爍感。 2011-1-19 19:06。

    8.03 [M] 新增縮圖滑鼠拖曳功能,且進一步調整了程式碼,使縮圖矩形固定下來,完全避免了縮放時的閃爍。 2011-1-19 23:50。

    8.04 [L] 新增功能,當滑鼠移到縮圖上和進行拖曳時,遊標變成伸開/抓住的手形。這是透過呼叫 PS 中的 Suite PEA UI Hooks suite 中的函數來實現的,即在縮圖上看到的是 PS 內部的遊標。 2011-1-20 1:23。

    8.05 [M] 修正在參數對話框上點選放大,縮小按鈕時,半徑參數折算的不正確的 BUG。此 BUG 使點擊放大縮小按鈕後,縮圖的顯示不準。 2011-1-20 1:55。

    8.06 [L] 把關於對話框上的網址連結調整為 SysLink 控件,這樣可以大大簡化關於對話框的視窗過程程式碼。 2011-1-20 18:12。

    8.07 [L] 更新插件安裝輔助工具,使它可以一次安裝多個插件。 2011-1-20 21:15。

    8.08 [L] 由於縮放縮圖時計算有誤差(原因不詳,可能是因為浮點運算誤差),可能會使靠近邊緣的右下角影像無法平移到縮圖視圖中,因此對平移範圍新增誤差緩衝。 2011-1-27。

    8.09 [L] 美化:把濾鏡參數對話框的放大縮小按鈕,改為使用 DirectUI 技術實現(新增一個類 CImgButton),其介面效果比用原始按鈕控制更好。 2011-2-14。

    8.10 [M] 性能:調整了插件在參數對話框時,調節半徑和光滑度參數的滑竿的交互性能。 2013-4-1。


更多Photoshop 油畫效果濾鏡 相關文章請關注PHP中文網!


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1657
14
CakePHP 教程
1415
52
Laravel 教程
1309
25
PHP教程
1257
29
C# 教程
1229
24
PS導出PDF如何設置密碼保護 PS導出PDF如何設置密碼保護 Apr 06, 2025 pm 04:45 PM

在 Photoshop 中導出帶密碼保護的 PDF:打開圖像文件。點擊“文件”>“導出”>“導出為 PDF”。設置“安全性”選項,兩次輸入相同的密碼。點擊“導出”生成 PDF 文件。

PS導出PDF有哪些常見問題 PS導出PDF有哪些常見問題 Apr 06, 2025 pm 04:51 PM

導出PS為PDF時常見問題及解決方法:字體嵌入問題:勾選"字體"選項,選擇"嵌入",或將字體轉換成曲線(路徑)。顏色偏差問題:將文件轉換成CMYK模式,並進行校色;直接用RGB導出需做好預覽和顏色偏差的心理準備。分辨率和文件大小問題:根據實際情況選擇分辨率,或使用壓縮選項優化文件體積。特殊效果問題:導出前將圖層合併(扁平化),或權衡利弊。

ps鋼筆工具怎麼用 ps鋼筆工具怎麼用 Apr 06, 2025 pm 10:15 PM

鋼筆工具是創建精確路徑和形狀的工具,使用方法為:選擇鋼筆工具(P)。設置路徑、填充、描邊和形狀選項。單擊創建錨點,拖動形成曲線,鬆開創建錨點。按 Ctrl/Cmd Alt/Opt 刪除錨點,拖動移動錨點,單擊調整曲線。單擊第一個錨點閉合路徑創建形狀,雙擊最後一個錨點創建開放路徑。

Photoshop的價值:權衡成本與其功能 Photoshop的價值:權衡成本與其功能 Apr 11, 2025 am 12:02 AM

Photoshop值得投資,因為它提供了強大的功能和廣泛的應用場景。 1)核心功能包括圖像編輯、圖層管理、特效製作和色彩調整。 2)適合專業設計師和攝影師,但業餘愛好者可考慮替代品如GIMP。 3)訂閱AdobeCreativeCloud可按需使用,避免一次性高額支出。

專業人士的Photoshop:高級編輯和工作流技術 專業人士的Photoshop:高級編輯和工作流技術 Apr 05, 2025 am 12:15 AM

Photoshop的高級編輯技巧包括頻率分離和HDR合成,優化工作流程可通過自動化實現。 1)頻率分離技術分離圖像的紋理和顏色細節。 2)HDR合成增強圖像的動態範圍。 3)自動化工作流程提高效率並確保一致性。

PS一直顯示正在載入是什麼原因? PS一直顯示正在載入是什麼原因? Apr 06, 2025 pm 06:39 PM

PS“正在載入”問題是由資源訪問或處理問題引起的:硬盤讀取速度慢或有壞道:使用CrystalDiskInfo檢查硬盤健康狀況並更換有問題的硬盤。內存不足:升級內存以滿足PS對高分辨率圖片和復雜圖層處理的需求。顯卡驅動程序過時或損壞:更新驅動程序以優化PS和顯卡之間的通信。文件路徑過長或文件名有特殊字符:使用簡短的路徑和避免使用特殊字符。 PS自身問題:重新安裝或修復PS安裝程序。

高級Photoshop教程:大師修飾和合成 高級Photoshop教程:大師修飾和合成 Apr 17, 2025 am 12:10 AM

Photoshop的高級修圖與合成技術包括:1.使用圖層、蒙版和調整層進行基礎操作;2.通過調整圖像像素值實現修圖效果;3.利用多圖層和蒙版進行複雜合成;4.應用“液化”工具調整面部特徵;5.使用“頻率分離”技術進行細膩修圖,這些技術能提升圖像處理水平並實現專業級效果。

如何加快PS的載入速度? 如何加快PS的載入速度? Apr 06, 2025 pm 06:27 PM

解決 Photoshop 啟動慢的問題需要多管齊下,包括:升級硬件(內存、固態硬盤、CPU);卸載過時或不兼容的插件;定期清理系統垃圾和過多的後台程序;謹慎關閉無關緊要的程序;啟動時避免打開大量文件。

See all articles