前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >两个表情合成出新表情:复刻Emoji Kitchen!详解算法实现!

两个表情合成出新表情:复刻Emoji Kitchen!详解算法实现!

原创
作者头像
Mintimate
发布2024-02-10 14:32:41
3.7K0
发布2024-02-10 14:32:41
举报
文章被收录于专栏:Mintimate's Blog
头图不能少( ◔ ڼ ◔ )
头图不能少( ◔ ڼ ◔ )

博客:https://www.mintimate.cn Mintimate’s Blog,只为与你分享

新年快乐嗷。给大家分享一下Emoji合成,助力欢乐加倍!让我们看看两个Emoji表情,可以合成出什么新表情,丰富聊天内容,让对话更加有趣!

好耶
好耶

Emoji Kitchen 是由 Google 键盘 Gboard 推出的功能。它允许用户将两个不同的 emoji 进行组合,创造出独特的表情符号。

用户可以在 Google 搜索中输入 Emoji Kitchen 来使用这个功能。生成的新表情以图片的形式呈现,用户可以方便地复制并粘贴到他们的聊天应用程序或社交媒体中。

可能相比一些工具,两个Emoji合成出新的EmojiMix,似乎并没有什么作用;但是就和表情包一样,单论本身,说起来是没有意义,但是却实打实地丰富了聊天内容,让对话更加有趣。

Emoji Kitchen

Emoji Kitchen 可以在Google的搜索引擎上搜索Emoji Kitchen,即可体验Emoji的合成:

Emoji Kitchen
Emoji Kitchen
Demo使用
Demo使用

我们可以选定两个Emoji,合成出新的Emoji:

合成游戏机
合成游戏机
合成降落伞🪂
合成降落伞🪂

它是如何做到图片合成的呢? 是现在很火的AIGC,由AI对两个Emoji进行合成么?

合成信息
合成信息

其实并不是,早在2019年底,就有Emoji Kitchen,那个时候,GPT-2刚刚发布,可以生成自然语言文本,但质量和多样性有限,远远不及现在的GPT3.5,更不用说是可以处理图片的AI了。

当然,不排除Google有算法,在2018年时候就使用图形处理,实现合成Emoji的AI;但是这种可能性很低,大概率还是设计师设计制作。

求生欲拉满
求生欲拉满

不过,在搜索引擎上使用,有一些不优雅,容易被其他搜索结果所干扰;更重要的是,中国大陆用户无法访问,我们可以试试第三方复刻版本的Emoji Mix。

总揽视频

部分东西,还是视频比较清晰。

这里做个视频,主要内容:

  • 展示Emoji合成效果;
  • 解释Emoji合成原理;
  • 介绍如何复刻和实现EmojiMix算法。

可以访问一下网站进行配套视频的查看:

复刻Emoji Mix

其实有非常多的Emoji Kitchen复刻版本,为了区别于Google官方的Emoji Kitchen,这里我们粗略地都称作:Emoji Mix。一般Emoji Mix都是使用Emoji Kitchen的图片源…… 我使用Python爬取了Google Emoji Kitchen,发现累计到现在,大概有5w张图片,占用空间500MB,估计很多网站都不会专门存储……

比较常见的Emoji Mix有很多,我们枚举一些。

OnlineTool EmojiMix

哈哈,首先当然是我复刻的版本:

效果图如下:

我复刻的版本
我复刻的版本

左侧进行Emoji的合成检录,右侧Emoji进行结果的筛选。点击中间的结果区可以进行合成后的Emoji下载:

使用效果
使用效果

还有什么惊喜呢? 大家可以自己探索一下。

Emojimix By Tikolu

接下来的选手,相信大家也非常熟悉了:

效果图如下:

EmojiMix Tikolu
EmojiMix Tikolu

EmojiMix Tikolu也是非常好用的Emoji Mix版本;点击左侧的搜索🔍按钮,可以进行检录:

检录Emoji表情
检录Emoji表情

不过,或许是为了适配动态Webp原因。EmojiMix Tikolu只选取了含有动态Webp的Emoji进行展示和参与合成,没有动态Webp的就不进行展示和参与合成了。举个动态Webp的例子:https://fonts.gstatic.com/s/e/notoemoji/latest/1f62f/512.webp

Emoji Tikolu使用Webp进行展示
Emoji Tikolu使用Webp进行展示

说实话,我一开始并没有接触Google的Emoji Kitchen,就是小伙伴发EmojiMix Tikolu的链接🔗给我,我玩了大半个下午…… 甚至,后来选择一张Emoji合成图片,作为自己的头像(后来觉得太阳光了,还是应该深沉一些就换掉了)。

