我编写了一个当我在电脑前难过时自动向我的手机发送猫猫图的程序。我的灵感来自于上周看到的一条推特,我弄丢了那条推特的链接,但他的大意是这样的:
如果这个算法能识别出我难过的表情,然后给我发猫猫图的话,我愿意上传我自己的照片。
我认为你可以通过在本地计算的方式来避免个人数据的泄露。
我们的电脑配置足够支持在我们在后台的浏览器上运行一个机器学习模型,这对我们电脑的影响甚至难以察觉。于是我尝试了几种预装了训练模型的JavaScript面部识别库,并按以下指标进行了测评:
该库的示例代码是否简单易上手
它是否能够准确识别我皱眉、噘嘴、生气的表情
我选择了 vladmandic/human — 和它的有力竞争对手 justadudewhohacks/face-api.js. 这些库都提供了API来识别常见表情并给出相应的分数。
['sad', 'angry', 'disgust', 'fear', 'neutral', 'happy', 'surprise']
为了更清晰的分辨我的情绪,我将这些表情分成了"好表情"与“坏表情”,并给其设定情绪评分在-1(非常生气)到1(非常高兴)。由于我不想让我每次鼻子痒的表情都被识别成我不高兴,然后导致我的邮件总是被猫猫图塞满的情况发生,我将识别系统设置成了取三秒内平均得分触发,以此来识别长时间的“坏表情”。于此同时,每次猫咪图的发送还有五分钟的间隔,在一次触发后,五分钟内都不会再次触发。
下图中可以看到我DEBUG控制台中输出的情绪评分。
我把全部的前端代码都写在项目原型的index.html
文件中了。主程序在一台十年前的台式机上每秒循环30-40次(而读取表情的速度更是远低于这个频率,并且我认为应该限制它的频率来节省一些资源)。
function main() { const config = { backend: 'webgl' } const human = new Human.Human(config) async function detectVideo() { // `inputVideo` is a video of a webcam stream const result = await human.detect(inputVideo) // `result` contains an array of faces along with emotion weights handleResult(result) requestAnimationFrame(detectVideo) } detectVideo()}
这个web服务同时在本地部署该文件和数据模型。你可以点击这个链接查看完整代码healeycodes/if-sad-send-cat
通知功能
我选用 Pushover 来给我的ipone手机发送通知. 它的文档 API和代码示例 community libraries 都是非常棒的,同时还提供了一个月的免费试用 (无需绑定信用卡那种)。我早就听说有程序员在家庭自动化项目上采用了 Pushover,我也一直想试着用一下。
这是我发送短信和猫图的代码 server.py
:
r = requests.post( "https://api.pushover.net/1/messages.json", data={ "token": token, "user": user, "message": f"{cat_name} needs your attention.", }, files={"attachment": (f"{cat_name}", open(cat_picture, "rb"), "image/jpeg")},)
你会认为我这个项目里给你印象最深的是面部识别技术,但是我认为使用Pushover才是整个项目最帅的部分。人人都会说“能用就行”,可是我发现Pushover它实在是太好用了,我以后会用它来代替我项目中的邮件或文本提醒。
发猫图
我通过两个API来组成信息的内容,一个随机生成的姓名 https://randomuser.me/api/ 和下载一个随机的猫猫图 https://api.thecatapi.com/v1/images/search. 实际上我必须把猫猫图下载到本地并进行压缩,因为这个猫猫API(thecatapi),似乎执着于上传超清晰的猫科动物图片(甚至超过5MB),这也是为什么我写了下面这个可爱的函数名。
def shrink_cat(path): image = Image.open(path) image.thumbnail((400, 400)) image.save(path)
我使用了python的SimpleHTTPRequestHandler
来部署我的静态文件。这和你使用著名的单行命令python -m http.server
使用的服务器是一样的。
我计划不为它单独运行服务后台,虽然运行后台是可行的,但是我发现在python里编写组合这些API的代码要更快。随后我意识到我需要一个API来对“发猫片”事件进行路由,当时我准备安装一个Flask解决,但是随后..我想我可以只是继续修改我这个简单的服务。
class HttpRequestHandler(http.server.SimpleHTTPRequestHandler): # future employers, please look away # while I override this function def translate_path(self, path): if path == "/web/cat.json": send_cat() return super().translate_path(path)
后续计划
我最初的想法是跟踪我的表情和我当前在用的编程语言的关系,所以我接下来也会致力于这两个方面。
未来可能会在以下的这些标题之一进行创作。
当我用 JavaScript 代替 TypeScript 时我表现的有多吃惊
Python使我快乐
YAML 让我害怕