0%

树莓派控制手机自动拍照

树莓派使用 Python 控制手机上的 DroidCam 自动拍照

需求

新买了个盆栽,想要关注盆栽的生长情况。如果是摄像,“代价”又有点大。想到了 DroidCam 这个软件,能够让手机变成监控摄像头。于是,可以利用它做一个自动拍照的延时摄影。

前期准备

  • 手机(IOS、Android 均可) + DroidCam 软件
  • 树莓派(常年开机的小主机,能用 Python就行)
  • 其他重要的内容:
    • 手机支架
    • 手机充电的电源

大致效果如图

v1.0

在搭建完基本的设施之后,首先测试拍照功能,命令如下所示,将 $IP_ADDR 换成手机 IP 地址即可,DroidCam 主界面也会显示。默认端口是 4747

1
wget "http://$IP_ADDR:4747/cam/1/frame.jpg" -O $(date +"%s").jpg

然而,在把这行命令放到树莓派上的定时任务中时,遇到了几个问题

晚上光线暗

打开手机摄像头的闪光灯,命令如下所示

1
2
3
curl "http://$IP_ADDR:4747/cam/1/led_toggle" \
--compressed \
--insecure

没有对焦

自动对焦命令如下所示

1
2
3
af_cmd = f"""curl "http://$IP_ADDR:4747/cam/1/af" \
--compressed \
--insecure

这两个问题算是可以通过软件本身进行解决。但引发了一个新问题就是,不能知道手机是否已经开启闪光灯、是否已经对焦。前者可以通过时间判断,如果是白天则不开,但后者没办法控制。DroidCam 的逻辑是,每次只能有一个客户端打开网址,如果有多个客户端打开,后者会把前者踢下线,且状态为止。因此,最后决定每次拍两张照片,用照片大小来判断图片质量。

DroidCam 要求启动摄像头后,才能拍照

一个比较大的问题是,DroidCam 要求启动摄像头后,才能拍照。而如果没有客户端打开网址,则摄像头不会启动。因此,需要在请求前,去开启网址。

1
2
3
4
def start_func():
video_url = "http://{}/video?640x480".format(ip_addr)
response = requests.get(video_url, stream=True)
print("start_func")

如果长时间没有启动 DroidCam,手机则会自动息屏,导致之后的拍照全部失败。

实现

见下面代码的 take_picture.py 部分,只需将其设置为定时任务即可 */10 * * * * cd /root/pics && /usr/bin/python3 take_picture.py。每 10 分钟会去拍一次照,且会拍两张,以时间戳保存在 /root/pics 目录下。

v2.0

照片数据问题解决了,接下来就要处理照片的删除、处理、合成逻辑了。

见上面代码的 process.py 部分

简单来说分为三个部分:

  1. 获取当前文件夹下所有的图片,以时间戳进行排序,时间戳间隔小于 60 秒的照片,只保留一张(以图片大小定)。
  2. 按照日期进行移动,并打包成 zip 文件。
  3. 在 PC 端运行 python3 process.py --convert,会拉取树莓派的压缩包,并解压 zip 文件,最后合成视频。(为什么不在树莓派上,性能太弱,很慢)

ffmpeg 合并命令如下所示,会预先按照时间戳排序,写入到 input.txt 文件中,然后合并成视频。

1
ffmpeg -f concat -i input.txt -vf "fps=25" $OUTPUT

成品