进入烤箱
进入烤箱

Emoji Kitchen React

最后介绍一个重磅选手,实际上官方项目名字叫Emoji-kitchen,但是我为了和Google进行区分,并且它是使用React进行技术实现的,所以我这里就给它取个别名啦:

和上文一样,我们看看效果:

emoji-kitchen 效果
emoji-kitchen 效果

是不是感觉和我的OnlineTool EmojiMix很相似? 没错,我就是看到这个项目后,发现这个项目使用React实现,而我使用Vue + Nuxt进行了复刻。

为什么说是重磅选手呢?其实是因为它还开源了:

同时,整理了Google Emoji Kitchen的直链文件:

直链文件(就是有点大)
直链文件(就是有点大)

2024.02.09 这个大文件已经被移动到CI/CD 里再下载了,可以查看这次commit: Move large file download to CI/CD

如果大家想复刻和实现更好的Emoji Mix,可以参考这个项目。

Emoji合成请求

知道了那里可以体验到合成的Emoji;有没有小伙伴还是想知道两个Emoji,如何变成一个复合Emoji呢?

实际上,如果你查看Google Emoji Kitchen 页面的源码,你会发现:

  • 用于合成Emoji的原始Emoji,实际上是SVG格式的,而合成后的Emoji是PNG格式的。
  • SVG格式和PNG格式的Emoji文件名由Unicode的编号进行组成。
Emoji请求
Emoji请求

也就是,我们可以把它当作API地址,对其进行请求得到我们的Emoji合成图片。

如何获得Emoji的Unicode字典,并且判断那些Emoji相互组合,Google Emoji Kitchen有对应的Emoji合成图片呢?我们就可以使用重磅选手提供的metadata.json字典:

metajson字典
metajson字典

下滑可以发现更多惊喜:

下滑查看data内容
下滑查看data内容

data内,我们就可以看到哪两个Emoji组成可以合成新的Emoji。于是,我们就可以使用Python,对这个文件进行解析。

另外,正如上文所说,metadata.json已经被移动到CI/CD里,也就是在构建这个React项目并部署的时候,才会进行下载:

在CI/CD中,进行metadata.json的下载
在CI/CD中,进行metadata.json的下载

所以,如果你想查看metadata.json,可以直接访问下载地址。

解析原始Emoji

首先是解析原版的Emoji,其实我们可以直接用metadata.json里面的knownSupportedEmoji进行数据提取。但是我另辟蹊径了一下……

既然我们是准备使用knownSupportedEmoji配合API地址,请求出Emoji的SVG文件。为什么我们不直接下载渲染好的Emoji SVG文件呢?

所以,再次回到我们的重磅选手

https://emojikitchen.dev/;这次我们不查看Github仓库,直接访问页面,并且打开 F12 开发者调试,查看页面内容:

查看页面内容
查看页面内容

你可以发现,所有的Emoji SVG已经在页面的div内展示,并且每个元素包含SVG的地址:

代码语言:html
复制
<li class="MuiImageListItem-root css-kxftp1" style="height: auto; grid-column-end: span 1; grid-row-end: span 1;"><img loading="lazy" width="32px" height="32px" alt="stuck_out_tongue" src="https://raw.githubusercontent.com/googlefonts/noto-emoji/main/svg/emoji_u1f61b.svg" class="MuiImageListItem-img"></li>

很简单啦,我们只需要复制这个div,直接使用正则表达式提取所有链接并下载即可(SVG_RAW为div内容):

代码语言:python
代码运行次数:0
复制
pattern = r'src="(.*?\.svg)"'
matches = re.findall(pattern, SVG_RAW)

最后下载的结果:

下载的SVG文件
下载的SVG文件

在Vue上进行展示,我们需要对文件名字符串做一些处理,主要是根据长度,对©️ 和 ®️ 进行长度截取:

代码语言:html
复制
 <img loading="lazy" :alt="`Emoji_${item.item}`"
               :src="`/img/emoji/svg/emoji_u${item.item.split('-')
                        .filter((x) => x !== 'fe0f')
                        .map((x) => x.padStart(4, '0')) // Handle ©️ and ®️
                        .join('_')}.svg`"
               :class="!ignoreDisable && item.disabled ? 'opacity-30 cursor-not-allowed':'cursor-pointer hover:scale-150 transition-transform duration-150 ease-in-out'"
               class="w-8 rounded-lg hover:ring-2 hover:ring-blue-200 hover:bg-amber-50/10 cursor-pointer
                            hover:scale-150 transition-transform duration-150 ease-in-out"/>

当时这样似乎不是很智能,每次都要人手动访问网站,F12复制元素,能不能更加智能一些?免去手动打开浏览器的操作?

这个时候,我们就可以引入selenium,自动让Python自动调用浏览器:

代码语言:python
代码运行次数:0
复制
from bs4 import BeautifulSoup
from selenium import webdriver

def scan_svg_raw():
    options = webdriver.ChromeOptions()
    options.add_argument("--headless")
    driver = webdriver.Chrome(options=options)
    driver.get("https://emojikitchen.dev/")
    # 等待5秒让页面完全渲染
    time.sleep(5)
    # 获取页面源代码
    page_source = driver.page_source
    # 关闭浏览器
    driver.quit()
    soup = BeautifulSoup(page_source, 'html.parser')
    # 找到第一个 class 为 "MuiBox-root css-1uithqi" 的 div
    target_div = soup.find('div', class_='MuiBox-root css-1uithqi')
    # 获取该 div 内的全部内容
    content = target_div.prettify()
    # 将内容写入文件
    with open('source/svg_raw.txt', 'w', encoding='utf-8') as file:
        file.write(content)
自动扫描完整div
自动扫描完整div

有小伙伴可能会问,为什么不用requests库呢? 这个就要说了,网站实际是React渲染的,在页面使用JavaScript加载完成前,页面只有一个<div id="root"></div>的占位符,并没有实际内容:

id为root的占位符
id为root的占位符

解析合成Emoji

原始的Emoji已经解析完成,合成后的Emoji呢?这次就不要再“造轮子”,直接使用metadata.json里的内容即可,但是这里还是提一下我的方法。

最初metadata.json里的内容是这样的:

初代版本metadata.json
初代版本metadata.json

可以看到,体积比现在50MB版本的小很多;可能是官方觉得,他们的服务器性能比较好,所以在新版本metadata.json内,直接暴露了合成后的Emoji Kitchen地址:

直接暴露Emoji Kitchen地址
直接暴露Emoji Kitchen地址

那么,我基于初代版本,是如何处理的呢?其实很简单:

代码语言:python
代码运行次数:0
复制
def get_download_url(json_object):
    root_png_dir = 'pngs/' + json_object['date'] + '/'
    if not os.path.exists(root_png_dir):
        os.makedirs(root_png_dir)
    left = "-".join(["u" + part.lower() for part in json_object['leftEmoji'].split("-")])
    right = "-".join(["u" + part.lower() for part in json_object['rightEmoji'].split("-")])
    date = json_object['date']
    return f'https://www.gstatic.com/android/keyboard/emojikitchen/{date}/{left}/{left}_{right}.png'

是不是还算巧妙?

json_object作为输入,并从中提取dateleftEmojirightEmoji的值。然后,它根据这些值构建了一个用于下载的URL的文件路径。下载URL以格式化字符串的形式返回。

当然,面对新版本的metadata.json,我们可以直接获取JSON内的data内,每个对象combinations数组内的gStaticUrl内容:

代码语言:python
代码运行次数:0
复制
def get_download_url_from_metadata():
    with open(JSON_FILE_FULL, 'r') as f:
        # 读取整个文件内容
        json_data = json.load(f)['data']
    # 遍历"data"内的对象
    for obj in json_data.values():
        # 获取每个对象的"combinations"数组
        combinations = obj['combinations']
        # 遍历"combinations"数组
        for combination in combinations:
            # 获取每个组合的"gStaticUrl"属性
            static_url = combination['gStaticUrl']
            # 添加下载任务到Aria2内进行多线程异步下载
            add_mission_to_aria2(static_url)

END

好啦,本次的Emoji Mix复刻介绍就到这里啦。

总的来说,解决了Emoji Kitchen的一些小痛点。虽然实现的过程可能比较麻烦,但是实现的结果可以让更多人体会到Emoji表情的内涵,也是挺不错的。与此同时,也是使用Python进行数据清洗的小小Demo。

大家新年快乐,希望Emoji的合成,能给大家再增添一些欢乐。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Emoji Kitchen
  • 总揽视频
  • 复刻Emoji Mix
    • OnlineTool EmojiMix
      • Emojimix By Tikolu
        • Emoji Kitchen React
        • Emoji合成请求
        • 解析原始Emoji
        • 解析合成Emoji
        • END
        相关产品与服务
        云服务器
        云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档