[Discode] 生成 & 识别Discode

简介

书接上文,在上一章节中,我详细的分析了市场上已经落地应用的部分商用方案,也针对自己的实际需求进行了思考,设计了适合需求的编码规范和编码形式。在本章节中,我将会分享一下Discode的生成和识别过程和技术细节。

目录

  1. 生成Discode
  2. 识别Discode
  3. Github仓库
  4. 编后语
  5. 版权声明

生成Discode

如何生成图形编码?

在前面的设计原型中,Discode中包含四个定位点的设计。按照设计Discode的定位点类似于微信小程序码的定位点,基础元素是由一个圆环和一个圆点组成的图案。

定位点

之后会将其等距离的放置在图形编码的四个角上,用于图形的定位,如下图所示。

确定好定位点之后,我们就需要生成我们的图形编码了。图形编码包含两个部分:

一、用什么规则来代表数据?

参考条形码的设计,我决定通过点与线来分别代表0和1。之所以会有这样子的想法,是我认为在之后的学习研究识别过程中,点与线的识别应该会有更多现成的代码可以参考学习,不用自己再花大量时间来研究。

基于这种想法,通过简单的编程在canvas上生成了上图的DEMO图形,拥有五个定位点与按照一定规则环状点线的编码区所组成的Discode。(之所以在图形的中心也包含一个定位点,主要是当时想用来确认圆心是否能够被计算正确,所以增加的辅助图形,在技术验证后就被品牌Icon代替。)

二、存储数据量要设计多大?

在之前的原型设计中,我曾经分析过小程序拥有多种容量的设计,比如36线、72线、144线等设计。通过增加线密度来增加图形的数据承载量。因此我也对此进行了一些简单的实验。

上图是每隔五度绘制一位数据的72线版本的Discode,可以很容易的看到,在内圈的1-3层,由于图形之间的间隙过小,很容易产生图形与图形间粘连在一块的问题,特别是第二圈右下角的多线段连在一块很难辨别的问题。

题外话

那为啥微信小程序可以支持72线?

通过观察微信小程序的设计规范可以发现,之所以元信息区并不是从最内圈开始的原因:就是为了解决72线可能会导致图形绘制过于密集,导致编码图形难以被识别和处理。而选择了往外移了几圈,才开始进行实质性的编码。

微信小程序码的编码设计

对比实际编码出来的图形,我们可以发现,为了美观考虑,小程序码在元信息区往圆心方向的编码区其实只有36线,即10度才记录一个编码,只有在元信息区才开始使用72线,即5度进行一个编码。

那问题就迎刃而解了,要么就是将实际数据编码区往外移,要么就是减少单圈编码密度。最终我还是选择了减少单圈编码密度作为我的解决方法,之所以选择这个方法就是图省事,简单快速的解决问题,不然将编码区外移又需要耗费一部分的时间来重新设计编码规范,我着实是不想这么干。

增大到10度一编码后,图形的视觉效果就好多了,另外也部分程度上的解决了图形粘黏的问题。解决了编码问题后,我们只要将定位点、编码区组装起来就是我们设计出来的Discode了。

其实到这一步Discode就已经生成完成了,只要在中间预留的空白处填上我们希望填充的Logo即可。

识别Discode

识别Discode主要有以下的几个步骤:

  1. 使用Hough Circle获取定位点的圆心坐标

通过Hough Circle Transform获得四个定位点的相对于图片的位置信息。

  1. 通过四个定位点计算编码区圆心位置

接下来连接对角点,形成两条线段(红线与蓝线),计算交点位置。

如上图顺序对应0-3的四个坐标代入公式计算得出圆心坐标。

  1. 设置ROI(Region of interest)识别指定区域

Discode的编码起点如下图所示:

Discode从上图的矩形框中开始生成第一位编码,然后在相同半径内沿着逆时针方向(红箭头),生成接下来的编码,当一圈编码完成后就自增半径,开始第二圈的编码直到编码五圈为止。

而识别其实就是逆向这个过程,如上图设置图像的ROI到图像的编码开始点,然后逆时针一个一个识别,一圈一圈识别,直到识别完成。

  1. 使用Canny edge detection获得识别区的轮廓

在上一步中,我们设置了图像的ROI,接下来我们要做的就是计算这个ROI内的图形到底代表的是0还是1。

识别的核心原理:计算ROI区域内的图形的面积。

之所以我们可以这么做,是因为我们已知ROI的面积信息,我们也知道长线段占用的面积理应大于短线段的常理,基于这两个信息,我们只要计算ROI内图形面积,并通过经验设定一个阈值来判定是长线段还是短线段。知道线段类型后,转换成0和1就水到渠成了。

这里我们引入了Canney边缘检测,通过边缘检测获得ROI内图形的轮廓数据。

  1. 通过contourArea函数计算轮廓面积

获得轮廓数据后,我们就可以计算出ROI中的闭合图形个数以及总面积信息,之所以有时候个数会大于1,是因为有时候ROI会重复识别到上一个图形的边缘,导致到污染了识别区。不过由于这种现象仅仅发生于长线段的交接处才会发生,且数据影响不大,因此我也没有做进一步的处理。如果要继续优化,可以继续精细化ROI区域,使得覆盖率提高。或者调整生成图形算法,加大线段之间的间隙,避免互相粘黏。

  1. 判定图形代表0或1

