使用 opencv 將圖片壓縮到指定文件尺寸


前言

圖片壓縮應用很廣泛,如生成縮略圖等。前期我在進行圖片處理的過程中碰到了一個問題,就是如何將圖片壓縮到指定尺寸,此處尺寸指的是生成圖片文件的大小。

我使用 opencv 進行圖片處理,於是想着直接使用 opencv 進行圖片壓縮處理, opencv 本身包含了壓縮到指定像素大小的方法,奈何尋找了很多方法均不能壓縮到指定文件尺寸,於是自己在思考后寫出了此方法。本文使用python語言。

一、 opencv 常規使用

opencv 無需多言,做過圖片處理的人應該都知道此類庫,下面我介紹一些常用方法。

1.1 安裝 opencv

首先安裝 python ,建議 python3 ,然后執行

pip install opencv-python

1.2 讀取圖片

首先引入 opencv 包:

import cv2 as cv

而后讀取圖片:

image = cv.imread(path)

其中 path 為圖片路徑, image 為圖片數據,是一個 numpy.ndarray 對象,其實就是一個多維數組。目前 opencv 支持幾乎所有格式的圖片(參考 http://blog.csdn.net/mars_xiaolei/article/details/78890971)。

1.3 保存圖片

代碼:

cv.imwrite(path, image)

其中 path 為保存的文件路徑, image 為讀取或者處理過的圖片數據, opencv 根據保存文件的后綴名來寫不同格式的圖片數據,所以后綴名一定要寫正確。

二、圖片壓縮

2.1 常規壓縮

opencv 支持常規壓縮,可以將圖片壓縮到指定的像素尺寸或者按比例縮放。

  • 壓縮到指定的像素尺寸:
new_image = cv.resize(image, size)

其中 size 是一個二維元組,表示壓縮后圖片的寬高。

  • 按比例縮放:
new_image = cv.resize(image, None, fx, fy)

其中 fx , fy 表示圖片在寬和高方向的壓縮了比例。

2.2 壓縮到指定文檔大小

有了上面的基礎我們來分析一下如何實現壓縮到指定文檔大小。

首先我們要讀取原始文檔的大小,算出原始文檔大小和壓縮目標值的比例,由於我們要實現的是寬高等比例壓縮,於是將其開根號即表示在單邊的壓縮比例,調用 2.1 節中的按比例壓縮。理論上一次就能達到效果,但是由於圖片本身存在壓縮,所以可能一次無法達到預期,只要對壓縮后的圖片重復此步驟,直到達到預期即可。

2.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 。

2.2.2 刪除文件

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 方法刪除之。

2.2.3 壓縮

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 ,這個完全可以根據用戶自己的興趣而來,並且也可以優化最終的循環算法,以達到更佳的效果,或者更快的收斂。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM