Skip to content

hardware

基于树莓派打造你的个人感知终端

cover_image

基于树莓派打造你的个人感知终端

原创 喵喵张 城市感知计算

城市感知计算

微信号 sensingcity

功能介绍 认识世界和改造世界,分享地理信息系统科普知识与学术研究,欢迎加好友学术交流。



哈喽大家好,好久没有给大家带来好玩的东西了。这次给大家介绍下开发的小玩意,让大家联动手机与树莓派,来进行实时的监控。

首先我们用的是一台树莓派4B,加装了一个摄像头,并安装了Raspber ry Pi OS系统。 这个系统大家一般购买的时候店家会发给你,自己按照教程烧录就好啦。

(购买的树莓派)

(进入到系统界面)

然后最关键的是我们要安装Linux版本的opencv,这个步骤相对较难,我直接找了别人装好的镜像,安装到了树莓派里,其他的诸如miniconda等大家自行安装。然后进行以下测试,如果桌面正常采集出 example1.png 那么我们基本上可以完成剩下的步骤!

    import cv2import numpy as npcap = cv2.VideoCapture(0) # 注意:这个地方本文的图片里没有参数0,但是应该传入0f, frame = cap.read() # 此刻拍照cv2.imwrite("example1.png", frame) # 将拍摄内容保存为png图片cap.release() # 关闭调用的摄像头print('采集完成')

如果我们想对摄像头采集的内容进行感知,来判断是否存在场景变化(例如实现有行人经过进行抓拍),那么最简单的思路是,间隔一秒钟进行拍照,然后对比一秒钟前后的图像变化,计算哈希相似度,如果相似度低于0.8那么我们判断有人经过或者场景发生了改变~

    def compare_image(self, file_image1, file_image2, size=(256, 256), part_size=(64, 64)): ''' 'file_image1'和'file_image2'是传入的文件路径 可以通过'Image.open(path)'创建'image1' 和 'image2' Image 对象. 'size' 重新将 image 对象的尺寸进行重置,默认大小为256 * 256 . 'part_size' 定义了分割图片的大小.默认大小为64*64 . 返回值是 'image1' 和 'image2'对比后的相似度,相似度越高,图片越接近,达到1.0说明图片完全相同。 '''
    image1 = Image.open(file_image1) image2 = Image.open(file_image2)
    img1 = image1.resize(size).convert("RGB") sub_image1 = self.split_image(img1, part_size)
    img2 = image2.resize(size).convert("RGB") sub_image2 = self.split_image(img2, part_size)
    sub_data = 0 for im1, im2 in zip(sub_image1, sub_image2): sub_data += self.calculate(im1, im2)
    x = size[0] / part_size[0] y = size[1] / part_size[1]
    pre = round((sub_data / (x * y)), 6) # print(str(pre * 100) + '%') print('Compare the image result is: ' + str(pre)) return pre

(写一下对比的代码)

同时我们设置While循环,这个系统就可以一直运行啦。但是仅仅计算出来,没办法传送到移动设备,感觉这还是不够智能。我们就引入邮件的SMTP服务,让他自动进行戒备。我们这里使用的是网易163邮箱,相关授权请自行百度。

构造一个发邮箱请求:

    def sendEmail(content,title): sender = 'XXX@163.com'# 我用的163邮箱 receivers = ['XXXX'] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
    message_content = MIMEText(content, 'plain', 'utf-8')# 内容, 格式, 编码 message = MIMEMultipart('related') message['Subject'] = '摄像头识别检测' message['From'] = "{}".format(sender) message['To'] = ",".join(receivers) # message['Subject'] = title
    # 第三方 SMTP 服务 mail_host = "smtp.163.com" # SMTP服务器 mail_user = "" # 用户名 mail_pass = "" #你的smtp密钥
    img = MIMEImage(open('example1.png', 'rb').read(), _subtype='octet-stream') img.add_header('Content-Disposition', 'attachment', filename='example1.png') message.attach(img) message.attach(message_content) try: smtpObj = smtplib.SMTP_SSL(mail_host, 465) # 启用SSL发信, 端口一般是465 smtpObj.login(mail_user, mail_pass)# 登录验证 smtpObj.sendmail(sender, receivers, message.as_string())# 发送 print("mail has been send successfully.") except smtplib.SMTPException as e: print(e)