通过多次的实验可得,短线段的占用的面积必定小于10,大于10的必定是长线段。因此在这里使用10作为阈值,用于判定ROI内的图像是代表0或1。

  1. 分割 & 转换

将每个图像代表的二进制数值存入数组当中并将其按照6bit为一位通过编码字典,重新转换成可阅读的字符串。

  1. 输出结果

由于有时候编码的字符不一定会用完全部可用编码位,因此还会在有效编码后面加入一些随机数据作为填充,使得图形更加美观。

Github仓库

https://github.com/7gugu/Discode

仓库中包含了完整的生成和识别图形代码,可以自行运行学习一下。实测通过FireFox 100是可以正常运行的。

编后语

至此整个Discode系列就全部更新完成了。原来在这个部分我思考了很久,写了几个版本的内容,先是是过拆分成两个章节来慢慢讲解,也试过回溯历史结合QRCode来阐述为啥我要这么做,但效果都不尽如意,过于的繁琐冗余,最后还是秉着少即是多的原则,缩减成一章来讲解。五月中的时候恰好碰上了组内的技术分享,有幸向其他同事分享了我的这个想法,也得到很多宝贵的建议。之后由于毕业设计和工作上的琐事,使得进度很慢,对此向期待这篇技术分享的朋友说声抱歉。接下去我应该会专注于wasm和三维建模上,希望以后可以投入游戏产业,继续实现个人梦想。

版权声明

知识共享许可协议

本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。

[日常碎碎念-特别篇] 五年前给自己做的语音时间胶囊

这个录音的声音真的好陌生,不知不觉就过去5年了,5年前我还在高中摸🐟摆烂,怎么也想不到五年后的自己居然能够如愿进厂打工,也算是没有愧对五年前对自己的期望了。(不过我还是没去找女朋友,继续寻找吧,应该能找到的,希望。)科技在疫情的大背景下其实也没啥太大的发展,可能探月探火这种航天技术的发展也是相对巨大的吧。

最近自己都在忙工作和论文,Discode的文章虽然还在写,但进度还是很慢。周末仅有的两天假期,我还是更愿意花一天时间到处走走,而不是宅在家里写代码,或许哪一天我逛累了就会回归初心继续coding吧,不过谁知道呢?能够安心、平淡的摸鱼其实也不错,能够免于裁员,能够混口饭吃就是幸福感了吧。想家了,虽然交通很方便,回家所需的时间跟大学回家的时间也是相同,但毕竟是背井离乡,还是想念的。朋友都在家乡找饭吃,感觉出来打工也没啥朋友,好孤独呀。此时此刻的我,喝着啤酒,吃着牛肉干,在这发着水文,一时间不知道应该写啥,就先到这里吧。明天也要继续加油了,平安喜乐。

日常碎碎念 2022.04.23

前言

忙里偷闲,明天周日要补五一假期的班,趁着这周是逐渐恢复正常节奏的一周来更新一下碎碎念。之前一周的死亡冲刺真的是快把我搞死了,周一交第二版论文,周三查重截止,白天要上班,晚上通宵两晚到3点赶论文实在是刺激。万幸的是有一个通人情的leader,我也提早跟leader打了预防针,不然再来点活我就真的崩溃了。

回顾

1. 独立开发者流量变现计划的开始

这个是我在2022年的一个新增的大目标,就是实现2022年全年度独立开发收入突破800元(刚好可以cover掉我的Apple Developer License的费用😂)。原因是最近我给课表小程序恢复了封面广告并借着学校课程表瘫痪的空白期(2个月),赚了140多元的广告收入。虽然这收入对于我的月收入而言实在是微不足道,但好歹也是自己除正职工作外的被动收入了,积少成多嘛。所以我还是希望在今年内继续开发一些独立的应用来帮助我赚取更多的被动收入,另外其实也确确实实帮助到了一小部分的用户,解决了他们的一些日常难题,从多方面都有所收获,也是会令人开心的。

小程序最近一个月的收入数据

wTodo的月收入数据就有点惨不忍睹了,不过作为开发者而言,我认为当前的体验仍然不太好和宣发做的不到位,因此接下去的一段时间我会认真学习一个swiftUI把界面和部分逻辑完善一下,预计9月的时候再跟大家分享一下我的进度吧。

2. 入手Xbox series S

背景

3月中的时候深圳的疫情还是较为严重的,当时除了每天要核酸检测,还不允许外出购物,只能困在家里远程办公。说实话头两天在家里办公还是挺新鲜的,但新鲜劲过去之后就是无尽的无聊和焦虑,天天就是床、电脑、手机之间来回切换,出租屋很小(真·家徒四壁),周末在家就只能看抖音和B站,电脑又玩不了游戏,属实是把我给憋坏了。好在深圳市政府的果断处理(当然也是因为钞能力),在一周内解决了问题,工作生活马上就回到正轨上了。但无聊感空虚感和焦虑感还是给我留下了深刻的印象,因此决定入手一台游戏机,避免宅在家里无聊。(另外出来打工的一个好处就是花自己的钱,不用再问他人意见了)

