前言

最近网上看了一个叫BadApple的字符串动画,很有意思。作者是用python+OpenCv实现的转换流程。而OpenCv又是一个开源项目,我们为什么不能把这个效果移植到iOS手机上呢?

原文地址

正文

首先先放一下效果图:

本次文章提及的相关内容demo地址

视频网盘地址:

链接:pan.baidu.com/s/1GjSzUKIn… 密码:lojq

我们想实现这么一个效果,自然不能只是纯粹地去翻写代码,我们首先得知道原理,才能知道为什么要这么做?

原理

ps: 这里的原理不一定那么专业,其中结合了本人的理解,如有错误,还望指出

首先,视频的本质是声音+图像,这里因为声音相关内容并非我们的研究方向,所以暂时省略。

所以,我们要将视频转换成字符串动画,首先就需要知道一点,图像是如何转成字符串的

图像转成字符串

我们在研究如何转化前,还需要大概了解下图像的存储

图像的存储

一个图像是由许许多多的小方格组成的,这些小方格都有明确的位置和颜色,这些小方格的位置与颜色最终决定了图像的样子,这些小方格也被称作像素

图像的显示

图像在屏幕上的显示,便是将图像的每一个像素点的颜色渲染在屏幕上的对应位置处,我们就看到对应图片了。

计算机中一般采用Bitmap(位图),来显示图像

Bitmap一般采用二维数组进行存取,二维数组中储存的便是该像素的颜色

颜色

计算机中颜色一般是采用RGB通道(在iOS中,我没有用过其他),也就是说一个颜色是由三种基础颜色(红Red绿Green蓝Blue)通道叠加生成的。所有颜色均可由三种颜色通道的不同强度组成。

我们通常用到图像一般是8位图像,在这里也可以说是三种颜色的强度可以从0 ~ (2^8 - 1 = 255)一共256个强度等级,而可以显示的总颜色数量就是256^3。

至此,图像就由一个具象的画面,变成了抽象的数据了。

灰度图像

因为彩色图像使用三个颜色通道描述一个像素点的颜色,我们也可以认为一张彩色图像拥有三个维度。

但是,如果我们希望以字符串显示的话,我们只能展示其中的一个维度(这里不考虑使用富文本时候字符串可以展示多个颜色的情况)。

所以我们需要对彩色图像进行降维处理,也就是通过某种算法使得我们可以使用一个颜色通道便可以描述出图像的特点。

灰度图像正是为了满足我们的这种需求而出现的。

定义

在计算机领域中, 灰度 (Gray scale) 数字图像是每个像素只有一个采样颜色的图像。 这类图像通常显示为从最暗黑色到最亮的白色的灰度 ,尽管理论上这个采样可以是任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。 灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑白两种颜色,灰度图像在黑色与白色之间还有许多级的颜色深度。 但是,在数字图像领域之外,「黑白图像」也表示「灰度图像」,例如灰度的照片通常叫做「黑白照片」。 在一些关于数字图像的文章中单色图像等同于灰度图像,在另外一些文章中又等同于黑白图像。

转换公式
  1. 浮点算法:Gray = R * 0.3 + G * 0.59+B * 0.11
  2. 整数方法:Gray = (R * 30 + G * 59 + B * 11)/100
  3. 移位方法:Gray = (R * 76 + G * 151 + B * 28)>>8;
  4. 平均值法:Gray =(R + G + B)/ 3;
  5. 仅取绿色:Gray = G;
为什么要选取灰度图像?

字符串图像,意味着图像的每一个像素均是使用一个字符进行表示的。而字符是一个一维的变量(在这种条件下,我们忽略了每一个字符的字体、颜色、字号差别)。所以我们需要一个同样是一维的图像——灰度图像

如何将灰度像素转换成字符串

这里提供一个灰度值对应的字符串表示数组:

@[@"$", @"@", @"B", @"%", @"8", @"&", @"W", @"M", @"#", @"*", @"o", @"a", @"h", @"k", @"b", @"d", @"p", @"q", @"w", @"m", @"Z", @"0", @"o", @"Q", @"L", @"C", @"J", @"U", @"Y", @"X", @"z", @"c", @"v", @"u", @"n", @"x", @"r", @"j", @"f", @"t", @"/", @"\\", @"|", @"(", @")", @"1", @"{", @"}", @"[", @"]", @"?", @"-", @"_", @"+", @"~", @"<", @">", @"i", @"!", @"l", @"I", @";", @":", @",", @"\"", @"^", @"", @"'", @".", @" "]`

我们根据对应灰度图像的每一个像素的Gray值,获取对应Gray值的百分比(即 Gray * 1.f / 255.0)。然后在根据百分比,获得对应的字符,拼接成一个完整的字符串。这个字符串,便是字符串图像

流程图解

过程实现

我们已经分析过基础原理了,接下来开始编写应用吧

首先当然是视频了,如果想直接观看原视频,请点击这里

OpenCV 配置

什么是OpenCV?

OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。

iOS 配置OpenCV

一共有三种方法可以配置OpenCV

  1. 直接从源码编译(不过多介绍,因为我也不是很了解)
  2. 从CocoaPod导入(因为折腾起来感觉很费劲,因此也不过多介绍)
  3. 下载打包好的iOS Framework

这里我只介绍第3种

我们创建好对应工程后,将解压过的Framework拖入到项目后我们需要添加如下依赖库:

AVFoundation.framework
AssetsLibrary.framework
CoreMedia.framework
CoreVideo.framework
复制代码

这里是我目前为止需要的依赖库,用以保证我们的项目编译不报错

处理图像

首先,因为OpenCV是c++ 代码,所以我们所有希望和OpenCV进行交互的类,后缀均需要改成.mm文件以使编译器识别c++ 语法

接下来导入头文件

#import <opencv2/opencv.hpp>
#import <opencv2/imgproc/types_c.h>
#import <opencv2/imgcodecs/ios.h>
#import <opencv2/videoio/cap_ios.h>
#import <opencv2/core/core.hpp>
#import <opencv2/highgui/highgui.hpp>
复制代码

这些头文件需要在我们导入其他文件之前导入,也就是说需要写在最上面,否则会报错。

接下来我按照上面的步骤依次写出图像转字符串操作:

// 先声明一个结构体用以标明长和宽
typedef struct{int width, height;
}SizeT;
复制代码
  1. 图片缩放
/// 根据给定大小缩放图片
- (UIImage *)resizeImage:(UIImage *)image withSize:(SizeT)size {/// cv::Mat 对象为对应的图片的二维数组对象,我们可以很方便使用角标进行数组操作cv::Mat cvImage;/// 将UIImage对象转换为对应cv::Mat对象UIImageToMat(image, cvImage);cv::Mat reSizeImage;/// 重新赋值大小cv::resize(cvImage, reSizeImage, cv::Size(size.width, size.height));/// 释放cvImage.release();/// 生成新的UIImageUIImage *nImage = MatToUIImage(reSizeImage);/// 释放reSizeImage.release();return nImage;
}
复制代码
  1. 彩色图转换为灰度图片
- (UIImage *)grayImage:(UIImage *)image {cv::Mat cvImage;UIImageToMat(image, cvImage);cv::Mat gray;// 将图像转换为灰度显示cv::cvtColor(cvImage, gray, CV_RGB2GRAY);cvImage.release();// 将灰度图片转成UIImageUIImage *nImage = MatToUIImage(gray);gray.release();return nImage;
}
复制代码
  1. 将灰度图片转换为字符串
- (NSString *)convertImage:(UIImage *)image {cv::Mat gray;UIImageToMat(image, gray);// 获取一共多少列int row = gray.rows;// 获取一共多少行int col = gray.cols;// 初始化字符串数组 用来存储图片的每一行NSMutableArray <NSString *>* array = [NSMutableArray arrayWithCapacity:row];// 给定字符串灰度对应值NSArray *pixels = @[@"$", @"@", @"B", @"%", @"8", @"&", @"W", @"M", @"#", @"*", @"o", @"a", @"h", @"k", @"b", @"d", @"p", @"q", @"w", @"m", @"Z", @"0", @"o", @"Q", @"L", @"C", @"J", @"U", @"Y", @"X", @"z", @"c", @"v", @"u", @"n", @"x", @"r", @"j", @"f", @"t", @"/", @"\\", @"|", @"(", @")", @"1", @"{", @"}", @"[", @"]", @"?", @"-", @"_", @"+", @"~", @"<", @">", @"i", @"!", @"l", @"I", @";", @":", @",", @"\"", @"^", @"`", @"'", @".", @" "];;for (int i = 0 ; i < row; i ++) {NSMutableArray <NSString *>*item = [NSMutableArray arrayWithCapacity:col];for (int j = 0; j < col; j ++) {// 取出对应灰度值int temp = gray.at<uchar>(i, j);// 计算灰度百分比CGFloat percent = temp / 255.f;// 根据百分比取出对应的字符int totalCount = (pixels.count - 1) * percent;// 加入到字符串数组里[item addObject:pixels[totalCount]];}// 将数组转成字符串[array addObject:[item componentsJoinedByString:@" "]];}gray.release();// 返回分好行后的字符串return [array componentsJoinedByString:@"\n"];
}
复制代码

这些步骤操作完毕后,我们剩下的最后一个步骤,就是将字符串显示在Label上。

一些iOS上的坑
  1. 字符串图像首先得需要保证是等宽字体(因为非等宽字体将会产生图像移位,显示错乱),但是系统标准字体又是非等宽字体。

解决方案: 采用等宽字体Courier

  1. 在iOS上,UILabel如果采用居中设置的话,字符串渲染过程中可能出现撕裂

解决方案: UILabel请全部采用默认设置(左对齐),如果需要居中,最好采用AutoLayout将Label设置居中

处理视频

视频的处理其实就是将视频的每一帧转换成图像,然后将图像转换成字符串。播放就是按照视频原有的每帧间隔将字符串显示在屏幕上,于是就变成动画了。