测试效果:

(手机收到邮件)

其他的 一些好玩的,例如在树莓派上进行图像的边缘检测:

    import cv2import numpy as npimg1=cv2.imread('/home/pi/Desktop/example1.png')img2=cv2.imread('/home/pi/Desktop/example2.png')# 从文件中读取图像image = cv2.imread('/home/pi/Desktop/example2.png', cv2.IMREAD_COLOR)# 将图像转换为灰度图gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 使用Canny算法进行边缘检测edges = cv2.Canny(gray, threshold1=30, threshold2=100)# 保存边缘检测结果的图像cv2.imwrite('edges_image.jpg', edges)# 显示原始图像和边缘检测结果cv2.imshow('Original', image)cv2.imshow('Edges', edges)# 等待用户按下任意键,然后关闭窗口cv2.waitKey(0)cv2.destroyAllWindows()

还可以 部署 yolos-tiny 来进行目标检测与识别~返回手机的信息可以更多,甚至可以接入大模型接口来进行场景描述(参见: 城市字幕,教你如何利用图像跨模态推理空间知识 )。后期我们还集成了人脸的年龄、情绪、族裔以及性别检测算法,也会将在接下来的教程中公开。

做科学实验,数据的获取是非常关键的步骤,计划未来开发城市感知微型基站,集成更加多源的传感器,获取声热音光等多源信息,部署在车辆上,采集 一手的 城市数据,欢迎大家继续关注。

(采购了一些小的传感器)

下一期继续给大家推送微博数据相关的技术与方法,教大家如何构建自己的公共事件社交媒体数据集,以下是一些前期文档:

微博签到数据的获取思路与实战

城市微博签到数据分享&地址解码与纠偏教程

北京市含地理坐标的微博数据分享&数据获取方法与科学研究问题

超越微博,小红书数据采集数据、代码和思路