Sony大法 or 巨硬?

家里从90年代起就是忠实的Sony党,一直都是买的Sony的电视机。因此我也一直偏爱于Sony的产品,从PSP到PS4、PS4 Pro我都有入手。可能是因为我手大和爱出汗的缘故,我总是感觉PS的手柄很滑,搓着搓着一不小心就要把手柄给搓飞出去。19年的时候我去参加了机核的线下游戏展《核聚变》,游戏展里刚好就有Xbox的展台,因此跑去试了试Xbox的手柄。可能是欧美人种普遍较壮,所以Xbox的手柄有种很大很扎实的感觉,恰好满足我的需求,终于可以在搓遥杆的时候,不用担心把手柄给搓飞了,在那时候就已经埋下了入手一台Xbox的种子了。回到2022年,微软还有Xbox Game Pass Ultimate计划(简称XGPU,后面都会有XGPU作为代称),可以让玩家以极低的价格畅旺多款3A大作,更加坚定了我选择Xbox作为我的游戏平台的想法。

S or X?

对于不常玩主机的朋友,我在这里先跟大家交代一下Xbox series S和 Xbox series X有啥区别。首先在本世代的Xbox主机中,包含了两种机种:S系列和X系列。S系列是残血版,主要是提供一个基础平台,能玩次世代游戏,但不能达到次世代的画质(简单来说就是游戏可以玩,但画质一般);X系列是满血版,能玩次世代的游戏并且还能有最好的画质。

从PSP到PS4、PS4 Pro我都有入手,不过可惜的是拥有游戏机的时候还是学生党,能够自由支配的零花钱实在是有限,因此游戏机买到手的大部分时间里都是吃灰然后二手卖给朋友,自己实际的游玩时间真的很少很少。就算后续我自己也组装了台式电脑,从970到2060,即使有着强劲的计算性能,我却没有时间去发挥,着实是有点浪费了。

2020年开始的全球疫情真真切切的影响到了芯片工艺的生产,现在全世界都处于芯片荒的困境当中,前不久就已经听说有洗衣机企业在回收二手洗衣机的处理芯片用来做新的产品了,更不要提游戏机这种需要重计算的高精密芯片了,可想而知的紧缺。因此游戏机的价格也在水涨船高,不仅仅是国内涨价,海外的很多地区都在涨价,大家都有通过黄牛才能买到新的主机。国内的X系列的日版机器已经从原价的3899元涨到了5300元(京东),S系列的价格反而没啥变动(国内的策略主推的是S系列,所以X系列的机器很少很少,价格水涨船高也是在情理之中了)。

综合价格和游戏时间以及易搬运的特点,我最终还是去闲鱼收了一台准一手的日本Xbox series S。(最妙的是,这机器是原封的,而且比原价还便宜了30元,实在是爽到了)

加上卖家后,我惊奇的发现居然是同在电子厂里上班的同事,感觉这个世界真的好小哦。因此第二天晚上下班后火速打车去卖家那取回了机器。

这个白色跟出租屋里的电器都真的很搭了

之后的故事就很简单了,开机初始化,上某宝买个XGPU开造,从入手到今天为止,我总共玩了三个游戏,DOOM、杀手三部曲和甜甜圈大冒险,三个游戏都好好玩,而且在Quick Resume(快速恢复)的机制下,特别适合我这种上班族,随停随恢复游戏,真的是很赞。我还买了GTA5,打算在接下来的这段时间好好玩一下。

地平线右舵太奇怪了之后就被我卸载了

计划

1. 继续制作Discode的技术分享

(这周的技术分享上,我就向同事分享了一下,看起来大家都还是挺有兴趣的)

2. 玩GTA5

3. 等待毕业活动

4. 专心工作赚钱

5. 继续独立开发

尾声

时间总是飞快的,上一篇的碎碎念还是在2月份,本来原计划3月中也有碎碎念的,不过由于多方面的原因成为了废案停留在了草稿箱中,等以后有机会了,我再拎出来分享吧。希望大家喜欢我这次的碎碎念,祝大家平安喜乐。

[Discode] 设计Discode

简介

在本篇文章中我将一步步的阐述我设计Discode的流程以及我的思考点。虽然Discode作为一种编码仍然比较稚嫩,但作为入门自己的第一个图形编码仍然是不错的例子。

目录

  • 分析现有编码的设计
  • Discode的视觉设计
  • Discode的技术指标
  • Discode的编码设计
  • 编后语
  • 版权声明

分析现有编码的设计

当前世面上各家厂商为了用户纷纷都推出了自有的编码规范,仅仅在大陆地区而言,当前能够看到的自由编码普遍是圆形二维码,也有像是QQ小程序码的变种圆形二维码。

QQ小程序码

从这四种只有编码中我们不难观察出一个规律,大家的编码样式的元素基本都是:

  1. 图形编码环绕着Logo
  2. 四点定位

