胡奇超,王贈(zèng)凱,易文亮,盧奇
(嘉興學(xué)院數(shù)理與信息工程學(xué)院,嘉興 314001)
調(diào)查研究發(fā)現(xiàn),年齡在4-7 歲的兒童富于想象力和創(chuàng)造力,特別喜歡隨時(shí)隨地勾畫(huà)周邊的感興趣物體。這個(gè)階段的孩子大部分并不掌握基本的繪畫(huà)技巧,實(shí)際表現(xiàn)就是在紙上或墻上隨意涂畫(huà)。而很多家長(zhǎng)并不能在繪畫(huà)方面給予孩子很好的指導(dǎo),他們不擅長(zhǎng)將身邊看到的任何意思的物體通過(guò)寥寥幾筆勾勒出來(lái)。雖然網(wǎng)絡(luò)上有一些特定物體的簡(jiǎn)筆畫(huà)圖案供家長(zhǎng)和孩子學(xué)習(xí)參考,但卻無(wú)法滿足家長(zhǎng)和孩子在任意時(shí)間對(duì)任意場(chǎng)景中任意物體的簡(jiǎn)筆畫(huà)圖案的需求。作為計(jì)算機(jī)應(yīng)用領(lǐng)域中的一個(gè)重要技術(shù),圖像處理技術(shù)能夠?qū)?shù)字圖像進(jìn)行分析、處理和變換,從中抽取出用戶感興趣的東西。基于此,本文試圖利用圖像處理技術(shù)實(shí)現(xiàn)一個(gè)能夠自動(dòng)生成感興趣物體簡(jiǎn)筆畫(huà)圖案的移動(dòng)端軟件,最大程度地滿足家長(zhǎng)和孩子對(duì)簡(jiǎn)筆畫(huà)圖案的需求。
所謂簡(jiǎn)筆畫(huà),就是用簡(jiǎn)單的線條來(lái)勾勒出物體的基本特征,簡(jiǎn)筆畫(huà)繪制已成為非真實(shí)感繪制研究領(lǐng)域的一個(gè)重要組成部分[1]。目前最常見(jiàn)的生成簡(jiǎn)筆畫(huà)的做法是將源圖像轉(zhuǎn)化成灰度圖像,再對(duì)灰度圖像進(jìn)行平滑、銳化圖像增強(qiáng)處理,然后在此基礎(chǔ)上對(duì)增強(qiáng)后的圖像進(jìn)行邊緣檢測(cè)[2-5]、邊緣細(xì)化、輪廓提取[6-8],對(duì)得到的輪廓圖進(jìn)行分層處理,最后利用LIC 算法模擬產(chǎn)生鉛筆紋理,從而完成圖像的簡(jiǎn)筆畫(huà)風(fēng)格[9]。傳統(tǒng)的做法中,使用Canny 邊緣檢測(cè)[4]具有定位準(zhǔn)、精度高的優(yōu)點(diǎn);使用圖層的劃分技術(shù)和LIC 算法,能夠較為真實(shí)的達(dá)到簡(jiǎn)筆畫(huà)繪制的效果。但也存在一定的缺點(diǎn),例如傳統(tǒng)的Canny 邊緣檢測(cè)算法忽略了圖像的色彩信息、人為設(shè)定上下閾值等,這些缺陷導(dǎo)致檢測(cè)結(jié)果中包含了假邊緣或是丟失了某些真實(shí)邊緣[10-11],以及LIC 算法需要對(duì)各個(gè)像素進(jìn)行卷積,計(jì)算量相對(duì)較大,比較費(fèi)時(shí)。
本文就如何利用計(jì)算機(jī)圖像處理技術(shù)開(kāi)發(fā)基于Android 的“易拍畫(huà)”軟件進(jìn)行論述。“易拍畫(huà)”軟件通過(guò)對(duì)手機(jī)拍攝對(duì)照片或網(wǎng)上下載的圖片,實(shí)現(xiàn)對(duì)彩色圖像進(jìn)行簡(jiǎn)筆畫(huà)風(fēng)格轉(zhuǎn)換,得到只具有原圖像輪廓的簡(jiǎn)筆畫(huà)。這種簡(jiǎn)筆畫(huà)正適合兒童模仿創(chuàng)造,解決了家長(zhǎng)在對(duì)兒童進(jìn)行繪畫(huà)指導(dǎo)中可能會(huì)碰到的問(wèn)題。
圖片簡(jiǎn)筆畫(huà)方案的生成可以利用計(jì)算機(jī)圖像處理中的輪廓檢測(cè)技術(shù)進(jìn)行自動(dòng)檢測(cè),其步驟如圖1 所示。
圖1 輪廓檢測(cè)步驟
首先獲取源圖像,對(duì)源圖像進(jìn)行灰度處理,對(duì)得到的灰度圖像進(jìn)行邊緣檢測(cè),其中邊緣檢測(cè)步驟包括圖像平滑處理、計(jì)算梯度值與方向、非極大值抑制、雙閾值檢測(cè)連接;最后是輪廓提取,得到輪廓輸出圖像。
灰度化處理是將彩色數(shù)字圖像轉(zhuǎn)化為灰度圖像的過(guò)程。彩色數(shù)字圖像的每一個(gè)像素點(diǎn)都是由紅、藍(lán)、綠三個(gè)通道組成,分別對(duì)這三個(gè)通道每個(gè)分量分配不同的比重就可以產(chǎn)生世界上所有的顏色。在圖像的RGB模型中,當(dāng)R=G=B 時(shí),表示為一種灰度顏色,其中R=G=B 的值叫做圖像的灰度值,將圖像進(jìn)行灰度化處理本質(zhì)上就是使彩色圖像的R,G,B 分量值相等的過(guò)程?;叶然幚矸椒╗12]有平均值法,最大值法和加權(quán)平均值法。本文使用基于OpenCV 的圖像灰度化處理,其函數(shù)原型是 CV_EXPORTS_W void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0),參數(shù)含義如表1 所示。
表1 cvtColor 函數(shù)參數(shù)說(shuō)明
邊緣檢測(cè)是圖像處理的重要操作,是對(duì)圖像進(jìn)行分割和對(duì)象特征提取的關(guān)鍵步驟。當(dāng)一個(gè)像素點(diǎn)的四周像素灰度發(fā)生階躍性變化時(shí),則把這種像素點(diǎn)的集合叫做邊緣。邊緣檢測(cè)的算法眾多,而Canny 算子由于其在抑制噪聲和檢測(cè)邊緣之間能夠取得較好的平衡,因而被廣泛應(yīng)用。用Canny 算子得到邊緣點(diǎn)的具體算法步驟如下所示:
(1)平滑處理
噪聲對(duì)邊緣檢測(cè)的算法效果影響很大,需要使用濾波器對(duì)圖像進(jìn)行降噪處理。常用的濾波器有均值濾波器、中值濾波器和高斯濾波器。由于高斯濾波器對(duì)去除服從正態(tài)分布的噪聲十分有效,對(duì)于去除高斯噪聲也有很好的效果。本文采用高斯濾波器對(duì)圖像進(jìn)行平滑處理,具體使用OpenCV 的GaussianBlur 函數(shù)進(jìn)行濾波,函數(shù)原型是void GaussianBlur(Mat src, Mat dst,Size ksize, double sigmaX, double sigmaY, int border-Type),參數(shù)說(shuō)明如表 2。
表2 GaussianBlur 函數(shù)參數(shù)說(shuō)明
(2)計(jì)算梯度幅值與方向
平滑后的圖像使用3×3 的一階有限差分進(jìn)行圖像的梯度幅值與方向計(jì)算。圖像的邊緣有不同方向的指向,Canny 算子用了四個(gè)梯度算子分別計(jì)算水平、垂直和對(duì)角線方向的梯度。要計(jì)算水平和垂直方向的差分Gx和Gy,可以使用邊緣差分算子進(jìn)行計(jì)算,計(jì)算梯度模和方向的公式如下,Gx,Gy分別代表x,y方向的梯度,θ代表梯度角度:
梯度角度θ的范圍為-π到π,把它近似到四個(gè)方向,分別代表水平,垂直和兩個(gè)對(duì)角線方向(0°,45°,90°,135°)。以 ±iπ/8(i=1,3,5,7)分割,給每個(gè)區(qū)域中下降的梯度角一個(gè)特定值,以表示四個(gè)方向之一。
(3)非極大值抑制
Canny 算子針對(duì)梯度幅值進(jìn)行非極大值抑制。通過(guò)檢測(cè)同一梯度方向上每個(gè)像素點(diǎn)的梯度幅值,判斷其是否為局部最大值。如果該點(diǎn)的梯度幅值不是最大值,則對(duì)應(yīng)的灰度值將被設(shè)置為0,如此大多數(shù)非邊緣點(diǎn)就可以被移除。如果該點(diǎn)的梯度幅值是最大值,它將被保留為邊緣點(diǎn)。
(4)滯后閾值處理
要確定圖像的哪些邊界才是真正的邊界。如圖2所示,需要設(shè)置兩個(gè)閾值:minVal 和maxVal,當(dāng)圖像的灰度梯度高于maxVal 時(shí)被認(rèn)為是真的邊界,而低與minVal 的則被拋棄。如果介于兩者之間的話,則判斷這個(gè)點(diǎn)是否與某個(gè)被確定為真正邊界的點(diǎn)相連,如果是就認(rèn)為這個(gè)點(diǎn)是邊界點(diǎn),如果不是就拋棄。
圖2 滯后閾值示意圖
A 高于閾值maxVal 所以是真正的邊界點(diǎn),C 介于maxVal 與minVal 之間并與A 相連,所以也被認(rèn)為是真正的邊界點(diǎn)。而B(niǎo) 就會(huì)被拋棄,其低于maxVal 且不與真正的邊界點(diǎn)相連。所以選擇合適的maxVal 和min-Val 對(duì)于能否取得好的邊緣十分重要。
輪廓簡(jiǎn)單來(lái)說(shuō)就是一系列邊緣的集合,通過(guò)對(duì)一系列的邊緣進(jìn)行組合就可以得到一個(gè)完整的輪廓。用Canny 邊緣檢測(cè)算子對(duì)二值化后的圖像進(jìn)行處理后,得到只含邊緣的二值圖像。通過(guò)基于OpenCV 的find-Contours 函數(shù)對(duì)得到的只含邊緣的二值化圖像進(jìn)行輪廓提取,再通過(guò)drawContours 函數(shù)就可將輪廓繪制出來(lái)得到了輪廓圖。findContours 函數(shù)原型是void find-Contours(InputOutputArray image, OutputArrayOfArrays contours,OutputArray hierarchy, int mode,int method,Point offset=Point()),參數(shù)說(shuō)明如表3。
drawContours 函數(shù)原型 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())是,參數(shù)說(shuō)明如表4。
表3 findContours 函數(shù)參數(shù)說(shuō)明
表4 drawContours 函數(shù)參數(shù)說(shuō)明
本文在基于傳統(tǒng)做法基礎(chǔ)上做出了一定的改進(jìn)。在傳統(tǒng)的Canny 邊緣檢測(cè)算法的基礎(chǔ)上,進(jìn)行了對(duì)梯度幅值進(jìn)行非極大值抑制;用雙閾值算法檢測(cè)和連接邊緣等操作提升了效果。具體使用的圖像處理操作基于 OpenCV 開(kāi)源庫(kù)[13-14]。
本文實(shí)現(xiàn)一個(gè)基于Android 移動(dòng)端的“易拍畫(huà)”軟件,主要功能為將彩色圖像轉(zhuǎn)簡(jiǎn)筆畫(huà)風(fēng)格圖像[15-16]。將通過(guò)拍照或下載得到的源圖像進(jìn)行灰度化處理,將得到的灰度圖像通過(guò)Canny 邊緣檢測(cè)算法對(duì)其進(jìn)行模糊、去噪得到邊緣圖像,在得到的邊緣圖像的基礎(chǔ)上提取其輪廓,然后對(duì)圖像進(jìn)行分層處理,提出了適用于圖層的白噪聲生成方法,最后采用快速積分卷積(FLIC)替代傳統(tǒng)線積分卷積)LIC)進(jìn)行模擬紋理[17],并將各層結(jié)果以及圖像輪廓進(jìn)行疊加生成簡(jiǎn)筆畫(huà)[18-20]。軟件的功能架構(gòu)如圖3 所示。
圖3“易拍畫(huà)“軟件的功能架構(gòu)
“易拍畫(huà)”軟件包括4 個(gè)主要功能。本地相冊(cè)選圖:用戶通過(guò)選擇本地相冊(cè)的圖片,裁剪后作為簡(jiǎn)筆畫(huà)的原圖像。拍照取圖:用戶啟動(dòng)手機(jī)的相機(jī)拍照,拍完照片后裁剪,作為簡(jiǎn)筆畫(huà)的原圖像。簡(jiǎn)筆畫(huà)生成:基于OpenCV 開(kāi)源庫(kù)對(duì)用戶選擇的圖像進(jìn)行處理后得到簡(jiǎn)筆畫(huà)。保存簡(jiǎn)筆畫(huà):將生成的鉛筆畫(huà)保存到系統(tǒng)目錄下。
功能描述:此功能按鈕通過(guò)用戶直接選擇相冊(cè)中的圖片以便進(jìn)行之后的裁剪并簡(jiǎn)筆畫(huà)操作。
實(shí)現(xiàn)方法:checkReadPermission()是處理執(zhí)行時(shí)的權(quán)限的邏輯的函數(shù),判斷是否被授權(quán),授權(quán)時(shí)直接進(jìn)行操作,未授權(quán)時(shí)根據(jù)請(qǐng)求結(jié)果進(jìn)行處理。請(qǐng)求處理結(jié)果在onRequestPermissonsResult()函數(shù)中。這里,執(zhí)行權(quán)限申請(qǐng)按組處理,即屬于同一組的權(quán)限要求相同,如果用戶授權(quán)一個(gè)權(quán)限,同一組的權(quán)限也同時(shí)授權(quán)。SD 卡的讀寫(xiě)都屬于STORAGE 組,所以在申請(qǐng)SD 卡的讀寫(xiě)權(quán)限的時(shí)候申請(qǐng)讀寫(xiě)權(quán)限或者寫(xiě)權(quán)限就可以了。之后調(diào)用choseHeadImageFromGallery()函數(shù)處理Intent 的 Activity,請(qǐng)求碼是 CODE_GALLERY_REQUEST。
功能描述:此功能按鈕通過(guò)用戶拍照并顯示圖片以便進(jìn)行之后的裁剪并簡(jiǎn)筆畫(huà)操作。
實(shí)現(xiàn)方法:checkStoragePermission()函數(shù)同樣用于處理運(yùn)行時(shí)權(quán)限的邏輯,需要Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STOR -AGE 這兩個(gè)權(quán)限,判斷是否被授權(quán),授權(quán)時(shí)直接進(jìn)行操作,未授權(quán)時(shí)根據(jù)請(qǐng)求結(jié)果進(jìn)行處理。之后調(diào)用choseHeadImageFromCameraCapture()函數(shù)。addflags的作用是標(biāo)記Intent,允許Intent 啟動(dòng)的Activity 使用FileProvider 封裝的Uri。接著啟動(dòng)Activity,請(qǐng)求代碼為CODE_CAMERA_REQUEST。由此,完成拍攝請(qǐng)求,轉(zhuǎn)移到系統(tǒng)的拍攝接口,接著處理拍攝的照片。
從Android 7.0(SDK>=24)開(kāi)始,直接使用本地真實(shí)的URI 被認(rèn)為是不安全的,會(huì)拋出一個(gè)FileUriExposedException 異常,需要使用 FileProvider 上封裝的URI。FileProvider 的使用:新建 provider_paths.xml,paths指定要使用的目錄,external-path 為SD 卡根目錄,接下來(lái),在AndroidManifest.xml 中注冊(cè)provider。grantU-riPermissions 設(shè)為true,以允許系統(tǒng)相機(jī)臨時(shí)使用此provider。authorities 與此前使用FileProvider 時(shí)一樣,exported 必須為false,否則將返回錯(cuò)誤。
功能描述:此功能用于將本地相冊(cè)選的圖片或拍照選的圖片進(jìn)行裁剪以達(dá)到用戶所期望的圖片。
實(shí)現(xiàn)方法:cropRawPhoto(Uri uri)函數(shù)參數(shù)為拍照或本地圖片得到的圖片的Uri,創(chuàng)建com.android.camera.action.CROP 的 Intent,通過(guò) intent.putExtra 方法設(shè)置裁剪的大小比例,然后將裁剪好的圖輸出到所建文件中,圖片裁剪完成后回調(diào)的是case CODE_RESULT_REQUEST 下 的 setImageToHeadView(Intent a,Bitmap b)方法提取保存裁剪之后的圖片數(shù)據(jù),并設(shè)置圖像部分的View。
intent.putExtra("return-data", false)函數(shù)參數(shù) return-data 應(yīng)設(shè)置為false,如果設(shè)置為true,那么裁剪后的圖像直接以Bitmap 形式緩存到內(nèi)存中,但Bitmap 相當(dāng)大,如果手機(jī)內(nèi)存不足或分配給手機(jī)的內(nèi)存不足,就會(huì)因OOM 問(wèn)題而閃退。
功能描述:此功能用于將生成的簡(jiǎn)筆畫(huà)保存到手機(jī)本地相冊(cè)。
實(shí)現(xiàn)方法:設(shè)置點(diǎn)擊監(jiān)聽(tīng)器setOnClickListener,用戶點(diǎn)擊后調(diào)用saveImage()方法,首先獲取ImageView,開(kāi)啟 DrawingCache,通過(guò) getDrawingCache 方法獲取ImageView 的Bitmap 格式的圖像并調(diào)用saveBitmap-File()方法保存獲取的圖像,關(guān)閉DrawingCache,顯示Toast“已保存”。saveBitmapFile()方法中獲取系統(tǒng)時(shí)間并賦給圖像名ImgName,new File("/sdcard/1StickFigure/")創(chuàng)建文件夾,new File("/sdcard/1StickFigure/"+ImgName+".jpg")將要保存圖片的路徑和圖片名稱,new FileOutputStream(file)保存到系統(tǒng)本地相冊(cè)。
“易拍畫(huà)”軟件的開(kāi)發(fā)環(huán)境為Android Studio 3.5.2,開(kāi)發(fā)語(yǔ)言是Java 語(yǔ)言,利用JDK1.8 和開(kāi)源圖像處理工具OpenCV 3.4.3。由于Android 6.0 引入了運(yùn)行時(shí)權(quán)限,用戶不必在安裝時(shí)授予所有權(quán)限,可以在使用到相關(guān)功能時(shí)再授權(quán)。
圖4 展示了“易拍畫(huà)”軟件界面,界面中間是用來(lái)顯示圖像的ImageView 控件,點(diǎn)擊本地相冊(cè)和拍照選圖按鈕,分別是拍照和相冊(cè)選擇圖片功能,其中都實(shí)現(xiàn)了照片的自動(dòng)裁剪。裁剪后的圖片通過(guò)ImageView 控件顯示。如圖4 所示,可見(jiàn)在背景較為簡(jiǎn)單的情況下,彩色圖像的輪廓能很好地繪制出來(lái),生成的輪廓完整清晰,無(wú)假邊緣,并且實(shí)際生成時(shí)間在1 秒之內(nèi),一定程度上滿足了用戶對(duì)簡(jiǎn)筆畫(huà)效果和等待時(shí)間的需求。
圖4 易拍畫(huà)軟件實(shí)現(xiàn)效果圖
我們分別用不同類型的圖片對(duì)本文輪廓檢測(cè)算法進(jìn)行來(lái)測(cè)試,其中部分實(shí)驗(yàn)效果如圖5 所示??梢钥吹讲煌瑘?chǎng)景下,輪廓效果都較為完整。但在背景較復(fù)雜、物體細(xì)節(jié)特征較多的情況下,輪廓的丟失以及細(xì)節(jié)處理方面都還需要進(jìn)一步改進(jìn)。
依據(jù)軟件的實(shí)際使用人群分別對(duì)四個(gè)年齡段的人群進(jìn)行調(diào)研打分,每組15 人分別打分,從邊緣檢測(cè)效果圖的邊緣完整性、邊緣準(zhǔn)確性、實(shí)際觀看效果三個(gè)方面對(duì)效果圖進(jìn)行了綜合評(píng)價(jià),表5 給出了評(píng)分依據(jù)。評(píng)分結(jié)果如表6 所示。
圖5 輪廓檢測(cè)示例
第一行是源圖像,第二行是檢測(cè)結(jié)果
表5 評(píng)分依據(jù)
另外,選取10 組親子家庭實(shí)際使用“易拍畫(huà)”軟件,在他們使用了一段時(shí)間后,分別從軟件的易用性、界面設(shè)計(jì)、性能上進(jìn)行評(píng)判,評(píng)判結(jié)果如表7 所示。
表6 評(píng)分結(jié)果表
表7 評(píng)分結(jié)果表
本文提出了利用圖像處理技術(shù)進(jìn)行簡(jiǎn)筆畫(huà)圖像生成的方法,并利用OpenCV 開(kāi)源庫(kù)實(shí)現(xiàn)了基于Android平臺(tái)“易拍畫(huà)”軟件。經(jīng)測(cè)試表明,所提出的方法可行,“易拍畫(huà)”軟件的實(shí)現(xiàn)效果能夠滿足用戶的基本需求,但仍然存在進(jìn)一步改進(jìn)的空間。可以通過(guò)使用不同場(chǎng)景下多樣的濾波來(lái)代替單一高斯濾波,來(lái)改進(jìn)Canny算子的邊緣檢測(cè)效果;在輪廓提取上可以使用輪廓近似來(lái)使輪廓更加完整。由于Android 手機(jī)的限制,簡(jiǎn)筆畫(huà)圖像生成速度也需進(jìn)一步改善;在具有復(fù)雜背景的輸入圖片情況下,簡(jiǎn)筆畫(huà)效果圖需要在輪廓精確性和簡(jiǎn)化輪廓層次兩個(gè)方面進(jìn)一步平衡和提升。