最后是本文分享的全部代码:

    -- coding: UTF-8 --author = 'zy'time = '2020/5/24 20:21'#coding:utf8import osfrom PIL import Image,ImageDraw,ImageFileimport numpyimport pytesseract#import cv2#import imagehashimport collectionsimport cv2,time

    def compare_image_with_hash(image_file1,image_file2, max_dif=0): """ max_dif: 允许最大hash差值, 越小越精确,最小为0 推荐使用 cv2.img_hash.averageHash """ ImageFile.LOAD_TRUNCATED_IMAGES = True hash_1 = None hash_2 = None with open(image_file1, 'rb') as fp: hash_1 = cv2.img_hash.averageHash(Image.open(fp)) print(hash_1) with open(image_file2, 'rb') as fp: hash_2 = cv2.img_hash.averageHash(Image.open(fp)) print(hash_2) dif = hash_1 - hash_2 print(dif) if dif < 0: dif = -dif if dif <= max_dif: return True else: return False
    class CompareImage(): def calculate(self, image1, image2): g = image1.histogram() s = image2.histogram() assert len(g) == len(s), "error" data = [] for index in range(0, len(g)): if g[index] != s[index]: data.append(1 - abs(g[index] - s[index]) / max(g[index], s[index])) else: data.append(1) return sum(data) / len(g)

    def split_image(self, image, part_size):        pw, ph = part_size        w, h = image.size        sub_image_list = []        assert w % pw == h % ph == 0, "error"        for i in range(0, w, pw):            for j in range(0, h, ph):                sub_image = image.crop((i, j, i + pw, j + ph)).copy()                sub_image_list.append(sub_image)  
        return sub_image_list
    
    def compare_image(self, file_image1, file_image2, size=(256, 256), part_size=(64, 64)):        '''        'file_image1'和'file_image2'是传入的文件路径         可以通过'Image.open(path)'创建'image1' 和 'image2' Image 对象.         'size' 重新将 image 对象的尺寸进行重置,默认大小为256 * 256 .         'part_size' 定义了分割图片的大小.默认大小为64*64 .         返回值是 'image1' 和 'image2'对比后的相似度,相似度越高,图片越接近,达到1.0说明图片完全相同。        '''  
        image1 = Image.open(file_image1)        image2 = Image.open(file_image2)  
        img1 = image1.resize(size).convert("RGB")        sub_image1 = self.split_image(img1, part_size)  
        img2 = image2.resize(size).convert("RGB")        sub_image2 = self.split_image(img2, part_size)  
        sub_data = 0        for im1, im2 in zip(sub_image1, sub_image2):            sub_data += self.calculate(im1, im2)  
        x = size[0] / part_size[0]        y = size[1] / part_size[1]  
        pre = round((sub_data / (x * y)), 6)        # print(str(pre * 100) + '%')        print('Compare the image result is: ' + str(pre))        return pre
    

    import smtplib,timefrom email.mime.text import MIMETextfrom email.mime.image import MIMEImagefrom email.mime.multipart import MIMEMultipart
    def sendEmail(content,title): sender = 'XXX@163.com'# 我用的163邮箱 receivers = ['XXXX'] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
    message_content = MIMEText(content, 'plain', 'utf-8')# 内容, 格式, 编码 message = MIMEMultipart('related') message['Subject'] = '摄像头识别检测' message['From'] = "{}".format(sender) message['To'] = ",".join(receivers) # message['Subject'] = title
    # 第三方 SMTP 服务 mail_host = "smtp.163.com" # SMTP服务器 mail_user = "" # 用户名 mail_pass = "" #你的smtp密钥
    img = MIMEImage(open('example1.png', 'rb').read(), subtype='octet-stream') img.add_header('Content-Disposition', 'attachment', filename='example1.png') message.attach(img) message.attach(message_content) try: smtpObj = smtplib.SMTP_SSL(mail_host, 465) # 启用SSL发信, 端口一般是465 smtpObj.login(mail_user, mail_pass)# 登录验证 smtpObj.sendmail(sender, receivers, message.as_string())# 发送 print("mail has been send successfully.") except smtplib.SMTPException as e: print(e)
    if __name_
    =='main':
    while True: cap = cv2.VideoCapture(0) # 注意:这个地方本文的图片里没有参数0,但是应该传入0 f, frame = cap.read() # 此刻拍照 cv2.imwrite("example1.png", frame) # 将拍摄内容保存为png图片 cap.release() # 关闭调用的摄像头 print('采集完成') time.sleep(1)
    cap = cv2.VideoCapture(0) # 注意:这个地方本文的图片里没有参数0,但是应该传入0 f, frame = cap.read() # 此刻拍照 cv2.imwrite("example2.png", frame) # 将拍摄内容保存为png图片 cap.release() # 关闭调用的摄像头
    compare_image = CompareImage() result=compare_image.compare_image("example1.png","example2.png") print(result) if result<0.8: sendEmail(str(result), '温度测试反馈结果')

预览时标签不可点

微信扫一扫
关注该公众号



收藏

精选留言

Accio来自上海

太牛啦!准备入手树莓派当新玩具了哈哈哈

未命名用户来自上海

我也想玩儿,哈哈哈,准备弄个二手的试试

未命名用户来自上海

玩!大胆玩![耶]

未命名用户来自北京

嘿嘿 好滴[好的]

我直接阿炎来自河北

看完直接激发兴趣,研究一下[嘿哈]

wy来自中国香港

太有意思了!我说你桌子上放的是什么呢[哇]

城市感知计算来自

哈哈哈

老张来自河南

我也想买几个玩玩,觉得挺有意思里。可以锻炼自己动手的能力

兰spring来自河南

有意思