图形编码环绕着Logo

这种设计有两个好处:

  1. 具有高自由度的品牌露出的能力

开发者可以自由的定义自己的图标类型,使得用户一眼就能识别出编码对应的软件信息(比如广东省的粤核酸小程序的Logo是DNA双链+号码,用户扫描前就已经可以预测到自己扫描的是一个粤核酸的小程序)。

  1. 不占用实际编码区域

现有的二维码规范中,已经通过纠错编码的能力,来实现图片覆盖二维码后仍能识别的能力。但对于一个新生的图形编码而言,设计一个出色的纠错编码并不是一件容易的事情,即使套用现有的编码规范仍有可能因为经验不足等因素导致到后来Coding过程中出现一些不可预见的限制。因此将分开显示能够极大的规避掉初期编码水平不足给自己挖坑的风险。

有好处当然也是有坏处的:

  1. 需要开发全新的生成与识别规则

环形编码意味着不能直接复用二维码已有的生成能力也不能直接识别,所有的东西都需要从0开始。

  1. 编码容量有限

环状编码的本质就是在圆圈上作文章,比如使用点、线段等作为二进制中的1,空白作为二进制中的0,实现二进制编码成图像元素。受制于圆形的特性:一圈是360度,为了视觉识别的准确性和速度,一般都会设计为每5-10度的圆弧内记录一个编码。因此单圈的能够承载的编码都是有限的,比如小程序码就是设计了36线,54线,72线的小程序码。假如我们10度编码一位信息,则一圈最多可以编码36位二进制信息。同时自定义的编码还有长度限制,因此单圈的实际编码数量肯定是远远小于36位的。

思考:如何拓展容量?

圆形编码有两种扩大容量的方式:

1.使用更密集的图形(在更小的弧度内编码信息)

比如小程序码的36线就是每10度作为一个编码区,54线就是6.6度一个编码区,72线就是5度一个编码区。

2.扩大半径(增加圈数)

比如支付宝只有3圈编码区域,AppClips则是5圈编码区

2.四点定位

以小程序码为例,分别在左上右上左下设置了Mark Point(定位点),其实右下角的Logo也是一个定位点,不过他是一个特殊的定位点,需要使用特殊的计算方式确定真实的圆心(在此不赘述),最终微信是可以通过这四点的圆心坐标,计算出对角线交线的坐标点,而这个坐标点就是小程序码的圆心。另外通过这四个点还能确定编码的实际区域,方便进行透视变换矫正图形到正确的位置。

思考:定位点是必须的吗?

虽然定位点确实能够帮助我们进行很炫酷的图形变换来矫正图形到正确的形态,但对于刚刚入门图形编码的我来说这个也太难了吧!遂开始寻找有没有不需要定位点的图形码,没想到还真的有,那就是Apple为App小程序推出的AppClips Code。

那么问题来了,为什么AppClip码可以不要定位点?那它要怎么定位圆心?机器如何对其进行纠正?通过查阅设计文档得出的答案居然是:标准限制+人工对准。

文档地址: Human Interface Guidelines > App Clips > App Clip Codes

阅读了Apple的设计规范之后,我才悟到其实我们不需要强行考虑复杂的环境,我们完全可以设计一些标准规避到复杂环境的可能,让用户遵守标准就好了,这样子就可以规避到很多问题,极大的降低工程的技术难度,为后续的继续设计奠定了基础。

Discode的视觉设计

完成上一节的市场分析后,我们就可以开始思考一下我们的Discode到底要长什么样子了。

基于市面上的圆形码,我的初步想法是:通过定位点来定位图像,同样支持品牌Logo的露出,另外也需要支持可变容量。因此原型设计中我参考了小程序码的定位点设计,出于后期编码的简单化考虑和法务风险规避的考虑,我把小程序码右下角的官方Logo去掉,替换成为了定位点。如果日后需要增加官方Logo的话,则如下图所示可以在品牌Logo的右下角增加一个官方的小Logo。

对于可变容量我也思考了两种方向,增大圈数或者加大密度,考虑到半径的动态变化可能会对识别造成一些不可规避的难点,我还是选择了减小编码区所占用的弧度,来增加编码密度实现容量的可变性。为此我同样参考了小程序码的设计并根据圆弧的弧度为360度进行平均分割,设计了36区、72区和144区的编码区密度,其分别占用10度/编码区、5度/编码区、2.5度/编码区。为了容量和设计美观度的考虑,暂定的圈数应该为3圈,确保可以将Discode印刷于一个非常小的区块中。

Discode的编码设计

图像编码中最核心的部分之一就是数据的编码规则了,通过编码规则,我们才能将二进制的数据转换成特定的图形并组合成一块就可以生成出自己的图形编码了,反过来的就是识别的流程了,不过具体怎么做我会留到接下来的生成和识别的解析文章中来讲解。

设计编码主要是遵循以下的几步:

  1. 确定编码的使用场景(决定未来的可能场景)
  2. 确定编码的宽度(决定可以容纳多少的字符)
  3. 根据编码容量来调整实际可编码的字符
  4. 分配字符到编码规则
  5. 根据视觉调整编码规则(这一步会发生在生成Discode后才会进行,在《生成Discode》中会讲到如何调整)
  6. 确定最终编码规则 & 整理成编码字典

