1. 程式人生 > >Android中圖片壓縮分析(下)

Android中圖片壓縮分析(下)

一、Android 尺寸壓縮邏輯

針對圖片尺寸的修改其實就是一個影象重新取樣的過程,放大影象稱為上取樣(upsamping),縮小影象稱為下采樣(downsampling),這裡我們重點討論下采樣。

在 Android 中圖片重取樣提供了兩種方法,一種叫做鄰近取樣(Nearest Neighbour Resampling),另一種叫做雙線性取樣(Bilinear Resampling)

除了 Android 中這兩種常用的重取樣方法之外,還有另外比較常見的兩種:雙立方/雙三次取樣(Bicubic Resampling)Lanczos Resampling。除此之外,還有一些其他個人或機構發明的演算法 Hermite Resampling

Bell ResamplingMitchell Resampling。我們這裡著重介紹前面提到的四種取樣方法。

二、鄰近取樣(Nearest Neighbour Resampling)

Nearest Neighbour Resampling(鄰近取樣),是 Android 中常用的壓縮方法之一,我們先來看看在 Android 中使用鄰近取樣的示例程式碼:

BitmapFactory.Options options = new BitmapFactory.Options();
//或者 inDensity 搭配 inTargetDensity 使用,演算法和 inSampleSize 一樣
options.inSampleSize
= 2; Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.png"); Bitmap compress = BitmapFactory.decodeFile("/sdcard/test.png", options);

來看看鄰近取樣的圖片效果:

原圖  
  
處理之後的圖片

原圖是每個畫素紅綠相間的圖片,可以看到處理之後的圖片已經完全變成了綠色,接著我們來看看 inSampleSzie 的官方描述:

If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2.

從官方的解釋中我們可以看到 x(x 為 2 的倍數)個畫素最後對應一個畫素,由於取樣率設定為 1/2,所以是兩個畫素生成一個畫素。鄰近取樣的方式比較粗暴,直接選擇其中的一個畫素作為生成畫素,另一個畫素直接拋棄,這樣就造成了圖片變成了純綠色,也就是紅色畫素被拋棄。

鄰近取樣採用的演算法叫做鄰近點插值演算法。

三、雙線性取樣(Bilinear Resampling)

雙線性取樣(Bilinear Resampling)在 Android 中的使用方式一般有兩種:

Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.png");
Bitmap compress = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth()/2, bitmap.getHeight()/2, true);

或者直接使用 matrix 進行縮放

Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.png");
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 0.5f);
bm = Bitmap.createBitmap(bitmap, 0, 0, bit.getWidth(), bit.getHeight(), matrix, true);

看原始碼可以知道 createScaledBitmap 函式最終也是使用第二種方式的 matrix 進行縮放,我們來看看雙線性取樣的表現:

原圖

處理之後的圖片

可以看到處理之後的圖片不是像鄰近取樣一樣純粹的一種顏色,而是兩種顏色的混合。雙線性取樣使用的是雙線性內插值演算法,這個演算法不像鄰近點插值演算法一樣,直接粗暴的選擇一個畫素,而是參考了源畫素相應位置周圍 2x2 個點的值,根據相對位置取對應的權重,經過計算之後得到目標影象。

雙線性內插值演算法在影象的縮放處理中具有抗鋸齒功能, 是最簡單和常見的影象縮放演算法,當對相鄰 2x2 個畫素點採用雙線性內插值演算法時,所得表面在鄰域處是吻合的,但斜率不吻合,並且雙線性內插值演算法的平滑作用可能使得影象的細節產生退化,這種現象在上取樣時尤其明顯。

四、鄰近取樣和雙線性取樣對比

我們這裡來對比一下這兩種 Android 中經常用到的圖片尺寸壓縮方法。

鄰近取樣的方式是最快的,因為它直接選擇其中一個畫素作為生成畫素,但是生成的圖片可能會相對比較失真,產生比較明顯的鋸齒,最具有代表性的就是處理文字比較多的圖片在展示效果上的差別,對比:

原圖:原圖

鄰近取樣:鄰近取樣

雙線性取樣:雙線性取樣

這個對比就非常直觀了,鄰近取樣字的顯示失真對比雙線性取樣來說要嚴重很多。

