胡奇超,王贈凱,易文亮,盧奇
(嘉興學院數理與信息工程學院,嘉興 314001)
調查研究發現,年齡在4-7 歲的兒童富于想象力和創造力,特別喜歡隨時隨地勾畫周邊的感興趣物體。這個階段的孩子大部分并不掌握基本的繪畫技巧,實際表現就是在紙上或墻上隨意涂畫。而很多家長并不能在繪畫方面給予孩子很好的指導,他們不擅長將身邊看到的任何意思的物體通過寥寥幾筆勾勒出來。雖然網絡上有一些特定物體的簡筆畫圖案供家長和孩子學習參考,但卻無法滿足家長和孩子在任意時間對任意場景中任意物體的簡筆畫圖案的需求。作為計算機應用領域中的一個重要技術,圖像處理技術能夠對數字圖像進行分析、處理和變換,從中抽取出用戶感興趣的東西。基于此,本文試圖利用圖像處理技術實現一個能夠自動生成感興趣物體簡筆畫圖案的移動端軟件,最大程度地滿足家長和孩子對簡筆畫圖案的需求。
所謂簡筆畫,就是用簡單的線條來勾勒出物體的基本特征,簡筆畫繪制已成為非真實感繪制研究領域的一個重要組成部分[1]。目前最常見的生成簡筆畫的做法是將源圖像轉化成灰度圖像,再對灰度圖像進行平滑、銳化圖像增強處理,然后在此基礎上對增強后的圖像進行邊緣檢測[2-5]、邊緣細化、輪廓提取[6-8],對得到的輪廓圖進行分層處理,最后利用LIC 算法模擬產生鉛筆紋理,從而完成圖像的簡筆畫風格[9]。傳統的做法中,使用Canny 邊緣檢測[4]具有定位準、精度高的優點;使用圖層的劃分技術和LIC 算法,能夠較為真實的達到簡筆畫繪制的效果。但也存在一定的缺點,例如傳統的Canny 邊緣檢測算法忽略了圖像的色彩信息、人為設定上下閾值等,這些缺陷導致檢測結果中包含了假邊緣或是丟失了某些真實邊緣[10-11],以及LIC 算法需要對各個像素進行卷積,計算量相對較大,比較費時。
本文就如何利用計算機圖像處理技術開發基于Android 的“易拍畫”軟件進行論述。“易拍畫”軟件通過對手機拍攝對照片或網上下載的圖片,實現對彩色圖像進行簡筆畫風格轉換,得到只具有原圖像輪廓的簡筆畫。這種簡筆畫正適合兒童模仿創造,解決了家長在對兒童進行繪畫指導中可能會碰到的問題。
圖片簡筆畫方案的生成可以利用計算機圖像處理中的輪廓檢測技術進行自動檢測,其步驟如圖1 所示。

圖1 輪廓檢測步驟
首先獲取源圖像,對源圖像進行灰度處理,對得到的灰度圖像進行邊緣檢測,其中邊緣檢測步驟包括圖像平滑處理、計算梯度值與方向、非極大值抑制、雙閾值檢測連接;最后是輪廓提取,得到輪廓輸出圖像。
灰度化處理是將彩色數字圖像轉化為灰度圖像的過程。彩色數字圖像的每一個像素點都是由紅、藍、綠三個通道組成,分別對這三個通道每個分量分配不同的比重就可以產生世界上所有的顏色。在圖像的RGB模型中,當R=G=B 時,表示為一種灰度顏色,其中R=G=B 的值叫做圖像的灰度值,將圖像進行灰度化處理本質上就是使彩色圖像的R,G,B 分量值相等的過程。灰度化處理方法[12]有平均值法,最大值法和加權平均值法。本文使用基于OpenCV 的圖像灰度化處理,其函數原型是 CV_EXPORTS_W void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0),參數含義如表1 所示。

