Swift函式式程式設計二(封裝Core Image)

2021-09-11 08:26:07 字數 3678 閱讀 2642

core image是乙個強大的影象處理框架,但是api略顯笨拙。它的api是弱型別的,通過鍵值編碼(kvc)來配置影象濾鏡(filter)的,在使用引數的型別或名字時,都使用字串來進行表示,這十分容易出錯,極有可能導致執行時錯誤。因此打算利用型別來規避這些問題,最終實現一組型別安全且高度模組化的api。

cifilter是core image的核心類之一,用於建立濾鏡。幾乎總是通過kciinputimagekey鍵提供輸入影象來例項化cifilter,再通過kcioutputimagekey鍵取回處理後的影象。取回的結果可以作為下乙個濾鏡的輸入值。嘗試分裝應用這些鍵值對的細節,從而提供乙個強型別的api。於是將filter定義為乙個函式,該函式接受乙個影象作為引數並返回乙個新影象。將在這個型別的基礎上進行後續的構建:

/// 濾鏡

typealias filter = (ciimage) -> ciimage

已經定義了filter型別,於是就可以定義函式來構建特定的濾鏡了。這些函式接受特定濾鏡所需的引數後,構造並返回乙個filter型別的值。

1、高斯模糊

高斯模糊很簡單只需要半徑這乙個引數。這個函式返回乙個新函式,新函式接受ciimage型別的引數並返回乙個新的ciimage物件。返回值符合之前定義的filter型別(ciimage -> ciimage)。

/// 高斯模糊濾鏡

////// - parameter radius: 半徑

/// - returns: 高斯模糊濾鏡

func gaussianblur(radius: double) -> filter

guard let outputimage = filter.outputimage else

return outputimage

}}

2、顏色疊加

建立乙個可以在影象上覆蓋純色疊層的濾鏡,coreimage不包括這樣的濾鏡,但是可以用已經存在的濾鏡來組成。

將使用兩個基礎濾鏡:顏色生成(ciconstantcolorgenerator)與覆蓋合成(cisourceovercompositing)。

下面這段**與高斯模糊相似,有乙個區別就是顏色生成不檢測輸入影象。因此不需要給函式中的影象引數命名,用_來強調引數被忽略。

/// 顏色生成濾鏡

////// - parameter color: 顏色

/// - returns: 顏色生成濾鏡

func colorgenerator(color: cicolor) -> filter

guard let outputimage = filter.outputimage else

return outputimage

}}

下面定義合成濾鏡,這裡將影象裁剪為輸入影象一致的尺寸,這並不是必須的只是為了展示效果。

/// 合成濾鏡

////// - parameter overlay: 前景層

/// - returns: 合成濾鏡

func compositesourceover(overlay: ciimage) -> filter

guard let outputimage = filter.outputimage else

return outputimage.cropped(to: image.extent)

}}

最後建立顏色疊層濾鏡,首先呼叫colorgenerator函式返回乙個濾鏡filter,再執行濾鏡得到乙個ciimage新疊層。與此類似,返回值由compositesourceover(overlay)構成的濾鏡和被作為引數的ciimage顏色疊層。

/// 顏色疊層濾鏡

////// - parameter color: 顏色

/// - returns: 顏色疊層濾鏡

func coloroverlay(color: cicolor) -> filter

}

到目前為止已經定義了高斯模糊與顏色疊層濾鏡,可以先模糊再疊一層顏色。

/// 組合濾鏡

func combine() -> filter

}

可以將上面兩個濾鏡呼叫表示式合併為一體:

coloroverlay(color: color)(gaussianblur(radius: radius)(image))
但是由於括號錯綜複雜,這些**失去了可讀性。更好的解決方案是定義運算子來組合濾鏡,首先定義乙個組合濾鏡的函式:

func composefilters(filter1: @escaping filter, filter2: @escaping filter) -> filter 

}

composefilters函式接受兩個filter引數,並返回乙個新的filter濾鏡。這個新濾鏡接受乙個ciimage引數並傳遞給filter1,再將取得的返回值ciimage傳遞給filter2。如此便可以定義復合函式:

composefilters(filter1: gaussianblur(radius: radius), filter2: coloroverlay(color: color))
為了讓**更具可讀性,可以引入運算子。雖然隨意定義運算子並不一定能提公升**可讀性,但是影象處理庫中,濾鏡的組合是乙個反覆被討論的問題,所以引入運算子極有意義:

precedencegroup filterprecedence 

infix operator >>>: filterprecedence

func >>>(filter1: @escaping filter, filter2: @escaping filter) -> filter

}

與composefilters方法相同,現在可以使用運算子達到目的:

gaussianblur(radius: radius) >>> coloroverlay(color: color)
運算子》是左結合的,濾鏡將從左到右的順序被應用到影象上。

組合濾鏡運算子是乙個符合函式的例子。數學上兩個函式f、g構成復合函式被寫作f·g,表示的新函式將輸入引數x對映到f(g(x))上。除了順序這恰恰也是》運算子所做的:將ciimage引數傳遞給》運算子操作的兩個filter濾鏡函式。

定義接受兩個引數的函式的兩種方法:

func add1(x: int, y: int) -> int 

var result1 = add1(x: 1, y: 2)

func add2(x: int) -> (int) -> int

}var result2 = add2(x: 1)(2)

方法一將兩個引數同時傳遞給add1;方法二先向函式add2傳遞乙個引數,然後向其返回的函式傳遞第二個引數。這兩個版本完全等價。

add1和add2展示了如何將接受多個引數的函式變為只接受乙個引數的函式,這個過程被稱為柯里化,將add2稱為add1的柯里化版本。

函式柯里化,給了呼叫者更多的選擇,可以用乙個、兩個……引數來呼叫。

把定義濾鏡的函式進行柯里化,有利於使用《運算子進行組合。

coreimage框架已經非常成熟,幾乎能提供所有需要的功能,儘管如此。這麼設計api也有一定的優勢:

二 封裝json輸出

controller類有兩種返回值 rest api json 輸出頁面 這裡對json輸出結果result做封裝 成功時返回code 0,msg success 和資料 失敗時返回錯誤碼和錯誤資訊 public class result private result codemsg cm 成功時的...

java物件導向(二) 封裝

參考形象例子 封裝把不需要暴露的成員變數隱藏起來,對外進行合理的暴露,這樣做的目的是保證業務的安全性。1.通過關鍵字private來修飾成員變數。被private修飾的成員變數,只能在本類當中訪問 2.如果想要對外開放,通過public設定對應的方法,如getter和setter方法。public ...

Javascript 物件導向(二)封裝

寫個小例子 第一步 做乙個 手機的類 var mobilephone function 第二步 考慮這個類,裡需要那些類的私有屬性,這裡我想定義的是例項出來手機的數量 var mobilephone function 第三步 建立乙個建構函式,即例項時候,對產生的新象的乙個初始化,例如屬性,方法的初...