五、雙立方/雙三次取樣(Bicubic Resampling)

雙立方/雙三次取樣使用的是雙立方/雙三次插值演算法。鄰近點插值演算法的目標畫素值由源圖上單個畫素決定,雙線性內插值演算法由源畫素某點周圍 2x2 個畫素點按一定權重獲得,而雙立方/雙三次插值演算法更進一步參考了源畫素某點周圍 4x4 個畫素。

這個演算法在 Android 中並沒有原生支援,如果需要使用,可以通過手動編寫演算法或者引用第三方演算法庫,幸運的是這個演算法在 ffmpeg 中已經給到了支援,具體的實現在 libswscale/swscale.c 檔案中:FFmpeg Scaler Documentation

雙立方/雙三次插值演算法經常用於影象或者視訊的縮放,它能比雙線性內插值演算法保留更好的細節質量。我們看看這個演算法的實際表現和與雙線性內插值演算法的下采樣對比:

原圖:下采樣--原圖

雙三次取樣:下采樣--雙三次取樣 

雙線性取樣:下采樣--雙線性取樣

就下采樣來說,兩者表現很相近,肉眼可見的差距不大,接下來比較一下這兩種演算法的上取樣實際表現:

原圖:上取樣--原圖

雙三次取樣:上取樣--雙三次取樣

雙線性取樣:上取樣--雙線性取樣

這兩種演算法的上取樣結果我們還是可以看見較為明顯的差距,雙立方/雙三次取樣的鋸齒是要小一些。

雙立方/雙三次插值演算法在平時的軟體中是很常用的一種圖片處理演算法,但是這個演算法有一個缺點就是計算量會相對比較大,是前三種演算法中計算量最大的,軟體 photoshop 中的圖片縮放功能使用的就是這個演算法。

六、Lanczos Resampling

Lanczos 取樣和 Lanczos 過濾是 Lanczos 演算法的兩種常見應用,它可以用作低通濾波器或者用於平滑地在取樣之間插入數字訊號,Lanczos 取樣一般用來增加數字訊號的取樣率,或者間隔取樣來降低取樣率。

Lanczos 取樣使用的 Lanczos 演算法也可以用來作為圖片的縮放,Lanczos 演算法和雙三次插值演算法都是使用卷積核來通過輸入畫素計算輸出畫素,只不過在演算法表現上稍有不同。關於卷積核的介紹,這裡給一張簡單的圖片幫助大家理解:

影象卷積

Lanczos 從演算法角度講理論上會比雙三次/雙立方插值演算法更好一點,先來看看它和雙三次/雙立方取樣的圖片下采樣對比:

原圖:下采樣--原圖

Lanczos 取樣:下采樣--Lanczos 取樣

雙三次取樣:下采樣--雙三次取樣

基本看不出差別,然後是這兩種演算法的上取樣對比:

原圖:上取樣--原圖

Lanczos 取樣:上取樣--Lanczos 取樣

雙三次取樣:上取樣--雙三次取樣

這兩種演算法的上下采樣結果從肉眼上看差距很小,但是從理論上來說 Lanczos 演算法處理出來的圖片應該是更加平滑少鋸齒的。

同樣的,Lanczos 演算法在 ffmpeg 的 libswscale/swscale.c 中也有實現。其實不光 Lanczos 和上面的三種演算法,ffmpeg 還提供了其他的影象重取樣方法,諸如 area averagingGaussian 等等,通過編譯好的 ffmpeg 庫呼叫這些演算法處理圖片的命令如下:

ffmpeg -s 600x500 -i input.jpg -s 300x250 -sws_flags lanczos lanczos.jpg

-sws_flags 引數根據取樣演算法可以選擇 bilinear/bicubic/lanczos 等等。

七、四種演算法對二值化圖片的處理表現

這四種圖片重取樣演算法在處理二值化圖片上面的表現差異較大,我們先看看下采樣的對比:

原圖:下采樣--原圖

鄰近取樣:下采樣--鄰近取樣

雙線性取樣:下采樣--雙線性取樣

雙三次取樣:下采樣--雙三次取樣

Lanczos 取樣:下采樣--Lanczos 取樣