表1 cvtColor 函數參數說明
邊緣檢測是圖像處理的重要操作,是對圖像進行分割和對象特征提取的關鍵步驟。當一個像素點的四周像素灰度發生階躍性變化時,則把這種像素點的集合叫做邊緣。邊緣檢測的算法眾多,而Canny 算子由于其在抑制噪聲和檢測邊緣之間能夠取得較好的平衡,因而被廣泛應用。用Canny 算子得到邊緣點的具體算法步驟如下所示:
(1)平滑處理
噪聲對邊緣檢測的算法效果影響很大,需要使用濾波器對圖像進行降噪處理。常用的濾波器有均值濾波器、中值濾波器和高斯濾波器。由于高斯濾波器對去除服從正態分布的噪聲十分有效,對于去除高斯噪聲也有很好的效果。本文采用高斯濾波器對圖像進行平滑處理,具體使用OpenCV 的GaussianBlur 函數進行濾波,函數原型是void GaussianBlur(Mat src, Mat dst,Size ksize, double sigmaX, double sigmaY, int border-Type),參數說明如表 2。

表2 GaussianBlur 函數參數說明
(2)計算梯度幅值與方向
平滑后的圖像使用3×3 的一階有限差分進行圖像的梯度幅值與方向計算。圖像的邊緣有不同方向的指向,Canny 算子用了四個梯度算子分別計算水平、垂直和對角線方向的梯度。要計算水平和垂直方向的差分Gx和Gy,可以使用邊緣差分算子進行計算,計算梯度模和方向的公式如下,Gx,Gy分別代表x,y方向的梯度,θ代表梯度角度:

梯度角度θ的范圍為-π到π,把它近似到四個方向,分別代表水平,垂直和兩個對角線方向(0°,45°,90°,135°)。以 ±iπ/8(i=1,3,5,7)分割,給每個區域中下降的梯度角一個特定值,以表示四個方向之一。
(3)非極大值抑制
Canny 算子針對梯度幅值進行非極大值抑制。通過檢測同一梯度方向上每個像素點的梯度幅值,判斷其是否為局部最大值。如果該點的梯度幅值不是最大值,則對應的灰度值將被設置為0,如此大多數非邊緣點就可以被移除。如果該點的梯度幅值是最大值,它將被保留為邊緣點。
(4)滯后閾值處理
要確定圖像的哪些邊界才是真正的邊界。如圖2所示,需要設置兩個閾值:minVal 和maxVal,當圖像的灰度梯度高于maxVal 時被認為是真的邊界,而低與minVal 的則被拋棄。如果介于兩者之間的話,則判斷這個點是否與某個被確定為真正邊界的點相連,如果是就認為這個點是邊界點,如果不是就拋棄。

圖2 滯后閾值示意圖
A 高于閾值maxVal 所以是真正的邊界點,C 介于maxVal 與minVal 之間并與A 相連,所以也被認為是真正的邊界點。而B 就會被拋棄,其低于maxVal 且不與真正的邊界點相連。所以選擇合適的maxVal 和min-Val 對于能否取得好的邊緣十分重要。
輪廓簡單來說就是一系列邊緣的集合,通過對一系列的邊緣進行組合就可以得到一個完整的輪廓。用Canny 邊緣檢測算子對二值化后的圖像進行處理后,得到只含邊緣的二值圖像。通過基于OpenCV 的find-Contours 函數對得到的只含邊緣的二值化圖像進行輪廓提取,再通過drawContours 函數就可將輪廓繪制出來得到了輪廓圖。findContours 函數原型是void find-Contours(InputOutputArray image, OutputArrayOfArrays contours,OutputArray hierarchy, int mode,int method,Point offset=Point()),參數說明如表3。
drawContours 函數原型 void drawContours( Input-OutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color,int thickness = 1, int line-Type = LINE_8, InputArray hierarchy = noArray(),int maxLevel=INT_MAX,Point offset=Point())是,參數說明如表4。

表3 findContours 函數參數說明

