图像的压缩算法--尺寸压缩、格式压缩和品质压缩

简介: 图像的压缩算法--尺寸压缩、格式压缩和品质压缩

图像分辨率指图像中存储的信息量,是每英寸图像内有多少个像素点,分辨率的单位为PPI(Pixels Per Inch),通常叫做像素每英寸。图像分辨率一般被用于ps中,用来改变图像的清晰度。

一个影像可被定义是一个二维的函数 f(x,y),其中x和y是空间平面坐标,在任意一对坐标轴(x,y),f的大小称为这幅影像在该点的强度(instensity)或灰阶(gray level).也即,灰阶是指地物电磁波辐射强度表现在黑白影像上的色调深浅的等级,是划分地物波谱特征的尺度。

一张图片的图片大小主要取决于图片尺寸(点阵图如6000*4000就时指的图片尺寸),分辨率(每英寸图像内有多少个像素点),灰阶。图像压缩算法(学过图像处理的人知道,图片最简单的是位图,就时bitMap,对应的是原始无压缩的点阵图,而jpeg等图像算法能把相同的连续图像点按照对应图像压缩算法和分辨率对位图进行压缩保存,也可以还原位图。由于jpeg和png是有损压缩,压缩后和原图有失真)。所以图片压缩分三类:尺寸压缩最快成比例压缩(理论上可以压缩到接近无限小,你把他压缩到4个点了也没有什么物理意义了)、图像格式压缩(如:把bitMap转换为jpeg,PNG等图片格式)、图像品质压缩(UIImageJPEGRepresentation(image, compressionQuality)进行分辨率和压缩算法方面的压缩。注意:compressionQuality是图像质量参数和图像分辨率强相关不是简单压缩比,这种压缩有压缩下限。其中图像格式压缩和图像品质压缩可以同时进行,把png等非JPG格式的图片通过UIImageJPEGRepresentation函数及compressionQuality压缩参数进行压缩。由于图片的点阵图尺寸不会变,而连续相同的像素点也是固定,最多你把一个像素点灰阶从很大压缩到1,使用UIImageJPEGRepresentation压缩图像主要是图像格式方面的压缩,而修改它的compressionQuality主要是修改它的分辨率,所以通过UIImageJPEGRepresentation修改compressionQuality对图片压缩到一定程度,图像大小是无限趋近于不变化而不是无限接近0),也就是超大尺寸的图片经过非尺寸方面的压缩后可能很小,但是不会无限小通常有100k以上。

UIImageJPEGRepresentation(compressedImage, compressionQuality)其中的compressionQuality可以称为图片质量参数,它能决定压缩后的图片大小和分辨率。一般的图片,当compressionQuality为0.7时和原图片大小比较接近,但是这和图像的尺寸,色彩丰富度等各种图像指标有关,有的是compressionQuality为0.8,有的是compressionQuality为0.5时更接近压缩前的图片大小,这个没有固定的值,它取决为图片本身,不能用一张图片设置为0.5时解决原图片都认为compressionQuality为0.5接近原图片。以前我专门测试过compressionQuality的值对图片原来大小的比例。只要测试10兆超级大的尺寸图片,全黑图片,全白图片,色彩特别复杂的图片。有的文章一概而论的说法本来就是错误的。

注意把一般的jpg图片通过UIImagePNGRepresentation(compressedImage)转变为png格式的图片,大约会变大1.2倍左右(具体多少根据图片来决定,但是基本都变大是肯定的)。但是png支持透明背景图片,把png 格式透明背景的图片转变jpg格式的图片,图片背景会变成默认的黑色。

由于常见的jpeg和png都有损压缩,若非必要,尽量别来回压缩。图像压缩很费时间和内存的,特别是时间。

图像可以通过图像尺寸和图像大小(图像格式和分辨率方面的压缩)两方面的多次压缩。

下面是按照要求,把图像压缩到指定的大小或接近最小值的循环压缩图像的算法(注意这个很浪费时间,有大图像可能需要浪费你几秒很正长,大尺寸图像很可能压缩不到你设置的很小的值,但是能接近它的最小值。这种压缩的特点是图片大小压缩很快,并且不改变图片的尺寸):

static const long long shareImageMaxLength = 1024*1024;
-(UIImage *)getImageWithDada : (NSData *)data
{
    if(!data)
    {
        return nil;
    }
    UIImage *image = [UIImage imageWithData:data];
    if(data.length <= shareImageMaxLength)
    {
        NSLog(@"data.length:%lu", (unsigned long)data.length);
        return image;
    }
    else
    {
        CGFloat compressionQualityArr[1001] = {0};
        compressionQualityArr[0] = 0.0001;
        for(NSInteger i = 1; i <= 1000; i++)
        {
            compressionQualityArr[i] = i*0.001;
        }
        NSData *compressedData = [self findImageWithImage:image lowerBoundary:0 upperBoundary:1000 compressionQualityArr:compressionQualityArr];
        return [UIImage imageWithData:compressedData];
    }
}