下采樣的對比一目瞭然,從上到下的影象表現效果逐漸變優,Lanczos 演算法處理後的影象質量屬於最優,接著我們看看這四種演算法的上取樣對比:

原圖:上取樣--原圖

鄰近取樣:上取樣--鄰近取樣

雙線性取樣:上取樣--雙線性取樣

雙三次取樣:上取樣--雙三次取樣

Lanczos 取樣:上取樣--Lanczos 取樣

從影象質量上來看,和下采樣結果一致,鄰近取樣效果較差,依次往下效果變優,Lanczos 效果最優。

八、總結

上面主要介紹了常見的四種影象重取樣演算法,在 Android 中,前兩種取樣方法根據實際情況去選擇即可,如果對時間要求不高,傾向於使用雙線性取樣去縮放圖片。如果對圖片質量要求很高,雙線性取樣也已經無法滿足要求,則可以考慮引入另外幾種演算法去處理圖片,但是同時需要注意的是後面兩種演算法使用的都是卷積核去計算生成畫素,計算量會相對比較大,Lanczos 的計算量則是最大,在實際開發過程中根據需求進行演算法的選擇即可。

九、參考

相關推薦

Android圖片壓縮分析

一、Android 尺寸壓縮邏輯 針對圖片尺寸的修改其實就是一個影象重新取樣的過程,放大影象稱為上取樣(upsamping),縮小影象稱為下采樣(downsampling),這裡我們重點討論下采樣。 在 Android 中圖片重取樣提供了兩種方法,一種叫

Android圖片壓縮分析

一、前言 在 Android 中進行圖片壓縮是非常常見的開發場景,主要的壓縮方法有兩種:其一是質量壓縮,其二是下采樣壓縮。 前者是在不改變圖片尺寸的情況下,改變圖片的儲存體積,而後者則是降低影象尺寸,達到相同目的。 由於本文的篇幅問題,分為上下兩篇釋出

Android 圖片壓縮分析

歡迎大家前往騰訊雲社群,獲取更多騰訊海量技術實踐乾貨哦~ 作者: shawnzhao 一、前言 在 Android 中進行圖片壓縮是非常常見的開發場景,主要的壓縮方法有兩種:其一是質量壓縮,其二是下采樣壓縮。 前者是在不改變圖片尺寸的情況下,

【資料運營】在運營,為什麼文字分析遠比數值型分析重要?一個實際案例,五點分析

https://www.pmcaff.com/article/index/408451832537216?from=profile 本文是《資料分析中,文字分析遠比數值型分析重要!》的下篇,以一個實際案例來聊聊文字分析在實際運營中如何落地。行為脈絡如下:先簡要講述文字分析的分支---情緒分析的基本原

android影象處理系列之六--給圖片新增邊框圖片疊加

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Mac使用Eclipse實現Android呼叫C/C++NDK基礎詳細教程

