iOS 操作像素点给图片打马赛克

马赛克前
iOS 操作像素点给图片打马赛克_第1张图片
屏幕快照 2017-05-02 下午7.31.23.png
马赛克后
iOS 操作像素点给图片打马赛克_第2张图片
屏幕快照 2017-05-02 下午7.32.06.png

代码演示

写一个继承自NSObject的类,创建类方法+ (UIImage*)imageProcess:(UIImage*)image;

第一步:确定图片的宽高
/*
     两种方案
     1 image.size.width
     2 GImageGetWidth(<#CGImageRef  _Nullable image#>)

     */
    CGImageRef imageRef = image.CGImage;
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    
第二步:创建颜色空间
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    
第三步:创建图片上下文(解析图片信息,绘制图片)

开辟内存空间,这块空间用于处理马赛克图片
参数1:数据源
参数2:图片宽
参数3:图片高
参数4:表示每一个像素点,每一个分量大小
在我们图像学中,像素点:ARGB组成 每一个表示一个分量(例如,A,R,G,B)
在我们计算机图像学中每一个分量的大小是8个字节
参数5:每一行大小(其实图片是由像素数组组成的)
如何计算每一行的大小,所占用的内存
首先计算每一个像素点大小(我们取最大值): ARGB是4个分量 = 每个分量8个字节 * 4
参数6:颜色空间
参数7:是否需要透明度

CGContextRef contextRef = CGBitmapContextCreate(nil, width, height, 8, width*4, colorSpaceRef, kCGImageAlphaPremultipliedLast);
    
第四步:根据图片上下文绘制图片
CGContextDrawImage(contextRef, CGRectMake(0, 0, width, height), imageRef);
第五步:获取图片的像素数组
unsigned char * bitMapData = CGBitmapContextGetData(contextRef);
第六步:核心算法 图片打码,加入马赛克

马赛克:将图片模糊,(马赛克算法可以是可逆,也可以是不可逆,取决于打码的算法)
对图片进行采样

 我们今天处理的原理:让一个像素点替换为和它相同的矩形区域(正方形,圆形都可以)
 矩形区域包含了N个像素点
//选择马赛克区域
    //矩形区域:认为是打码的级别,马赛克点的大小(失真的强度)
    //这里将级别写死了level
    //level 马赛克点的大小
    NSUInteger currentIndex , preCurrentIndex, level = 3;
    //像素点默认是4个通道,默认值是0
    unsigned char * pixels[4] = {0};
    for (NSUInteger i = 0; i < height - 1; i++) {
        for (NSUInteger j = 0; j < width - 1; j++) {
            //循环便利每一个像素点,然后筛选,打码
            //获取当前像素点坐标-》指针位移方式处理像素点-》修改
            //指针位移
            currentIndex = (i * width) + j ;
            //计算矩形的区域
            /*
             分析下面筛选算法(组成马赛克点,矩形算法)
             假设:level = 3 (3*3的矩形)
             
             
             宽的规律:========
             第一步:i=0 j=0 level=3  i%level = 0  j%level=0
             第一次运行循环:
             memcpy(pixels, bitMapData+4*currentIndex, 4) 给我们的像素点赋值
             在这里我们以字节作为单位来获取,一个像素=4个字节,bitMapData+4*currentIndex一个像素点的读取,每次读区4个字节(开始的位置)
             第一次运行结果:获取第一个像素点的值
             
             第二步循环结果:
             i=0 j=1 i%level=0 j%level=1
             memcpy(bitMapData+4*currentIndex, pixels, 4);将第一个像素点的值拷贝复制替换给第二个像素点(指针位移方式计算)
             循环结果:第一个像素点值 赋值给 第二个像素点
             
             
             第三次运行循环:第一行第三列
             i=0 j=2 level=3  
             i%level=0 j%level=2
             循环结果:第三次像素点的值 = 第一次像素点的值
             
             
             
             高的规律:
             i=1 j=1 
             
             
             preCurrentIndex = (i - 1) * width + j;
             memcpy(bitMapData+4*currentIndex, bitMapData+4*preCurrentIndex, 4);
             
             第二行第一个像素点的值 = 第一行i 一个像素点的值
             
             */
            
            //通过这个算法,截取了一个3*3的一个矩形
            
            if (i % level==0) {
                if (j % level==0) {
                    //拷贝区域 c语言拷贝数据的函数
                    /*
                     参数1:拷贝目标(像素点)
                     参数2:源文件
                     参数3:要截取的长度(字节计算)
                     */
                    memcpy(pixels, bitMapData+4*currentIndex, 4);
                    
                }else{
                    //将上一个像素点的值赋值给第二个(指针位移的方式计算原理)
                    memcpy(bitMapData+4*currentIndex, pixels, 4);
                }
                
            }else{
                /*
                 例如:i=1  j=0
                 preCurrentIndex = (i - 1) * width + j;
                 */
                preCurrentIndex = (i - 1) * width + j;
                memcpy(bitMapData+4*currentIndex, bitMapData+4*preCurrentIndex, 4);
            }
            
            
        }
    }

