圖片壓縮應用很普遍,如生成縮略圖等。前期我在進行圖片處理的過程當中碰到了一個問題,就是如何將圖片壓縮到指定尺寸,此處尺寸指的是生成圖片文件的大小。python
我使用 opencv 進行圖片處理,因而想着直接使用 opencv 進行圖片壓縮處理, opencv 自己包含了壓縮到指定像素大小的方法,奈何尋找了不少方法均不能壓縮到指定文件尺寸,因而本身在思考後寫出了此方法。本文使用python語言。算法
opencv 無需多言,作過圖片處理的人應該都知道此類庫,下面我介紹一些經常使用方法。shell
首先安裝 python ,建議 python3 ,而後執行
:數組
pip install opencv-python
首先引入 opencv 包:函數
import cv2 as cv
然後讀取圖片:測試
image = cv.imread(path)
其中 path 爲圖片路徑, image 爲圖片數據,是一個 numpy.ndarray 對象,其實就是一個多維數組。目前 opencv 支持幾乎全部格式的圖片(參考 http://blog.csdn.net/mars_xiaolei/article/details/78890971)。優化
代碼:.net
cv.imwrite(path, image)
其中 path 爲保存的文件路徑, image 爲讀取或者處理過的圖片數據, opencv 根據保存文件的後綴名來寫不一樣格式的圖片數據,因此後綴名必定要寫正確。code
opencv 支持常規壓縮,能夠將圖片壓縮到指定的像素尺寸或者按比例縮放。對象
new_image = cv.resize(image, size)
其中 size 是一個二維元組,表示壓縮後圖片的寬高。
new_image = cv.resize(image, None, fx, fy)
其中 fx , fy 表示圖片在寬和高方向的壓縮了比例。
有了上面的基礎咱們來分析一下如何實現壓縮到指定文檔大小。
首先咱們要讀取原始文檔的大小,算出原始文檔大小和壓縮目標值的比例,因爲咱們要實現的是寬高等比例壓縮,因而將其開根號即表示在單邊的壓縮比例,調用 2.1 節中的按比例壓縮。理論上一次就能達到效果,可是因爲圖片自己存在壓縮,因此可能一次沒法達到預期,只要對壓縮後的圖片重複此步驟,直到達到預期便可。
def get_doc_size(path): try: size = os.path.getsize(path) return get_mb_size(size) except Exception as err: print(err) def get_mb_size(bytes): bytes = float(bytes) mb = bytes / 1024 / 1024 return mb
get_doc_size 函數返回圖片的文檔大小,單位爲 MB 。
def delete_file(path): if file_exist(path): os.remove(path) else: print('no such file:%s' % path) def file_exist(path): return os.path.exists(path)
因爲咱們須要刪除壓縮過程當中產生的中間文件,因此須要調用 delete_file 方法刪除之。
size = get_doc_size(path) delete_file(resize_path) while size > filesize: rate = math.ceil((size / filesize) * 10) / 10 + 0.1 rate = math.sqrt(rate) rate = 1.0 / rate if file_exist(resize_path): resize_rate(resize_path, resize_path, rate, rate) else: resize_rate(path, resize_path, rate, rate) size = get_doc_size(resize_path)
其中 filesize 表示壓縮目標值, path 表示原始文件路徑, resize_path 表示壓縮後存放路徑, resize_rate 表示上述按比例壓縮方法,定義以下:
def resize_rate(path, resize_path, fx, fy): image = read_image(path) im_resize = cv.resize(image, None, fx=fx, fy=fy) delete_file(resize_path) save_image(resize_path, im_resize) def save_image(path, image): cv.imwrite(path, image) def read_image(path): return cv.imread(path)
固然此處爲了效果更好,我作了一些優化。
首先在獲取壓縮比例的時候我作了下述操做:
rate = math.ceil((size / filesize) * 10) / 10 + 0.1
理論狀況應當是直接返回 size / filesize 便可,可是在實際測試過程當中爲了加速收斂,我採用上述方式,將一個小數先乘以 10 對其向上取整,這樣就表示精度保留到原始數值小數後 1 位,即若是是 3.14 將獲得 32 ,然後將此結果再除以 10 , 即獲得 3.2 ,因此最終結果就是對小數後第二位進行向上進位,最後結果又加了 0.1 以更快速的收斂,固然你也能夠去掉。
實際測試發現,通常重複執行兩次便可獲得理想的壓縮效果,而且結果值與理想壓縮尺寸相差無幾。
本文簡單介紹瞭如何使用 opencv 將圖片壓縮到指定文件尺寸,固然你也能夠選擇其餘文件處理類庫而不是 opencv ,這個徹底能夠根據用戶本身的興趣而來,而且也能夠優化最終的循環算法,以達到更佳的效果,或者更快的收斂。