-(NSData *)findImageWithImage : (UIImage *)image
                 lowerBoundary : (NSInteger)lowerBoundary
                 upperBoundary : (NSInteger)upperBoundary
         compressionQualityArr : (CGFloat *)compressionQualityArr

{
    NSInteger x = (lowerBoundary + upperBoundary) / 2;
    NSData *data = UIImageJPEGRepresentation(image, compressionQualityArr[x]);
    if(data.length <= shareImageMaxLength)
    {
        NSLog(@"data.length:%lu,compressionQualityArr[%ld]:%f", (unsigned long)data.length, (long)x, compressionQualityArr[x]);
        return data;
    }
    if ((data.length > shareImageMaxLength) && (x > 0))//说明在compressionQualityArr[lowerBoundary]-compressionQualityArr[x]范围参数之中
    {
        return [self findImageWithImage:image lowerBoundary:lowerBoundary upperBoundary:x compressionQualityArr:compressionQualityArr];
    }
    else
    {
        NSLog(@"data.length:%lu,compressionQualityArr[%ld]:%f", (unsigned long)data.length, (long)x, compressionQualityArr[x]);
        return data;
    }
}

下面是把宽或高大于指定尺寸的图片等比例压缩到指定宽高范围内的图片的算法。图像大小一般在苹果手机上影响下载的快慢等用户体验问题,但是图像尺寸太大,苹果电脑直接不支持。我们的app甚至出现过SDWebImage下载图片时崩溃,没有办法只有通过修改SDWebImage这个开源库,压缩图像的尺寸才避免了崩溃。前不久做多图片分享时,调用系统分享组件UIActivityViewController,结果直接分享的界面出不来。只要尺寸指定不超过iphone X,一个图片再怎么大也大不到哪里去,但是超大尺寸的图片搞个几百兆没有问题。下面图片宽高设置为不超过iphone X ps像素。由于我是通过NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]]直接得到的图像数据流,所以压缩函数的入参是(NSData *)data。

/**分享的图片最大宽度,单位:ps像素(不是物理像素)*/
static const long long maxShareImageWidth = 800;
/**分享的图片最大高度,单位:ps像素(不是物理像素)*/
static const long long maxShareImageHeight = 800;
-(UIImage *)compressImageWithDada : (NSData *)data
{
    UIImage *image = [UIImage imageWithData:data];
    if((image.size.height <= maxShareImageHeight) && (image.size.width <= maxShareImageWidth))
    {
        return image;
    }
    if((maxShareImageWidth == 0) || (maxShareImageHeight == 0))
    {
        //防止除数为0而crash,理论上不该出现maxIphoneScreenMaxSizeHeight为0
        return nil;
    }
//    float imageWidth = image.size.width;
//    float imageHeight = image.size.height;
    //800x800
    float width = maxShareImageWidth;
    float height = image.size.height/(image.size.width/width);
    
    if((image.size.width >= maxShareImageWidth) && (image.size.height >= maxShareImageHeight))
    {
        width = maxShareImageWidth;
        height = image.size.height/(image.size.width/width);
        if(height > maxShareImageHeight)
        {
            height = maxShareImageHeight;
            width = image.size.width/(image.size.height/height);
        }
    }
    else if(image.size.width >= maxShareImageWidth)
    {
        height = maxShareImageHeight;
        width = image.size.width/(image.size.height/height);
    }
//    else if(image.size.height >= maxIphoneScreenMaxSizeHeight)
//    {
//        width = maxIphoneScreenMaxSizeWidth;
//        height = image.size.height/(image.size.width/width);
//    }
    
    
//    float widthScale = imageWidth /width;
//    float heightScale = imageHeight /height;
    
    // 创建一个bitmap的context
    // 并把它设置成为当前正在使用的context
    UIGraphicsBeginImageContext(CGSizeMake(width, height));
    [image drawInRect:CGRectMake(0, 0, width , height)];
//    if (widthScale > heightScale) {
//        [image drawInRect:CGRectMake(0, 0, imageWidth /heightScale , height)];
//    }
//    else {
//        [image drawInRect:CGRectMake(0, 0, width , imageHeight /widthScale)];
//    }
    
    // 从当前context中创建一个改变大小后的图片
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    // 使当前的context出堆栈
    UIGraphicsEndImageContext();
    
    return newImage;
    
}

当然你不怕压缩太费时间你也可以把图像尺寸压缩和图像大小方面的压缩(我暂时也叫它图像分辨方面方面的压缩吧)。

下面是先用图像大小压缩,当压缩到最小还是太大就采用图像尺寸方面的压缩。这种压缩不能解决大尺寸图片苹果手机支持的问题。因为相对苹果支持的尺寸是大尺寸的图片经过图像大小方面的压缩可能已经达标了,但是图像尺寸其实没变仍旧超标。这个只是两种图像压缩都使用的例子。当然你可以设计成先图像尺寸递归压缩然后图像大小太大再使用图像大小压缩的方法,这种方法我就不写了,自己改造就可以了。

