这是一个类似于QQ头像的处理方法,据我所知QQ也是用这种方式处理的,当然我们有两种方案可以选择
第一种方案
-
使用第三方工具 ---OpenCV(官网内可下载包文件)
OpenCV 它是可以运行在Linux、Windows、Android和Mac OS操作系统上,轻量级而且高效,由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。包括了现在很多平台使用的,人机互动,人脸识别,动作识别,运动分析图像分割等等一系列的图像算法操作。
-
闲言碎语不要讲,直接上代码
//第一步:导入OpenCV头文件
#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>
//第二步:导入命名空间
using namespace cv;
@implementation ImageUtils
- (UIImage*)imageToGrayImage:(UIImage*)image{
//image:表示源文件(原始图片)
//第一步:将iOS的UIimage转成C++的图片(数据:矩阵)
Mat mat_image_gray;
UIImageToMat(image, mat_image_gray);
//第二步:将C++的彩色图片转成灰度图片
//参数1:数据源(原图片)
//参数2:目标数据(目标图片)
//参数3:转换类型(图片格式)
//COLOR_BGR2GRAY :将彩色图片转成灰度图片
Mat mat_image_dst;
cvtColor(mat_image_gray, mat_image_dst, COLOR_BGR2GRAY);
//第三步:转回可显示的图片 灰度->可显示图片
//普及:RGB(3个通道的颜色) ARGB(4个通道颜色,增加了1个透明度)
cvtColor(mat_image_dst, mat_image_gray, COLOR_GRAY2BGR);
//第四步将C++处理后的图片转成iOS可以识别的UIimage
return MatToUIImage(mat_image_gray);
}
由于openCV是用C /C ++写的,所以,需要导入命名空间,然后将Object-C的.m文件改成C++的.mm文件,这样才能够运行C++的代码
第二种方案
-
使用系统底层API
-
闲言碎语不要讲,直接上代码
//系统方法实现
- (UIImage*)systemImageToGrayImage:(UIImage*)image{
int width = image.size.width;
int height = image.size.height;
//第一步:创建颜色空间(说白了就是 开辟一块颜色内存空间)
//图片灰度处理(创建灰度空间)
CGColorSpaceRef colorRef = CGColorSpaceCreateDeviceGray();
//第二步:颜色空间的上下文(保存图像数据信息)
//参数1:内存大小(指向这块内存区域的地址)(内存地址)
//参数2:图片宽
//参数3:图片高
//参数4:像素位数(颜色空间,例如:32位像素格式和RGB颜色空间,8位)
//参数5:图片每一行占用的内存比特数
//参数6:颜色空间
//参数7:图片是否包含A通道(ARGB通道)
CGContextRef context = CGBitmapContextCreate(nil, width, height, 8, 0, colorRef, kCGImageAlphaNone);
//释放内存
CGColorSpaceRelease(colorRef);
if (context == nil) {
return nil;
}
//第三步:渲染图片(绘制图片)
//参数1:上下文
//参数2:渲染区域
//参数3:源文件(原图片)(说白了现在是一个C/C++的内存区域)
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.CGImage);
//第四步:将绘制颜色空间转成CGImage(转成可识别图片类型)
CGImageRef grayImageRef = CGBitmapContextCreateImage(context);
//第五步:将C/C++ 的图片CGImage转成面向对象的UIImage(转成iOS程序认识的图片类型)
UIImage* dstImage = [UIImage imageWithCGImage:grayImageRef];
//释放内存
CGContextRelease(context);
CGImageRelease(grayImageRef);
return dstImage;
}
实现类似qq灰色头像的样式,我们就写完了,是不是很6。
这就完事儿了?怎么可能!
接下来我来讲解架构设计--策略模式
什么是策略模式呢?分析我们平时写的代码结构,通常写法是不是将所有类似功能写在一个类中(算法结构类似)。现实中是不是碰到过,自己写了一天的代码,提交上去,结果被人家给替换掉呢,有吧!我就遇到过,当时真想冲上去爆揍他一顿,哈哈,还好我控制住了。
而策略模式呢是将我们的算法结构进行分离,一个类中存在相同的算法,你可以单独定义,便于扩展。
1)策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
-
闲言碎语不要讲,直接上代码
1.第一步:创建协议(面向协议编程)
我们依旧是使用上面的两个算法,来介绍策略模式。
我们创建一个名为strategy的protocol
#import <UIKit/UIKit.h>
//策略协议:面向协议编程
@protocol Strategy <NSObject>
//定义算法
- (UIImage*)imageToGrayImage:(UIImage*)image;
@end
2.第二步:创建两个类
#import <Foundation/Foundation.h>
#import "Strategy.h"
@interface systemStrategy : NSObject <Strategy>
@end
#import <Foundation/Foundation.h>
#import "Strategy.h"
@interface OpencvStrategy : NSObject<Strategy>
@end
将之前的代码放到.m实现文件里
//系统方法实现
- (UIImage*)imageToGrayImage:(UIImage*)image{
int width = image.size.width;
int height = image.size.height;
//第一步:创建颜色空间(说白了就是 开辟一块颜色内存空间)
//图片灰度处理(创建灰度空间)
CGColorSpaceRef colorRef = CGColorSpaceCreateDeviceGray();
//第二步:颜色空间的上下文(保存图像数据信息)
//参数1:内存大小(指向这块内存区域的地址)(内存地址)
//参数2:图片宽
//参数3:图片高
//参数4:像素位数(颜色空间,例如:32位像素格式和RGB颜色空间,8位)
//参数5:图片每一行占用的内存比特数
//参数6:颜色空间
//参数7:图片是否包含A通道(ARGB通道)
CGContextRef context = CGBitmapContextCreate(nil, width, height, 8, 0, colorRef, kCGImageAlphaNone);
//释放内存
CGColorSpaceRelease(colorRef);
if (context == nil) {
return nil;
}
//第三步:渲染图片(绘制图片)
//参数1:上下文
//参数2:渲染区域
//参数3:源文件(原图片)(说白了现在是一个C/C++的内存区域)
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.CGImage);
//第四步:将绘制颜色空间转成CGImage(转成可识别图片类型)
CGImageRef grayImageRef = CGBitmapContextCreateImage(context);
//第五步:将C/C++ 的图片CGImage转成面向对象的UIImage(转成iOS程序认识的图片类型)
UIImage* dstImage = [UIImage imageWithCGImage:grayImageRef];
//释放内存
CGContextRelease(context);
CGImageRelease(grayImageRef);
return dstImage;
return nil;
}
@end
#import "OpencvStrategy.h"
//第一步:导入OpenCV头文件
#import <opencv2/opencv.hpp>
#import <opencv2/imgcodecs/ios.h>
//第二步:导入命名空间
using namespace cv;
@implementation OpencvStrategy
- (UIImage*)imageToGrayImage:(UIImage*)image{
//image:表示源文件(原始图片)
//第一步:将iOS的UIimage转成C++的图片(数据:矩阵)
Mat mat_image_gray;
UIImageToMat(image, mat_image_gray);
//第二步:将C++的彩色图片转成灰度图片
//参数1:数据源(原图片)
//参数2:目标数据(目标图片)
//参数3:转换类型(图片格式)
//COLOR_BGR2GRAY :将彩色图片转成灰度图片
Mat mat_image_dst;
cvtColor(mat_image_gray, mat_image_dst, COLOR_BGR2GRAY);
//第三步:转回可显示的图片 灰度->可显示图片
//普及:RGB(3个通道的颜色) ARGB(4个通道颜色,增加了1个透明度)
cvtColor(mat_image_dst, mat_image_gray, COLOR_GRAY2BGR);
//第四步将C++处理后的图片转成iOS可以识别的UIimage
return MatToUIImage(mat_image_gray);
}
@end
3.第三步:创建两个类
然后我们在Viewcontroller里面调用
#import "ViewController.h"
#import "systemStrategy.h"
#import "OpencvStrategy.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (nonatomic) id<Strategy> utils;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_utils1 = [[ImageUtils alloc]init];
_utils = [[systemStrategy alloc]init];//系统方法协议
// _utils = [[OpencvStrategy alloc]init];//OpenCV方法
}
//灰度
- (IBAction)clickImageGray:(UIButton *)sender {
//三个颜色值相同就是灰色
//底层算法就是通过动态修改颜色OpenCV和系统自带的API底层算法是相同的
_imageView.image = [_utils imageToGrayImage:_imageView.image];
}
这样我们就大功告成了!面向协议编程协议模式,完美实现,如果有不懂得地方,这里有demo别忘记点Star哦!
还可以联系我。嘻嘻!