第七步:获取图片数据集合
NSUInteger size = width * height * 4;
    CGDataProviderRef providerRef = CGDataProviderCreateWithData(NULL, bitMapData, size, NULL);
第八部:创建马赛克图片

参数1:宽
参数2:高
参数3:表示每一个像素点,每一个分量的大小
参数4:每一个像素点的大小
参数5:每一行内存大小
参数6:颜色空间
参数7:位图信息
参数8:数据源(数据集合)
参数9:数据解码器
参数10:是否抗锯齿
参数11:渲染器

CGImageRef mossicImageRef = CGImageCreate(width,
                                              height,
                                              8,
                                              4*8,
                                              width*4,
                                              colorSpaceRef,kCGImageAlphaPremultipliedLast,
                                              providerRef,
                                              NULL,
                                              NO,
                                              kCGRenderingIntentDefault);
    

第九步:创建输出马赛克图片(填充颜色)
CGContextRef outContextRef = CGBitmapContextCreate(nil,
                                                       width,
                                                       height,
                                                       8,
                                                       width*4,
                                                       colorSpaceRef,
                                                       kCGImageAlphaPremultipliedLast);
    //绘制图片
    CGContextDrawImage(outContextRef, CGRectMake(0, 0, width, height),mossicImageRef);
    
    //创建图片
    CGImageRef resultImageRef = CGBitmapContextCreateImage(outContextRef);
    UIImage *outImage = [UIImage imageWithCGImage:resultImageRef];
    
第十步:释放内存
//释放内存
    CGImageRelease(resultImageRef);
    CGImageRelease(mossicImageRef);
    CGColorSpaceRelease(colorSpaceRef);
    CGDataProviderRelease(providerRef);
    CGContextRelease(outContextRef);
    

完整代码

#import "ImageUntils.h"

@implementation ImageUntils