1. 确定编码什么字符

在这一步我们先要确定我们的使用场景:

  • 可以记录网址吗?
  • 可以记录图片吗?
  • 区分大小写字符吗?
  • 可以记录邮箱吗?
  • 我们需要考虑损毁吗?
  • 我们要考虑修复能力吗?
  • 如果要修复能力我们要支持多少百分比的恢复能力呢?
  • 中文字符要考虑吗?

这些都是需要我们根据我们的未来使用场景来预设的。在我们的本次的项目周期走,我认为网址信息和邮箱信息是必须的,因为这样子才能让Discode具有实际的落地场景。图片二维码一般都是依托于Base64来实现的,存储图片这种高密度信息,显然不是Discode的长处,因此不考虑实现。中文字符可以通过UniCode字符集实现,不过其本质还是特定字符+字母,因此实现特殊字符、大小写字母和数字的编码后就可以实现,因此可以考虑作为第二目标来实现。修复能力需要依托于支持校验的编码实现,本次开发更偏向于探究如何实现,因此参考AppClips的思路,我决定使用技术规范,来规避掉损毁的可能性,在此不考虑损毁修复的能力。

综合上述的思考:Discode的初步可编码字符就显而易见了,UniCode需要的&#;,邮箱网址需要要的@.,大小写字母和数字,一共67种字符。

2. 确定编码的宽度

按照计算机的二进制规范来看,我首先还是想到熟悉的[latex]2^{n}[/latex]次方,1 Byte = 8 Bit,但是8位二进制数最大可以代表[latex]2^{8}[/latex]=256个数字,对于需求中的67个数字而言冗余空间太多了,因此要进行一下缩减,那么要不就是使用7位128个,要不就是6位64个。128对于67而言冗余空间接近翻倍,太浪费了,但6位64个又存不下全部字符着实是让我有点苦恼。最终我还是选择了6位作为最终的编码长度,其中的原因主要是有两个,第一是编码密度可以达到100%,即每一位都会用于实际的编码当中,不会有冗余空间;第二则是6恰好与360的具有倍数关系,360/6 = 60,而60也恰好与2.5、5、10之间构成倍数关系,恰好满足144位、72位、36位的需求。因此出于这两点考虑选择了6位为最终的编码宽度。

3. 根据宽度来调整可实际编码的字符

确定了6位的编码宽度后,就确定了实际的容量了,即字符表最大可以存64个字符,那么大小写字符一种52个,数字字符10个,剩余2个空位。在使用场景中我有说过我的假设场景中存在用来存储邮箱地址和网址的想法,对于邮箱而言最重要的两个字符便是邮箱根地址,即@xxx.com中的@.,因此我选择了@.作为字符表最后两个空位所要代表的符号。

4. 分配字符到编码规则中

因为这次的开发中不需要考虑到纠错校验,因此分配到字符到编码规则中就很简单了,只要把所有可能出现的数字都列成表格,再一一对应填上就好了。

其中我还是有一点小考量的,开始符我设定为了.,结束符则是@,这其实是我的个人偏好而已,一个约定俗成的设定,其实换过来也是OK的。然后小写字母从000 001一直到011 010,而大写字母则是在则是最高位(第六位)设置为1,即100 001111 010,剩余的空间就用数字填空就好了。

到这里我的Discode的专属字符表就设计完成了,其实整个过程非常的简单有趣。另外一般而言,只要我们不外泄这张实际的编码表,其实基本上没人能够逆向这个图形编码的意义。(破解方法仍然是有的,只是成本问题,只要对方知道字符表大概能存哪些字符,通过一些数学统计方法仍旧是可以逆向出来的,不过对于Discode这样子的一个开源项目,其实没啥意义去逆向破解。)

Discode的技术指标

综合视觉设计和编码设计最终可以得出Discode的最终技术指标如下:

  1. 支持图像定位
  2. 支持30位的数据
  3. 支持a-z、A-Z、0-9、”@“、”.“共64种字符
  4. 支持自定义品牌Logo

编后语

说实话,其实这篇博文我觉得更像是我的一个思路的整理集,不太像一篇文笔流畅的技术解析文章,这点我确实意识到了。不过我还是想尽力分享一下我的思路出来看看能不能帮助到更多对此感兴趣的小伙伴,因为这实在是太有趣也太有成就感了。

版权声明

本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。

[Discode] 为啥要设计新的二维码系统?

这是《Discode的诞生与技术细节》系列文章的第一篇文章,分别讲述了为啥我会萌生设计一个新的图形编码系统、图形编码的技术指标以及未来的文章规划。

背景

2017年初的时候,微信小程序推出了它们自己的二维码编码系统,称作小程序码,也被大众称之为菊花码。这种新的编码系统着实是令我大开眼界,后续也了解到了Snapchat和Facebook自己也有编码系统,这些奇形怪状的图形编码系统着实吸引着我去了解它们的技术原理,但可惜的是,彼时的我恰逢高三冲刺阶段,并没有这么多的精力去学习和了解这些编码系统更深层次的技术原理,只可将其放在了自己的技术待办清单中。

