使用 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 ,这个完全可以根据用户自己的兴趣而来,并且也可以优化最终的循环算法,以达到更佳的效果,或者更快的收敛。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

mxnet安装及NDArray初体验

一、mxnet安装 (以下均为mac环境) 有二种方式: 1.1 用conda安装 1 #创建gluon目录 2 mkdir gluon-tutorial...

30460
来自专栏人工智能LeadAI

存储Tensorflow训练网络的参数

训练一个神经网络的目的是啥?不就是有朝一日让它有用武之地吗?可是,在别处使用训练好的网络,得先把网络的参数(就是那些variables)保存下来,怎么保存呢?其...

33180
来自专栏机器之心

资源 | TensorFlow极简教程:创建、保存和恢复机器学习模型

选自Github 机器之心编译 参与:Jane W、李泽南 TensorFlow 是一个由谷歌发布的机器学习框架,在这篇文章中,我们将阐述 TensorFlow...

28170
来自专栏WOLFRAM

可视化:标签、缩放和排除

21640
来自专栏CNN

Tensorflow将模型导出为一个文件及接口设置

在上一篇文章中《Tensorflow加载预训练模型和保存模型》,我们学习到如何使用预训练的模型。但注意到,在上一篇文章中使用预训练模型,必须至少的要4个文件:

21720
来自专栏wOw的Android小站

[Tensorflow] Faster R-CNN 和自定义 VOC 数据集

看了pascal_voc.py代码,可以把代码的jpg拼接改成png,这样可以不做上一步.

1.7K20
来自专栏CNN

从Tensorflow模型文件中解析并显示网络结构图(CKPT模型篇)

本文介绍如何从CKPT模型文件中提取网络结构图并实现可视化。

1.7K30
来自专栏机器学习算法与Python学习

不会用Photoshop抠图?Mask R-CNN助你一键“除”人

19430
来自专栏Small Code

【Python】Numpy 中的 shuffle VS permutation

有时候我们会有随机打乱一个数组的需求,例如训练时随机打乱样本,我们可以使用 numpy.random.shuffle() 或者 numpy.random.per...

454110
来自专栏机器之心

教程 | TensorFlow 官方解读:如何在多系统和网络拓扑中构建高性能模型

选自Tensorflow 机器之心编译 参与:黄玉胜、黄小天 这个文档和附带的脚本详细介绍了如何构建针对各种系统和网络拓扑的高性能可拓展模型。这个技术在本文档中...

387110

扫码关注云+社区

领取腾讯云代金券