图片压缩应用很普遍,如生成缩略图等。前期我在进行图片处理的过程当中碰到了一个问题,就是如何将图片压缩到指定尺寸,此处尺寸指的是生成图片文件的大小。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 ,这个彻底能够根据用户本身的兴趣而来,而且也能够优化最终的循环算法,以达到更佳的效果,或者更快的收敛。