基於ArkUI開發框架,圖片馬賽克處理的實現
阿新 • • 發佈:2022-05-31
關於馬賽克
馬賽克是一種使用較為廣泛的圖片處理方式,通過將圖片特定區域的色階細節劣化、色塊打亂讓圖片模糊化,常用來遮擋圖片中的重要資訊及隱私內容。本期,我們將通過影象的基礎知識幫助大家瞭解圖片馬賽克處理的原理,同時給大家帶來ArkUI開發框架中圖片馬賽克處理的實現。
一、影象基礎
瞭解圖片的畫素以及解析度等基礎知識,有助於後文對馬賽克原理的理解。
1. 畫素
畫素(英文名:pixel,簡稱px)是圖片的最小單位,每張圖片都是由無數的畫素點組成。如圖1所示,每個小方格就是一個個的畫素點,每個畫素點都具有明確的位置座標和色彩數值,畫素點的位置和顏色共同決定該圖片所呈現出來的樣子。
圖1 畫素點
在計算機中,每個畫素點的色彩數值都是通過RGB通道來控制,RGB即三原色:紅Red,綠Green,藍Blue的通道,這三種色彩混合疊加,幾乎能形成人類視力所能感知的所有顏色。由此,設定圖片中每個畫素的RGB通道分量值,並根據特有的演算法或者濾波器,便可讓畫素呈現任何顏色。
圖2 光學三原色
2. 解析度
解析度是圖片在長和寬上各擁有的畫素,解析度越高,所包含的畫素就越多,圖片就越清晰。如圖3所示,是一張解析度為12*14的圖片,由橫向12個畫素點和縱向14個畫素點構成,共包含了12*14個畫素點。不難發現,由於解析度比較低,我們甚至無法辨別圖片的內容。
圖3 低解析度圖片
如圖4所示,通過不斷增大圖片的解析度,不難看出,圖片的清晰度越來越高。
圖4 解析度的變化
二、馬賽克原理
增大圖片的解析度可以讓圖片變得更清晰,那麼我們是不是可以降低圖片的解析度來讓圖片變模糊?
馬賽克的原理就是降低原圖片的解析度。如圖5所示,首先我們將原圖分割成若干個大小一致的小方格,然後獲取每個小方格中的畫素點的平均色彩數值,最後使用獲取到的平均色彩數值替換該方格中所有的畫素點,即可實現圖片的馬賽克處理。
圖5 馬賽克原理
同時,我們還可以控制圖片中小方格的個數來實現馬賽克的強弱,如圖6所示。
圖6 馬賽克強弱控制
三、馬賽克實現
相信大家已經熟悉了馬賽克的原理,下面我們將以全馬賽克圖片為例,為大家介紹基於ArkUI開發框架的馬賽克的具體實現。
1. 首先我們需獲取ArkUI開發框架的image能力,該能力提供了圖片開發的基本介面。
import image from "@ohos.multimedia.image"2. 通過readPixelsToBuffer介面,一次性讀取圖片中所有的畫素點資料,每個畫素點資料都包含了RGB通道的分量值(如Red:18、Green:250、Blue:20)
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber()); await bitmap.readPixelsToBuffer(bufferData);其中ArrayBuffer裡面快取的畫素點資料主要包括RGB通道的分量值及圖片透明度,參考程式碼如下:
for (let index = 0; index < dataArray.length; index += 4) { const r = dataArray[index]; const g = dataArray[index+1]; const b = dataArray[index+2]; const a = dataArray[index+3]; }
3. 根據自定義的單個小方格的Width和Height,將整個圖片分成若干小方格。
//橫排的正方形個數 var x_index = Math.floor(targetWidth / realPixel_W); //縱排的正方形個數 var y_index = Math.floor(targetHeight / realPixel_H);
4. 獲取每個小方格左上角的最大座標及右下角的最小座標,以確定小方格的區域。並根據每個小方格內的所有畫素點資料統一該區域的畫素,統一方式可以是取該區域內畫素點的平均值,或者隨機選取一個畫素。 參考程式碼如下:
for (let ch = 0; ch < y_index; ch++) { for (let cw = 0; cw < x_index; cw++) { let max_x = (cw + 1) * realPixel_W > targetWidth ? targetWidth : (cw + 1) * realPixel_W; let max_y = (ch + 1) * realPixel_H > targetHeight ? targetHeight : (ch + 1) * realPixel_H; let min_x = cw * realPixel_W; let min_y = ch * realPixel_H; //取左上角的畫素值 let center_p = inPixels[min_y+1][min_x+1]; //設定該正方形裡的畫素統一 for (let zh = min_y; zh < max_y; zh++) { for (let zw = min_x; zw < max_x; zw++) { inPixels[zh][zw] = center_p; } } } }
5. 通過writeBufferToPixels介面,將統一的畫素點資料快取到ArrayBuffer中,並寫入PixelMap,由此得到整張馬賽克處理的圖片。
writeBufferToPixels(src: ArrayBuffer): Promise<void>
四、塗鴉馬賽克 通過上文的介紹,相信大家已經基本掌握了馬賽克的實現。下面我們將為大家帶來馬賽克開發的具體例項“塗鴉馬賽克”,即可以根據手指滑動的軌跡,生成對應的馬賽克區域。本文僅提供實現思路及關鍵程式碼,感興趣的小夥伴可結合上文的介紹補全程式碼。 1. 給圖片新增Touch事件,獲取手指的運動軌跡。參考程式碼如下:
Image(this._mCropPixelMap.pixelMap) .width(300) .height(300) .margin(10) .objectFit(ImageFit.Contain) .onTouch(event => { let array: TouchObject[] = event.changedTouches; for (let i = 0;i < array.length; i++) { //觸控的x y座標 let centX = array[i].x; let centY = array[i].y; } });2. 根據運動軌跡,以觸控點的座標(x,y)為中心,根據自定義小方格的大小,動態確認馬賽克區域的位置。參考程式碼如下:
//獲取到左上角的座標 let offMinX = Math.floor(centerX - pixel / 2); let offMinY = Math.floor(centerY - pixel / 2); //右下角的座標 let offMaxX = Math.floor(centerX + pixel / 2); let offMaxY = Math.floor(centerY + pixel / 2); offMinX = offMinX < 0 ? 0 : offMinX; offMinY = offMinY < 0 ? 0 : offMinY; offMaxX = offMaxX > targetWidth ? targetWidth : offMaxX; offMaxY = offMaxY > targetHeight ? targetHeight : offMaxY;
3. 統一馬賽克區域的所有的畫素點值。
//取左上角的畫素值 let center_p = PixelExampleUtils.inPixels[offMaxY+1][offMaxX+1]; //設定該正方形裡的畫素統一 for (let zh = offMinY; zh < offMaxY; zh++) { for (let zw = offMinX; zw < offMaxX; zw++) { PixelExampleUtils.inPixels[zh][zw] = center_p; changeArray[zh][zw] = center_p; } }
4. 最後將更改的畫素點寫入圖片中,即可得到手指滑動軌跡的馬賽克圖片。 以上就是本期全部內容,恭喜你花幾分鐘時間獲得了一個實用的技能。期待廣大開發者能開發出更多有趣的馬賽克應用。