家里的树莓派闲置一段时间了,一直不知道做什么。最近春天到了,看着小树苗慢慢长大的样子,真的很想记录下来,所以就动手啦!
准备工作首先请出主角: 一个闲置的树莓派、摄像头,当然还有花种、花盆。
考虑到树莓派需要长期开机,最好有一个散热风扇,某宝有很多这样的:
摄像头我就用了非常普通的pi camera V2.1,几十块钱就可以买到:(图片来自网络)
搭一个支架,调整焦距之后需要想办法把摄像头固定在一个合适的位置。pi Camera 周围有固定用的小圆孔,加上一个手机支架基本可以固定起来。淘宝上也有卖的,但是不建议买(因为真的没啥用)。保证摄像角度清楚、稳定是最重要的。我的长这样:
之后需要调整相机的焦距。Pi camera 是定焦摄像头,理论上来讲是不能调焦的,好在这个镜头在制作的时候是螺旋拧上去的,这就给了我们操作的空间。
拿一个镊子对镜头上的十字部分旋转。向右旋转焦距变小,旋转半圈基本就差不多了。各位根据自己的距离可以多尝试
旋转前vs旋转后的清晰度变化
这些都做完之后,可以把树莓派摆好了。选择位置的时候需要考虑以下几个问题:
- 电源:注意树莓派是没有电池的,因此需要一个稳压电源来供电。如果盆栽选在了没有电源的位置,只能考虑多个充电宝轮流接力,比较麻烦。而且充电宝的电压一般比额定的2.5A要低一些,可能会出现意外的情况。
- 散热。如前面所说的最好整一个风扇。如果温度过高的话可能拍照会失败。(使用
cat /sys/class/thermal/thermal_zone0/temp
查看温度) - 防水。这个就不多说了,罩一个塑料布即可。
- 除此之外最好放在一个有无线网络链接的地方,否则每次配置都要连网线,可能会不小心把相机碰歪。
下一步开始进入正题。延迟摄影其实就是拍摄一些比较低帧率的视频。我们可以直接拍很多照片,然后手动拼接起来:
首先,拍照片的任务使用一行raspistill
命令即可实现,而定时任务的部分可以用crontab来做。拿到照片后,再用opencv或者直接使用ffmpeg把图片拼起来。思路比较简单,我们就从最基础的部分开始:
- 1 首先需要保证树莓派的摄像头可以正常工作:
把Pi camera 的排线插进树莓派的卡槽里面,然后把卡扣压紧。(注意这一步最好在关机状态下做好,否则可能无法识别到摄像头)
然后远程连接到树莓派,输入sudo raspi-config
,进入设置,找到interface options
然后enable camera。
做完这一串之后,使用指令raspistill -v -o test.jpg -ex auto
可以测试自己的摄像头是否完全就绪了。如果正常的话,在用户空间下应该可以找到一个test.jpg文件。
- 2 写一个拍摄脚本。
其实理论上来讲根本不用写脚本,直接用raspistill命令就可以实现了。用脚本实现的好处是可以比较轻松的控制拍摄时间和文件名。一般延时摄影的图片格式考虑使用jpg格式就够了,否则合成视频的时候压力会比较大。
#!/bin/bash
DATE=$(date +"%m-%d_%H%M")
raspistill -o /home/pi/flower_pics/$DATE.jpg
把脚本保存之后记得新建对应存放照片的路径:mkdir /home/pi/flower_pics
- 3 修改权限
注意修改脚本的权限,否则crontab没办法自动化执行:chmod +x take_photo.sh
- 4 配置crontab。
这一步比较重要,拍照的间隔需要提前考虑好,因为涉及到最后合成视频的质量。
如果拍摄开花的视频,一般间隔可以选择20s-60s,拍摄2-3个小时;如果只是记录植物生长则可以间隔更长一点。我的视频大概拍了三周时间,每20分钟拍一次,最后视频约25s(考虑到我删去了夜间的照片,和偶尔一些采光不好的残次图)。如果时间比较刁钻,比如必须是每隔40、50分钟,这种情况可以在脚本里面用if条件语句另行做判断。
输入crontab -e
,在对应的文件内输入自己执行的时间,和脚本文件的位置:0,20,40 * * * * sh /home/pi/scripts/take_photo.sh 2>&1
都调整完之后,就可以躺平等着香菜慢慢长大了~
照片的调整&合成单纯的图片拼接是比较简单的。使用ffmpeg或者直接上pr都可以实现。但是为了考虑视频的质量,在合成视频前需要做一下简单的处理。
上面是我出的图。虽然清晰度还可以,但是很大的一个问题是画面的曝光程度差别太大了。学校sb宿舍只有早上有阳光直射,导致下午和晚上的香菜都有些不同程度的欠曝,几张图片直接拼接到一起会不太舒服,所以需要靠后期,给下午和晚上的照片补光。
考虑到需要对特定时间的图片批量处理,还是用opencv一条龙操作下来比较方便。
提升亮度方面,一方面增强的是对比度,另一方面考虑画面的整体亮度,所以主要考虑gamma变化和归一化处理。各位可以看一下效果自行决定。
- gamma变换
gamma变换是一个比较好的选择。对输入图像的亮度做一个非线性的变换,主要提升暗部的细节,这样变换得到的结果相比直接增加亮度更自然一些。
\[s = cr^\gamma,{ }r\in[0,1] \] gamma = 0.65
gamma_table=[np.power(x/255.0,gamma)*255.0 for x in range(256)]
gamma_table=np.round(np.array(gamma_table)).astype(np.uint8)
img = cv2.LUT(img,gamma_table)
看下效果:gamma = 0.65
- 归一化
实现只需要一行代码就够了:
img = cv2.normalize(img,dst=None,alpha=255,beta=30,norm_type=cv2.NORM_MINMAX)
其中,NORM_MINMAX表示使用归一化的类型,alpha和beta分别为归一化后的最大值最小值,也就是max',min'。
\[x' = \frac{x-min}{max-min} * (max' - min') + min' \]除了NORM_MINMAX之外,也可以选择切比雪夫距离(cv2.NORM_INF)/欧式距离(cv2.NORM_L2)/曼哈顿距离(cv2.NORM_L1)作为归一化的距离计算方式。
归一化调整出的结果更加自然,但是缺点也很明显:没有办法彻底改变图片的曝光问题。
min_max归一化:max = 250,min = 20
完整代码在这里
拿到视频之后就很简单了。打开pr配一段音乐,就完成啦!
结果