起因

在2022年年初的时候,我有一天偶然在电梯间看到一个支付宝的广告,发现支付宝居然也按捺不住推出了自己的图形编码系统(支付宝小程序码介绍),这再一次勾起了我蠢蠢欲动的内心欲望:做一个属于自己的编码系统。

支付宝小程序码

成果

说干就干,由于恰逢春节期间,自己有很多的个人时间,因此可以集中比较大的一块时间进行集中的研究和开发。目前已经成功开发出了一个Demo版本的编码系统,这套编码系统我将其称作为DisCode系统,分别是Disc(光盘)和Code(编码)撮合成的一个合成词,读音类同Disco(迪斯科),之所以叫做这个名字,是因为其实际的解码过程就像是读取光盘的过程,而且图形也近似于一张光盘,因此被命名为Discode系统。下图的这个就是Discode编码,编码了v2ex.com。

Discode

技术指标

  1. 支持30Bit的数据*
  2. 支持a-z、A-Z、0-9、”@“、”.“共64种字符**
  3. 支持自定义品牌ICON

*:图像中的一个圈可以编码6Bit的数据,理论上是支持[latex]6x(x\geq 1)[/latex]Bit的数据

**:目前仅仅是设计了一一对应的原始编码,理论上是可以支持带纠错功能的编码的,这需要结合你的实际场景进行设计

计划

在接下来的三个月内,计划沉淀出两篇技术文章和完整可运行的项目来一步步的阐述我的思考、设计和编码流程:

  1. 《设计Discode》
  2. 《生成 & 识别Discode》
  3. 《Discode生成和识别源码》

希望通过这两篇文章和全流程的项目,能够帮到一部分需要开发或者想要了解这项技术的开发者或者爱好者。

版权声明

本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。

日常碎碎念 2022.02.20

前言

不知不觉又迎来了新的一年,在新冠疫情背景的笼罩下,2021年彷佛”SOU~”的一下就过去了,即使回看2021年的年终总结,看到自己经历了这么多,但感觉时间依旧过的很快,好似啥都没做就过去了,不免有点无力失落感。不过光明总在未来等着我们,我们也无需过分的失落,坦然接受砥砺前行就好了啦🤷‍♂️。距离上一次的碎碎念已经过去了2个月了(果然还是打破了自己半月一更的幻想),之所以拖更了这么久,最主要的原因还是大四准备毕业设计中🎓,因此花费了较多的时间进行测试和撰写论文。(不过也仅仅停留在写完了,我还没有校对格式)

回顾

1.开发全新的二维码标签系统

自从微信小程序码出来之后,我就一直很想了解如何开发一个自己的圆形二维码系统。但比较可惜的是,无论是国内或者国外都鲜有关于这个技术的开源文章,大多还是大公司内部开发的商用型编码规范,唯一与之类似的编码系统是一个叫做ShotCode的编码系统,来自于剑桥大学。后面通过翻阅了部分的专利和文献后,开始了自己的踩坑开发之旅,并最终开发了一套全新的编码系统。(设计完成后,我才发现与抖音码高度相似😂) 我把这套全新的圆形编码系统命名为Discode。下图就是将我的博客地址编码成为了Discode的样子。

编码信息:7gugu.com

至于为什么会叫做Discode,以及如何生成如何识别。我计划在未来的3个月中,分别通过4个章节的文章来阐述,欢迎大家到时候常回来看一下。

2.回公司搬砖

做完毕设后,就一直在家里面闲着了,天天都是打游戏。母上大人看到后,就天天催我去打工赚钱补贴家用,因此就开始一起做手准备租房和入职手续。啪的一下,很快啊!我就办妥租房手续和公司入职流程回公司搬砖了。由于2月份的实习生数量比较少,值得庆幸的是,我终于有了一张大桌子了,另外也配了一台4K的外接显示器(爽歪歪),美中不足的就是M1Pro没到货,只能先用着19款的i7比较不爽。不过我最近也在内网看到,转正后貌似可以申请换一台笔记本,因此希望未来能够用上M1 Pro爽一下吧。(白嫖M1 Pro,省下14999元) Leader和Mentor还是原来的同事,大家依旧是如此的友好,感觉在这样子的工作环境下工作还是挺舒服的了,除了内部项目文档太傻逼,没啥很严重的问题了。(u1s1,文档真的是太太太拉垮了,啧)

3.春节放烟花

春节的时候回了几天乡下,令人惊喜的是,乡下居然可以放烟花🎆,这让生活在城市中的我非常的高兴了。遂探访了多家小卖部,奇怪的是居然没一家有的卖烟花,这就非常的令人疑惑了🤔,晚上像防空炮突突突的烟花,怎么哪里都找不到有的卖?一开始我还以为是因为我们的口音的问题(误以为是外乡人),后来无意中在百度地图中看到了一个烟花专门店,因此抓紧机会开车去看了一下。