-(UIImage *)getImageWithDada : (NSData *)data
{
    if(!data)
    {
        return nil;
    }
    UIImage *image = [UIImage imageWithData:data];
    if(data.length <= shareImageMaxLength)
    {
        NSLog(@"data.length:%lu", (unsigned long)data.length);
        return image;
    }
    else
    {
        CGFloat compressionQualityArr[1001] = {0};
        compressionQualityArr[0] = 0.0001;
        for(NSInteger i = 1; i <= 1000; i++)
        {
            compressionQualityArr[i] = i*0.001;
        }
        NSData *compressedData = [self findImageWithImage:image lowerBoundary:0 upperBoundary:1000 compressionQualityArr:compressionQualityArr];
        if(data.length <= shareImageMaxLength)
        {
            return [UIImage imageWithData:compressedData];
        }
        else
        {
            return [self compressImageWithDada:compressedData];
        }
    }
}
目录
相关文章
|
19天前
|
机器学习/深度学习 算法 数据库
KNN和SVM实现对LFW人像图像数据集的分类应用
KNN和SVM实现对LFW人像图像数据集的分类应用
49 0
|
19天前
|
编解码 监控 算法
图像和视频处理中DSP算法的研究与发展
图像和视频处理中DSP算法的研究与发展
35 2
|
14天前
|
人工智能 编解码 算法
使用 PAI-DSW x Free Prompt Editing图像编辑算法,开发个人AIGC绘图小助理
在本教程中,您将学习在阿里云交互式建模平台PAI-DSW x Free Prompt Editing图像编辑算法,开发个人AIGC绘图小助理,实现文本驱动的图像编辑功能单卡即可完成AIGC图片风格变化、背景变化和主体变化等功能。让我们一同开启这场旅程,为您的图像编辑添上无限可能性的翅膀吧。
|
4天前
|
算法 数据安全/隐私保护 C++
基于二维CS-SCHT变换和扩频方法的彩色图像水印嵌入和提取算法matlab仿真
该内容是关于一个图像水印算法的描述。在MATLAB2022a中运行,算法包括水印的嵌入和提取。首先,RGB图像转换为YUV格式,然后水印通过特定规则嵌入到Y分量中,并经过Arnold置乱增强安全性。水印提取时,经过逆过程恢复,使用了二维CS-SCHT变换和噪声对比度(NC)计算来评估水印的鲁棒性。代码中展示了从RGB到YUV的转换、水印嵌入、JPEG压缩攻击模拟以及水印提取的步骤。
|
19天前
|
算法
有史以来最全的图像相似度算法
有史以来最全的图像相似度算法
10 0
|
19天前
|
机器学习/深度学习 人工智能 算法
【图像版权】论文阅读:CRMW 图像隐写术+压缩算法
【图像版权】论文阅读:CRMW 图像隐写术+压缩算法
18 0
|
19天前
|
算法 数据安全/隐私保护 计算机视觉
基于DCT变换的彩色图像双重水印嵌入和提取算法matlab仿真
**算法摘要:** - 图形展示:展示灰度与彩色图像水印应用,主辅水印嵌入。 - 软件环境:MATLAB 2022a。 - 算法原理:双重水印,转换至YCbCr/YIQ,仅影响亮度;图像分割为M×N块,DCT变换后嵌入水印。 - 流程概览:两步水印嵌入,每步对应不同图示表示。 - 核心代码未提供。
|
19天前
|
算法 TensorFlow 算法框架/工具
基于直方图的图像阈值计算和分割算法FPGA实现,包含tb测试文件和MATLAB辅助验证
这是一个关于图像处理的算法实现摘要,主要包括四部分:展示了四张算法运行的效果图;提到了使用的软件版本为VIVADO 2019.2和matlab 2022a;介绍了算法理论,即基于直方图的图像阈值分割,通过灰度直方图分布选取阈值来区分图像区域;并提供了部分Verilog代码,该代码读取图像数据,进行处理,并输出结果到&quot;result.txt&quot;以供MATLAB显示图像分割效果。
|
19天前
|
算法 数据安全/隐私保护 数据格式
基于混沌序列的图像加解密算法matlab仿真,并输出加解密之后的直方图
该内容是一个关于混沌系统理论及其在图像加解密算法中的应用摘要。介绍了使用matlab2022a运行的算法,重点阐述了混沌系统的特性,如确定性、非线性、初值敏感性等,并以Logistic映射为例展示混沌序列生成。图像加解密流程包括预处理、混沌序列生成、数据混淆和扩散,以及密钥管理。提供了部分核心程序,涉及混沌序列用于图像像素的混淆和扩散过程,通过位操作实现加密。
|
19天前
|
机器学习/深度学习 文字识别 算法
MATLAB图像倾斜校正算法实现:图像倾斜角检测及校正
MATLAB图像倾斜校正算法实现:图像倾斜角检测及校正