表4 drawContours 函數參數說明
本文在基于傳統做法基礎上做出了一定的改進。在傳統的Canny 邊緣檢測算法的基礎上,進行了對梯度幅值進行非極大值抑制;用雙閾值算法檢測和連接邊緣等操作提升了效果。具體使用的圖像處理操作基于 OpenCV 開源庫[13-14]。
本文實現一個基于Android 移動端的“易拍畫”軟件,主要功能為將彩色圖像轉簡筆畫風格圖像[15-16]。將通過拍照或下載得到的源圖像進行灰度化處理,將得到的灰度圖像通過Canny 邊緣檢測算法對其進行模糊、去噪得到邊緣圖像,在得到的邊緣圖像的基礎上提取其輪廓,然后對圖像進行分層處理,提出了適用于圖層的白噪聲生成方法,最后采用快速積分卷積(FLIC)替代傳統線積分卷積)LIC)進行模擬紋理[17],并將各層結果以及圖像輪廓進行疊加生成簡筆畫[18-20]。軟件的功能架構如圖3 所示。

圖3“易拍畫“軟件的功能架構
“易拍畫”軟件包括4 個主要功能。本地相冊選圖:用戶通過選擇本地相冊的圖片,裁剪后作為簡筆畫的原圖像。拍照取圖:用戶啟動手機的相機拍照,拍完照片后裁剪,作為簡筆畫的原圖像。簡筆畫生成:基于OpenCV 開源庫對用戶選擇的圖像進行處理后得到簡筆畫。保存簡筆畫:將生成的鉛筆畫保存到系統目錄下。
功能描述:此功能按鈕通過用戶直接選擇相冊中的圖片以便進行之后的裁剪并簡筆畫操作。
實現方法:checkReadPermission()是處理執行時的權限的邏輯的函數,判斷是否被授權,授權時直接進行操作,未授權時根據請求結果進行處理。請求處理結果在onRequestPermissonsResult()函數中。這里,執行權限申請按組處理,即屬于同一組的權限要求相同,如果用戶授權一個權限,同一組的權限也同時授權。SD 卡的讀寫都屬于STORAGE 組,所以在申請SD 卡的讀寫權限的時候申請讀寫權限或者寫權限就可以了。之后調用choseHeadImageFromGallery()函數處理Intent 的 Activity,請求碼是 CODE_GALLERY_REQUEST。
功能描述:此功能按鈕通過用戶拍照并顯示圖片以便進行之后的裁剪并簡筆畫操作。
實現方法:checkStoragePermission()函數同樣用于處理運行時權限的邏輯,需要Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STOR -AGE 這兩個權限,判斷是否被授權,授權時直接進行操作,未授權時根據請求結果進行處理。之后調用choseHeadImageFromCameraCapture()函數。addflags的作用是標記Intent,允許Intent 啟動的Activity 使用FileProvider 封裝的Uri。接著啟動Activity,請求代碼為CODE_CAMERA_REQUEST。由此,完成拍攝請求,轉移到系統的拍攝接口,接著處理拍攝的照片。
從Android 7.0(SDK>=24)開始,直接使用本地真實的URI 被認為是不安全的,會拋出一個FileUriExposedException 異常,需要使用 FileProvider 上封裝的URI。FileProvider 的使用:新建 provider_paths.xml,paths指定要使用的目錄,external-path 為SD 卡根目錄,接下來,在AndroidManifest.xml 中注冊provider。grantU-riPermissions 設為true,以允許系統相機臨時使用此provider。authorities 與此前使用FileProvider 時一樣,exported 必須為false,否則將返回錯誤。
功能描述:此功能用于將本地相冊選的圖片或拍照選的圖片進行裁剪以達到用戶所期望的圖片。
實現方法:cropRawPhoto(Uri uri)函數參數為拍照或本地圖片得到的圖片的Uri,創建com.android.camera.action.CROP 的 Intent,通過 intent.putExtra 方法設置裁剪的大小比例,然后將裁剪好的圖輸出到所建文件中,圖片裁剪完成后回調的是case CODE_RESULT_REQUEST 下 的 setImageToHeadView(Intent a,Bitmap b)方法提取保存裁剪之后的圖片數據,并設置圖像部分的View。
intent.putExtra("return-data", false)函數參數 return-data 應設置為false,如果設置為true,那么裁剪后的圖像直接以Bitmap 形式緩存到內存中,但Bitmap 相當大,如果手機內存不足或分配給手機的內存不足,就會因OOM 問題而閃退。
功能描述:此功能用于將生成的簡筆畫保存到手機本地相冊。
實現方法:設置點擊監聽器setOnClickListener,用戶點擊后調用saveImage()方法,首先獲取ImageView,開啟 DrawingCache,通過 getDrawingCache 方法獲取ImageView 的Bitmap 格式的圖像并調用saveBitmap-File()方法保存獲取的圖像,關閉DrawingCache,顯示Toast“已保存”。saveBitmapFile()方法中獲取系統時間并賦給圖像名ImgName,new File("/sdcard/1StickFigure/")創建文件夾,new File("/sdcard/1StickFigure/"+ImgName+".jpg")將要保存圖片的路徑和圖片名稱,new FileOutputStream(file)保存到系統本地相冊。
“易拍畫”軟件的開發環境為Android Studio 3.5.2,開發語言是Java 語言,利用JDK1.8 和開源圖像處理工具OpenCV 3.4.3。由于Android 6.0 引入了運行時權限,用戶不必在安裝時授予所有權限,可以在使用到相關功能時再授權。
圖4 展示了“易拍畫”軟件界面,界面中間是用來顯示圖像的ImageView 控件,點擊本地相冊和拍照選圖按鈕,分別是拍照和相冊選擇圖片功能,其中都實現了照片的自動裁剪。裁剪后的圖片通過ImageView 控件顯示。如圖4 所示,可見在背景較為簡單的情況下,彩色圖像的輪廓能很好地繪制出來,生成的輪廓完整清晰,無假邊緣,并且實際生成時間在1 秒之內,一定程度上滿足了用戶對簡筆畫效果和等待時間的需求。