+ (UIImage*)imageProcess:(UIImage*)image{
    //第一步:确定图片的宽高
    /*
     两种方案
     1 image.size.width
     2 GImageGetWidth(<#CGImageRef  _Nullable image#>)

     */
    CGImageRef imageRef = image.CGImage;
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    
    //第二步:创建颜色空间
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    
    //第三部:创建图片上下文(解析图片信息,绘制图片)
    /*
     开辟内存空间,这块空间用于处理马赛克图片
     参数1:数据源
     参数2:图片宽
     参数3:图片高
     参数4:表示每一个像素点,每一个分量大小
            在我们图像学中,像素点:ARGB组成 每一个表示一个分量(例如,A,R,G,B)
            在我们计算机图像学中每一个分量的大小是8个字节
     参数5:每一行大小(其实图片是由像素数组组成的)
            如何计算每一行的大小,所占用的内存
            首先计算每一个像素点大小(我们取最大值): ARGB是4个分量 = 每个分量8个字节 * 4
     参数6:颜色空间
     参数7:是否需要透明度
     
     */
   CGContextRef contextRef = CGBitmapContextCreate(nil, width, height, 8, width*4, colorSpaceRef, kCGImageAlphaPremultipliedLast);
    
    //第四步:根据图片上下文绘制图片
    CGContextDrawImage(contextRef, CGRectMake(0, 0, width, height), imageRef);
    //第五步:获取图片的像素数组
    unsigned char * bitMapData = CGBitmapContextGetData(contextRef);
    
    //第六步:图片打码,加入马赛克
    /*
     核心算法
     马赛克:将图片模糊,(马赛克算法可以是可逆,也可以是不可逆,取决于打码的算法)
     对图片进行采样
     
     我们今天处理的原理:让一个像素点替换为和它相同的矩形区域(正方形,圆形都可以)
     矩形区域包含了N个像素点
     
     */
    
    //选择马赛克区域
    //矩形区域:认为是打码的级别,马赛克点的大小(失真的强度)
    //这里将级别写死了level
    //level 马赛克点的大小
    NSUInteger currentIndex , preCurrentIndex, level = 3;
    //像素点默认是4个通道,默认值是0
    unsigned char * pixels[4] = {0};
    for (NSUInteger i = 0; i < height - 1; i++) {
        for (NSUInteger j = 0; j < width - 1; j++) {
            //循环便利每一个像素点,然后筛选,打码
            //获取当前像素点坐标-》指针位移方式处理像素点-》修改
            //指针位移
            currentIndex = (i * width) + j ;
            //计算矩形的区域
            /*
             分析下面筛选算法(组成马赛克点,矩形算法)
             假设:level = 3 (3*3的矩形)
             
             
             宽的规律:========
             第一步:i=0 j=0 level=3  i%level = 0  j%level=0
             第一次运行循环:
             memcpy(pixels, bitMapData+4*currentIndex, 4) 给我们的像素点赋值
             在这里我们以字节作为单位来获取,一个像素=4个字节,bitMapData+4*currentIndex一个像素点的读取,每次读区4个字节(开始的位置)
             第一次运行结果:获取第一个像素点的值
             
             第二步循环结果:
             i=0 j=1 i%level=0 j%level=1
             memcpy(bitMapData+4*currentIndex, pixels, 4);将第一个像素点的值拷贝复制替换给第二个像素点(指针位移方式计算)
             循环结果:第一个像素点值 赋值给 第二个像素点
             
             
             第三次运行循环:第一行第三列
             i=0 j=2 level=3  
             i%level=0 j%level=2
             循环结果:第三次像素点的值 = 第一次像素点的值
             
             
             
             高的规律:
             i=1 j=1 
             
             
             preCurrentIndex = (i - 1) * width + j;
             memcpy(bitMapData+4*currentIndex, bitMapData+4*preCurrentIndex, 4);
             
             第二行第一个像素点的值 = 第一行i 一个像素点的值
             
             */
            
            //通过这个算法,截取了一个3*3的一个矩形
            
            if (i % level==0) {
                if (j % level==0) {
                    //拷贝区域 c语言拷贝数据的函数
                    /*
                     参数1:拷贝目标(像素点)
                     参数2:源文件
                     参数3:要截取的长度(字节计算)
                     */
                    memcpy(pixels, bitMapData+4*currentIndex, 4);
                    
                }else{
                    //将上一个像素点的值赋值给第二个(指针位移的方式计算原理)
                    memcpy(bitMapData+4*currentIndex, pixels, 4);
                }
                
            }else{
                /*
                 例如:i=1  j=0
                 preCurrentIndex = (i - 1) * width + j;
                 */
                preCurrentIndex = (i - 1) * width + j;
                memcpy(bitMapData+4*currentIndex, bitMapData+4*preCurrentIndex, 4);
            }
            
            
        }
    }
    
    //第七步:获取图片数据集合
    NSUInteger size = width * height * 4;
    CGDataProviderRef providerRef = CGDataProviderCreateWithData(NULL, bitMapData, size, NULL);
    //第八部:创建马赛克图片
    /*
     参数1:宽
     参数2:高
     参数3:表示每一个像素点,每一个分量的大小
     参数4:每一个像素点的大小
     参数5:每一行内存大小
     参数6:颜色空间
     参数7:位图信息
     参数8:数据源(数据集合)
     参数9:数据解码器
     参数10:是否抗锯齿
     参数11:渲染器
     */
    CGImageRef mossicImageRef = CGImageCreate(width,
                                              height,
                                              8,
                                              4*8,
                                              width*4,
                                              colorSpaceRef,kCGImageAlphaPremultipliedLast,
                                              providerRef,
                                              NULL,
                                              NO,
                                              kCGRenderingIntentDefault);
    
    //第九步:创建输出马赛克图片(填充颜色)
    CGContextRef outContextRef = CGBitmapContextCreate(nil,
                                                       width,
                                                       height,
                                                       8,
                                                       width*4,
                                                       colorSpaceRef,
                                                       kCGImageAlphaPremultipliedLast);
    //绘制图片
    CGContextDrawImage(outContextRef, CGRectMake(0, 0, width, height),mossicImageRef);
    
    //创建图片
    CGImageRef resultImageRef = CGBitmapContextCreateImage(outContextRef);
    UIImage *outImage = [UIImage imageWithCGImage:resultImageRef];
    
    
    
    //释放内存
    CGImageRelease(resultImageRef);
    CGImageRelease(mossicImageRef);
    CGColorSpaceRelease(colorSpaceRef);
    CGDataProviderRelease(providerRef);
    CGContextRelease(outContextRef);
    

    
    return outImage;
}
@end

你可能感兴趣的:(iOS 操作像素点给图片打马赛克)