没想到最后找到的这一家看起来非常不起眼的小店铺,居然是拿了烟花营业执照的专门店,令我大吃一惊😂。正是拥有执照,这家小店铺可以公开销售超多的品类烟花,另外价格也非常的公道。

现在的烟花销售真的是与时俱进,几乎每种套装级别的组合烟花都可以扫码预览效果,不满意可以继续挑到满意为止,最终我们选择了268元60发的小套装尝鲜。

在当日晚上,趁着夜色,点燃了烟花的索引,pong、pong、pong一束束的烟花在天空绽放,绚烂的烟花寄托着我们对于未来的期望,希望新的一年越来越好吧!哈哈哈😊

5.正月初二海底捞宵夜

其实早在21年的时候,我就跟朋友提出这个想法💡了,令我高兴的是,拥有这两位愿意陪我一块疯的好友,感谢🙏。海底捞春节期间宵夜依然有大学生8.8折优惠,因此约上晚上0点大家一块吃一个宵夜。正月初二大家都要先去亲戚家吃饭,但吃完饭最多也就是21点种,于是大家还是决定先去骑车消磨一下时间,再去吃宵夜。遂一起骑车去了沙面岛逛gai,22点钟的沙面岛是真的安静啊,街上没了白天时分的才会有的新婚夫妇(大家都喜欢沙面岛的欧陆风情建筑,拍婚纱照很好看),也没有了小朋友嬉戏打闹的声音,一片寂静。

骑车到23点左右开始回程,准备海底捞宵夜。令我比较惊讶的是,即使是凌晨0点时分,海底捞内居然还有不少的顾客在里面用餐,其中不乏一起出来团建的职员,兴许是刚唱完卡拉OK后出来炫一顿海底捞再回去继续唱歌吧。

最后吃到2点多,愉快的散伙回家,巴士超级冷清,整辆车就我和我朋友以及一个司机,直到家门口才有一个人上车,有点瘆人😂。

计划

  1. 好好工作攒钱买车
  2. 继续准备毕业设计
  3. 吃好喝好玩好睡好

结尾

新年新气象,深夜12点跟大家吃麻辣火锅,也是新的体验新的开始了。

[好物分享] 米家胶囊咖啡机💊☕️

背景

小时候跟父母去外地游玩,有一次酒店内的mini bar看到了一台奇怪的机器,机器旁边还放着一些杯子状的小药丸。出于对小物件的好奇,我第一次接触到了胶囊咖啡机。当时我的对于咖啡的认知还停留在包装速溶咖啡,通过胶囊做出一杯咖啡的体验是我大受震撼🤯,给我留下了很深的印象,至此之后我就把胶囊咖啡机放进了我的愿望清单里了。不过当时(2012年前后),Nespresso才刚刚进入中国市场,入门款都要上千块钱,对于那时候的我来说实在是承担不起。(虽然现在也是贵的离谱,但好歹现在有了闲鱼可以买二手)因此购入计划就被搁置下来了。

购入咖啡机

某一天晚上刷淘宝的时候,无意间我留意到米家也有自己的胶囊咖啡机了,一番了解后才知道是心想胶囊咖啡机的米家定制版,我还在愁到底要不要试一下呢?后面看大家的测评才知道,原来还兼容Nespresso胶囊系统,着实让我感到惊喜。恰逢今年元旦的时候,小米商城开启了新年的促销活动,原来399元一台的米家胶囊咖啡机,降价到了379元,于是乎果断剁手购入。

开箱试用

咖啡机本体

小米快递很快,下单的第三天我就收到货了。包装内包含了两部分:

  1. 咖啡机本体(上图)
  2. 两盒试用胶囊(心想系统与Nespresso系统)

咖啡机本体是米家祖传的灰白配色,简洁大气,十分百搭,放厨房里一点都不突兀。咖啡机通过220V供电,电源线不可拆卸。第一次使用的时候需要现在机器后部的水箱中加入适量的纯净水,之后连按两次110ml的按钮,对机器水路进行清洁🧹,之后方可使用。日常使用非常简单,仅仅需要将胶囊(下图)放到机器里,点击对应的杯量即可制作。通常做一杯Espresso(意式浓缩咖啡),仅需要10秒左右,Lungo(长杯咖啡/美式咖啡)则需要30秒左右。另外水槽是可以变更高度的,用以适配不同的杯子高度。制作咖啡的噪声不是很大,嗡嗡嗡的类似空调外机启动的声音,由于持续时间很短,因此不用太过担心扰民,隔一堵墙就没事了。

官方的试用胶囊(深烘,很拉垮)

从开机预热(30秒),到开始制作(15-30秒),到洗水槽(60秒),喝上一杯还算不错的咖啡仅需要不过3分钟的时间,实在是很不错了。早上来一杯,特惬意,大幅度提高幸福感。如果看到这里的你,居住在北方城市,空气较干燥的话,甚至不用像我一样,每天倾倒废料盒(把用完的胶囊丢掉);干燥一点的环境,每周洗一次就好了。这样子甚至可以节约60秒,每天60秒,一个月就30分钟了。

咖啡胶囊成本