圖4 易拍畫軟件實現效果圖
我們分別用不同類型的圖片對本文輪廓檢測算法進行來測試,其中部分實驗效果如圖5 所示。可以看到不同場景下,輪廓效果都較為完整。但在背景較復雜、物體細節特征較多的情況下,輪廓的丟失以及細節處理方面都還需要進一步改進。
依據軟件的實際使用人群分別對四個年齡段的人群進行調研打分,每組15 人分別打分,從邊緣檢測效果圖的邊緣完整性、邊緣準確性、實際觀看效果三個方面對效果圖進行了綜合評價,表5 給出了評分依據。評分結果如表6 所示。

圖5 輪廓檢測示例
第一行是源圖像,第二行是檢測結果

表5 評分依據
另外,選取10 組親子家庭實際使用“易拍畫”軟件,在他們使用了一段時間后,分別從軟件的易用性、界面設計、性能上進行評判,評判結果如表7 所示。

表6 評分結果表

表7 評分結果表
本文提出了利用圖像處理技術進行簡筆畫圖像生成的方法,并利用OpenCV 開源庫實現了基于Android平臺“易拍畫”軟件。經測試表明,所提出的方法可行,“易拍畫”軟件的實現效果能夠滿足用戶的基本需求,但仍然存在進一步改進的空間。可以通過使用不同場景下多樣的濾波來代替單一高斯濾波,來改進Canny算子的邊緣檢測效果;在輪廓提取上可以使用輪廓近似來使輪廓更加完整。由于Android 手機的限制,簡筆畫圖像生成速度也需進一步改善;在具有復雜背景的輸入圖片情況下,簡筆畫效果圖需要在輪廓精確性和簡化輪廓層次兩個方面進一步平衡和提升。