具体细节就不过多赘述了,可以看对应demo

结尾

图像处理其实是很高深的学科,这里我只是很简单的将图像转换为字符串。

如果大家对于这个有什么疑问,也可以关注本人公众号,并私聊。看到都会回复并解答的

iOS实现字符串动画相关推荐

  1. iOS学习——核心动画之Layer基础

    iOS学习--核心动画之Layer基础 1.CALayer是什么? CALayer我们又称它叫做层.在每个UIView内部都有一个layer这样一个属性,UIView之所以能够显示,就是因为它里面有这 ...

  2. 一步一步教你实现iOS音频频谱动画(一)

    如果你想先看看最终效果再决定看不看文章 -> bilibili 示例代码下载 第二篇:一步一步教你实现iOS音频频谱动画(二) 基于篇幅考虑,本次教程分为两篇文章,本篇文章主要讲述音频播放和频谱 ...

  3. iOS CAReplicatorLayer 简单动画

    代码地址如下: http://www.demodashi.com/demo/11601.html 写在最前面,最近在看学习的时候,偶然间发现一个没有用过的Layer,于是抽空研究了下,本来应该能提前记 ...

  4. ios 怎么判断字符串的字节数_如何用IOS判断字符串是不是纯数字

    我们在开发项目的时候经常会需要我们只输入一段纯数字,当我们在输入这段数字后就需要对字符串进行判断,看看是不是符合纯数字,那么你知道如何用IOS判断字符串是不是纯数字吗? 下面介绍几种判断字符串是否为纯 ...

  5. iOS 视图,动画渲染机制探究

    腾讯Bugly特约作者:陈向文 终端的开发,首当其冲的就是视图.动画的渲染,切换等等.用户使用 App 时最直接的体验就是这个界面好不好看,动画炫不炫,滑动流不流畅.UI就是 App 的门面,它的体验 ...

  6. ios去掉字符串中的某个字符_iOS 截取字符串中两个指定字符串中间的字符串方法...

    例如,要截取一个字符串中,两个指定字符串中间的字符串,OC截取方法如下: // 要截取 "> 和 之间的汉字内容: @implementation ViewController - ( ...

  7. 一步一步教你实现iOS音频频谱动画(二)

    如果你想先看看最终效果再决定看不看文章 -> bilibili 示例代码下载 第一篇:一步一步教你实现iOS音频频谱动画(一) 本文是系列文章中的第二篇,上篇讲述了音频播放和频谱数据计算,本篇讲 ...

  8. iOS CoreAnimation 核心动画系列博客索引

    学了这些文章能做什么,了解核心动画各个类能做什么,产品有些简单的视图平移.旋转.折叠.抖动的需求,都能搞了 我们写博客的目的是学习研究之后做记录,捎带让别人指教,就是这么简单 博客文章都是对同一个领域 ...

  9. iOS 最全动画教程(基础)

    IOS 最全动画教程(基础) 大家好,做了这么久的iOS开发,没有系统性的总结过iOS某方面的知识点,总觉得有些地方还是不太了解,查阅各种资料,加上平时开发的经验,因此准备写关于动画系列的总结.作为开 ...

最新文章

  1. tomcat 修改默认访问根目录
  2. CSS 实例之翻转图片
  3. Qt文档阅读笔记-QSslSocket中与错误相关的信号
  4. [心得]编写服务端的相关设计心得及体会
  5. 常用排序算法及其实现
  6. 丰巢回应小学生用照片“刷脸”取件;苹果明年或发布四款 5G 手机;Spring Boot 2.2.0 发布 | 极客头条...
  7. java获取响应网页源代码
  8. (九)OpenCV Canny边缘检测
  9. 《Java技术》第七次作业计科1501赵健宇
  10. SLAM学习笔记-------------(12)建图
  11. 一天搞懂深度学习--深度学习简介
  12. Android使用蓝牙录音和播放
  13. 关于跨境电商shopee平台,你了解多少?
  14. python-科研绘图系列(7)-箱型图(盒型图)
  15. Centos 7 安装Redis
  16. 电脑上可贴至桌面显示的便签软件
  17. 分形--Cantor三分集
  18. java ico图标_javaweb中如何给自己的网站更改ico图标
  19. 4 位硬科技创始人对谈 DevOps 硬件实战
  20. R语言里的非线性模型:多项式回归、局部样条、平滑样条、 广义相加模型GAM分析

热门文章

  1. 个人简历小程序前端源码
  2. 高性能Web框架FastAPI v0.62.0
  3. 星宿UI V1.1.2 跳转小商店+ wordpress微信小程序
  4. Java快速入门学习笔记1 | Eclipse使用
  5. WordPress简约博客主题模板Chen主题V1.2
  6. 用WebService实现调用新浪的天气预报功能
  7. WordPress 主题教程 #2:模板文件和模板
  8. SQL Server 2005 Service Broker 初探 [摘抄]
  9. 九张 Gif 图回顾 Web 设计的 25 年历史
  10. php.ini详细介绍与设置,配置