寫於2014年那個辦公室停電導致熱爆了汗流浹背的夏天。 需求 NDK是由谷歌娘提供的,某種意義上就是可以讓android使用c開發的第“三”方sdk,所以,正常來說eclipse是沒有配置這個東西的,當然如我所云,我只考慮用最小的工程成本(較少的

Android如何在應用層進行截圖及截圖原始碼分析

首先,那麼如果朋友你只是來找截圖介面使用在你的專案中的,那麼你就不用繼續往下看了。。。 基於上班時間較忙,另外個人覺得還是將這個截圖流程分析和使用分開總結比較好,於是決定分兩篇文章來講解。好了,那麼上一篇文章主要是從原始碼角度分析講解了Android系統截圖流

Android-3】Android的任務棧Task

集合 情況下 清除 bsp 生命周期方法 任務棧 保存 sin 也會 一、Android任務棧 概述:Android中的任務棧其實就是Activity的集合,在Android中退出程序的時候必須把任務棧中的所有Activity清除出棧,此時才能安全的完全的退出程序, 任務棧

JavaJNI的使用

將不 scribe gre 一個數 lai num 開頭 數組長度 jclass 數組的操作 數組是一個很常用的數據類型,在但是在 JNI 中並不能直接操作 jni 數組(比如 jshortArray、jfloatArray)。使用方法是: 獲取數組長度:jsize G

Android的對話方塊AlertDialog

建立android中分體式對話方塊需要四個步驟: 第一:獲得AlertDialog的靜態內部類Builder物件,有該類建立對話方塊。 第二:通過Builder物件設定對話方塊的標題,按鈕UI及將要響應的事件。、 第三:呼叫Builder的Create()方法建立對對話方塊 第四

C++筆記 第九課 函式過載分析---狄泰學院

如果在閱讀過程中發現有錯誤,望評論指正,希望大家一起學習,一起進步。 學習C++編譯環境:Linux 第九課 函式過載分析(下) 1.過載與指標 下面的函式指標將儲存哪個函式的地址?第一個 函式過載遇上函式指標 將過載函式名賦值給函式指標時 1.根據過載規則挑選與函式指標引

資料結構和算法系列3--複雜度分析

複雜度分析的4個概念 1.最壞情況時間複雜度:程式碼在最理想情況下執行的時間複雜度。 2.最好情況時間複雜度:程式碼在最壞情況下執行的時間複雜度。 3.平均時間複雜度:用程式碼在所有情況下執行的次數的加權平均值表示。 4.均攤時間複雜度:在程式碼執行的所有複雜度情況中絕大部分是低級別的複

【FastReport教程】介紹C#的非同步程式設計

【下載FastReport.Netdownload最新版本】 非同步程式設計模型出現在.Net Framework的第一個版本中。APM允許使用兩種方法建立同步方法的非同步版本 - Begin 和End 。 所以,只有兩種方法: public IAsyncResult Begin{MethodName}(

第四章 語法分析——LR文法

文章目錄 概述 基本概念 移動-歸約語法分析技術 SLR 增廣文法 狀態內部擴充套件 狀態之間的擴充套件 構建分析表 ACTION 構造SLR語法分析表

matlab第八課:影象分析

目標: 影象閾值 背景評估 聯通區域標記 一、影象閾值 graythresh():找出一個影象的最佳閾值是什麼 im2bw():轉變影象為二值影象 I = imread('rice.png'); level=graythresh(I); % 獲

編譯原理 第三章 詞法分析

3.6 有窮自動機(非常重要) 3.6.1 不確定的有窮自動機(重要) 例:  狀態0是開始狀態, 在狀態0上輸入符號b會進入狀態0,輸入a可能進去狀態0也有可能進入狀態1。所以對於狀態0來說一個確定的輸入符號a他有兩種離開狀態,這就是一種不確定的狀態。   &nbs

C++筆記 第五十一課 C++物件模型分析---狄泰學院

如果在閱讀過程中發現有錯誤,望評論指正,希望大家一起學習,一起進步。 學習C++編譯環境:Linux 第五十一課 C++物件模型分析(下) 1.繼承物件模型 在C++編譯器的內部類可以理解為結構體 子類是由父類成員疊加子類新成員得到的 51-1 繼承物件模型初探 #

C++筆記 第六十五課 C++的異常處理---狄泰學院

如果在閱讀過程中發現有錯誤,望評論指正,希望大家一起學習,一起進步。 學習C++編譯環境:Linux 第六十五課 C++中的異常處理(下) 1.C++中的異常處理 catch語句塊中可以丟擲異常 2.問題 為什麼要在catch中重新丟擲異常? 3.C++中的異常

病毒分析教程第五話--動態除錯分析

動態除錯分析(下) Lab 9-3 本節實驗使用樣本Lab09-03.exe、DLL1.dll、DLL2.dll、DLL3.dll。 Lab09-03.exe匯入了哪些DLL? 我們用OD開啟函式呼叫,發現Lab09-03.exe顯性地匯入了DLL1和DL

【資料結構與演算法-java實現】二 複雜度分析:最好、最壞、平均、均攤時間複雜度的概念

上一篇文章學習了:如何分析、統計演算法的執行效率和資源消耗? 點選連結檢視上一篇文章:複雜度分析上 今天的文章學習以下內容: 最好情況時間複雜度 最壞情況時間複雜度 平均情況時間複雜度 均攤時間複雜度 1、最好與最壞情況時間複雜度 我們首先