由于Nespresso咖啡胶囊系统已经存在了非常多年,同时雀巢作为Nespresso的母公司,一直在为其推广。所以官方所能提供的胶囊,相较其他的纯咖啡胶囊系统(DOLCE GUSTO 多趣酷思等咖啡饮料不做讨论,毕竟咖啡饮料有自己的玩法,饮料会侧重于花样,所以会有很多奶茶、热巧克力之类的选择),比如illy、Tassimo、Lavazza等会有更多口味,更不用说Nespresso胶囊专利已经到期,现在大家都能做Nespresso胶囊。副厂胶囊百花齐放,一抓一大把,甚至前面提到的三家拥有自己咖啡胶囊系统的厂家都为Nespresso专门推出了自家的咖啡。因此单杯咖啡的成本并不高,比如官方的普通咖啡系列,3.8-4.2元一颗胶囊,限定款6-15元不等。通常我们选择3.8-4.2元的胶囊作为口粮就足够了。对于我而言,我一天通常要喝两颗,上午一杯Espresso下午一杯美式,一天的开销也就是8-10元不等。相较于瑞幸咖啡、星巴克等咖啡还是会更加省钱的。更不要说副厂的了,可以通过较低的价格喝到更多口味,我甚至有看到SOE(单一产区)的胶囊,准备下次买来试试看。

PS:SOE这种咖啡豆主要是喝的产区味道。平时的咖啡豆是通过不同产区的咖啡豆混杂,获得的一个大众接受度高的味道,优势是苦度和酸度都拿捏的非常好,比较好入口;缺点就是太平淡了,没啥特别的😂。因此选择SOE更多是为了更多的风味,比如花香水果香巧克力焦糖等味道,如果你觉得为啥要在咖啡里找这些味道,喝果汁不好吗?那么你可以简单的理解成,人们是为了偏酸一点或者偏苦一点。而这些芳香物质只是在追求酸度和苦度过程中的副产物而已。通常焦糖和巧克力味会跟苦一点的咖啡相关联;水果香或者花香的话会跟酸一点的咖啡相关联。

我买了什么胶囊?

我买了两个口味的胶囊,都是看网上测评买的:

  1. 灵感之源-佛罗伦萨阿佩奇欧咖啡
  2. 上海大杯咖啡
灵感之源-佛罗伦萨阿佩奇欧咖啡
甚至买了个比赛用的加厚Espresso杯子来喝咖啡,逼格拉满😂

风味主要是:莓果香和可可香,个人喝下来感觉可可香会更重一点,醇厚的味道(简单理解就是苦),已经作为我的早餐Espresso用了。(风味这种东西,因人而异,建议还是直接入手所有口味喝个遍,挑个喜欢且便宜的就好)

上海大杯咖啡

上海大杯咖啡是用来做Lungo的,所以会比较稀,类似美式咖啡,比较好入口,因此现在已经作为我下午的口粮咖啡了。风味是偏酸一点的果香味道,好入口,喝完无负担。

2024/07/29更新:

如果能接受果酸的话,无脑买哥伦比亚和Cosi就好了,这两个不会踩雷,其他的喝起来都一般般。

最后

接下来等把其他胶囊喝完,我就买别的口味的胶囊,挑一个我喜欢的长期喝。如果你也喜欢咖啡,但苦于身边没咖啡店或者咖啡太贵不能天天喝,建议你入手试试看,真的能够省钱提高生活幸福感的。

[SQL] 如何获取昨日每个小时的记录数量?

方法

利用左连接来实现逐小时查询(终于把数据库原理学到的知识用上了😂)

select a.click_date,ifnull(b.total,0) as total from (
SELECT date_format(date_sub(curdate(), interval 1 HOUR),'%Y-%m-%d-%H') as click_date 
union all 
SELECT date_format(date_sub(curdate(), interval 2 HOUR),'%Y-%m-%d-%H') as click_date 
union all 
SELECT date_format(date_sub(curdate(), interval 3 HOUR),'%Y-%m-%d-%H') as click_date 
union all 
SELECT date_format(date_sub(curdate(), interval 4 HOUR),'%Y-%m-%d-%H') as click_date 
union all 
SELECT date_format(date_sub(curdate(), interval 5 HOUR),'%Y-%m-%d-%H') as click_date 
union all 
SELECT date_format(date_sub(curdate(), interval 7 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 8 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 9 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 10 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 11 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 12 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 13 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 14 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 15 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 16 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 17 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 18 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 19 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 20 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 21 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 22 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 23 HOUR),'%Y-%m-%d-%H') as click_date
union all 
SELECT date_format(date_sub(curdate(), interval 24 HOUR),'%Y-%m-%d-%H') as click_date
) a 
left join (
select date_format(createTime,'%Y-%m-%d-%H') as datetime, count(*) as total from `order` where  `status` = 2 group by date_format(createTime,'%Y-%m-%d-%H')
) b 
on a.click_date = b.datetime

infull用于字段的补0,在无数据的时候可以补上0。

dateSub用于减去时间戳的时间

a主要是用来生成逐小时的时间字段

b主要是查询数据

on是用来执行left join的条件