猫咪走开!计算机视觉喷水驱猫装备

[ 复制链接 ]
admin | 2020-2-8 04:51:51 | 显示全部楼层 | 阅读模式 打印 上一主题 下一主题

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x



猫咪走开!计算机视觉喷水驱猫装备

猫咪走开!计算机视觉喷水驱猫装备


MAKER:CatawayCV/译:趣无尽 Cherry(转载请注明出处)
不得不承认,Maker 撩猫那可是一把好手。咱们的撩猫系列教程,前有《用 Arduino DIY 镭射激光逗猫神器》,后有《Petoi Nybble:树莓派猫奴玩家的福音》。
下面要介绍的这个用来为你看家护院,驱赶外来的随地大小便的入侵猫!
虽然本教程没有对计算机视觉的工作原理作特别详细的介绍,但会将项目构建的过程和代码分享给大家。
首先,这个喷水驱猫装备是一个低压的喷头,而且转动的速度比猫的反应要快。但请放心,它不会把猫咪喷成落汤猫,只是产生威慑效果,打消它们在后院大小便的念头。
来看一段简单视频:

                    
               
材料清单

猫咪走开!计算机视觉喷水驱猫装备

猫咪走开!计算机视觉喷水驱猫装备


树莓派 Zero(Raspberry Pi Zero)1
SD卡1
树莓派摄像头1
继电器1
555定时器1(可以用 Arduino 和一个继电器代替)
电磁阀1
喷水头1
电子产品的外壳1
锤子1
低分辨率的摄像头1
系统介绍
1、树莓派摄像头检测到类似一只猫大小的物体的移动了数帧(下一步会说明)。
2、树莓派引爆喷水头。
3、猫落荒而逃。
4、视频自动上传到 Youtube 供大家伙儿围观。
编程

猫咪走开!计算机视觉喷水驱猫装备

猫咪走开!计算机视觉喷水驱猫装备


使用 openCV 的帧减法,你可以找到随时间变化的帧的区域,使用一些实用的函数,确定物体的大小以及其变化,最重要的是确实物体是否是猫。
你也可以自己在网上搜索有关帧减法的详细教程。
代码工作原理
1、摄像头要保持拍摄并将画面进行比较。检测到猫大小的物体将引起注意。
2、猫大小的物体变化持续超过 4 帧,树莓派将用 GPIO 为继电器供电并启动 Arduino。
3、Arduino 发送信号给第二个继电器供电五秒钟并激活电磁阀。电磁阀在通电时启动喷水头。
4、当喷水头启动时,摄像头会停止检测并记录视频。
5、将视频上传到你的 Youtube,同时上传到 Dropbox 进行微调系统。
使用两个继电器和一个 Arduino 来打开电磁阀的原因如下
1、录制视频时树莓派不能开关电磁阀,python 脚本直到视频结束后才能停止。因此当视频还在录制时,需要 Arduino 或555定时器作为独立的脚本来关闭电磁阀。
2、第一个继电器和 Arduino 可以用 555 定时器替换,它可以节省大量的时间和金钱。
3、树莓派不能直接触发电磁阀,因为树莓派的 GPIO 工作在 3.3v 和 51mA (最大值)上,而电磁阀需要 5V 并且大于 51mA 才触发。
4、可以裁剪每个画面的大小,除去不需要检测的区域,例如隔壁家的花园。
5、可能会错过一些画面,浪费时间来设置它。
代码如下
import cv2
import numpy as np
import argparse #cat
import time
import RPi.GPIO as GPIO
import os
import dropbox
from picamera.array import PiRGBArray
from picamera import PiCamera

#------------------------------------------------Upload to youtube---------------------------------------
def HDtoYoutube():
    ctime = time.strftime("_%H-%M-%S")
    cdate = time.strftime("_%d-%m-%Y")
    vidname = ctime + cdate
    #Trigger relay
    GPIO.output(11,True)
    time.sleep(.5)
    GPIO.output(11,False)
    print("Taking Video")
    try:

        #Take Video
        os.system('raspivid -w 1640 -h 922 -o vid{0}.h264 -t 15000'.format(vidname))
        #Upload to youtube
        print("Uploading to YouTube")
        os.system('sudo youtube-upload --title="Cat Got Wet {0}" --client-secrets=client_secret.json vid{0}.h264'.format(vidname))
        #Remove video file when done
        os.remove('vid{0}.h264'.format(vidname))
        print("Video uploaded and removed from Pi")

    except:
        pass

#------------------------------------------------Stills to dropbox---------------------------------------
def StillsToDropbox():
    print("Uploading Still To Dropbox Function")
    access_token = 'Ah ah ah, you didn't say the magic word...Ah ah ah, you didn't say the magic word'
    ctime = time.strftime("%H:%M:%S")
    cdate = time.strftime("%d-%m-%Y")
    try:
        filename = "/Motion/{0}/DetectedAt_{1}.jpg".format(cdate, ctime)
        print(filename)
        client = dropbox.client.DropboxClient(access_token)
        image = open("ToDropbox.jpg", 'rb')
        client.put_file(filename, image)
        image.close()
        os.remove("ToDropbox.jpg")
    except:
        pass

#------------------------------------------------Detect motion-----------------------------------------
def DetectMotion():
    #Define vars
    min_area = 400
    tolarance = 25 #change in pixel
    bluramount = 21
    timetoforget = 0.5
    kernel = np.ones((5,5),np.uint8) #used for dialate
    MotionCounter = 0
    MinTargetArea = 600 #smallest size to detect
    MaxTargetArea = 5000 #Largest size to detect
    now = time.time()
    then = time.time()

    #initialise camera
    camera = PiCamera()
    camera.resolution = (640,480)
    camera.framerate = 10
    rawCapture = PiRGBArray(camera, size=(640,480))

   #warmup camera
    time.sleep(1)

   #Grab first frame & prep it to go into cv2.acumulate weight
    camera.capture(rawCapture, format="bgr")
    avg = rawCapture.array

   #Crop out unwanted region
    PolyCrop = np.array( [[[362,480],[613,365],[628,161],[498,0],[640,0],[640,480]]], dtype=np.int32 )
    cv2.fillPoly(avg, PolyCrop, 0,0,0)
    #Process image
    avg = cv2.cvtColor(avg, cv2.COLOR_BGR2GRAY)
    avg = cv2.GaussianBlur(avg, (bluramount, bluramount), 0)
    avg = avg.copy().astype("float")
    rawCapture.truncate(0)
    print("Ready to detect")

    #capture frames
    for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
        #Pause Switch
        loopgo = GPIO.input(PauseNow)
        #print(loopgo)
        while loopgo == 0:
            #print(loopgo)
            loopgo = GPIO.input(PauseNow)
            time.sleep(1)

       #grabs raw numpy array
        currentframe = frame.array
        key = cv2.waitKey(1) & 0xFF
        #Crop out unwanted region
        cv2.fillPoly(currentframe, PolyCrop, 0,0,0)
        rawCapture.truncate(0) #Clear frame buffer for next loop
        currentgray = cv2.cvtColor(currentframe, cv2.COLOR_BGR2GRAY)
        currentgray = cv2.GaussianBlur(currentgray, (bluramount, bluramount), 0)
        #make time average frame
        cv2.accumulateWeighted(currentgray, avg, timetoforget)
        #get difference in frame
        frameDelta = cv2.absdiff(currentgray, cv2.convertScaleAbs(avg))
        thresh = cv2.threshold(frameDelta, tolarance, 255, cv2.THRESH_BINARY)[1]
        #Turn to blob
        thresh = cv2.dilate(thresh, kernel, iterations = 10) #dilate
        thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) #close holes
        thresh = cv2.erode(thresh, kernel, iterations = 5) #erode
  
      #contours
        _, cnts, _= cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # loop over the contours
        for c in cnts:
            # if the contour is too small, ignore it
            if cv2.contourArea(c) = MinTargetArea and cv2.contourArea(c)  MaxTargetArea:
                cv2.rectangle(currentframe, (x, y), (x + w, y + h), (255, 0, 0), 2)
                #MotionCounter = MotionCounter + 1 #Debug take all the pictures
                print("MotionDetected")

       #Keep now up to date
        now = time.time()
        #MotionCounterTimer
        if (MotionCounter > 0):
            if (now - then > 10):
                MotionCounter (www.yun-ling.cn)= 0
                then = time.time()
        #Break loop on pressing Q
        if key == ord("q"):
            break

        #If motion persists save current frame and activate countermeasures
        if MotionCounter >= 4:
            MotionCounter = 0
            cv2.imwrite('ToDropbox.jpg', currentframe)
            camera.close()
            return True

#------------------------------------------------Main---------------------------------------
try:
    #Set Pins
    GPIO.setmode(GPIO.BOARD)
    PauseNow=12
    GPIO.setup(11,GPIO.OUT)
    GPIO.setup(PauseNow,GPIO.IN,pull_up_down=GPIO.PUD_UP)

    while True:
        MotionDetected = False
        MotionDetected = DetectMotion()
        if MotionDetected == True:
            HDtoYoutube()
            StillsToDropbox()

except KeyboardInterrupt:
    print("Keyboard Interupt")   
except:
    print("Other Error")   
finally:
    GPIO.cleanup()
组装

猫咪走开!计算机视觉喷水驱猫装备

猫咪走开!计算机视觉喷水驱猫装备


猫咪走开!计算机视觉喷水驱猫装备

猫咪走开!计算机视觉喷水驱猫装备


猫咪走开!计算机视觉喷水驱猫装备

猫咪走开!计算机视觉喷水驱猫装备


猫咪走开!计算机视觉喷水驱猫装备

猫咪走开!计算机视觉喷水驱猫装备


1、将所有电器安装防水外壳,并使用胶带和热熔胶固定到位。

猫咪走开!计算机视觉喷水驱猫装备

猫咪走开!计算机视觉喷水驱猫装备


猫咪走开!计算机视觉喷水驱猫装备

猫咪走开!计算机视觉喷水驱猫装备


2、开始投入运转。
误报的情况

猫咪走开!计算机视觉喷水驱猫装备

猫咪走开!计算机视觉喷水驱猫装备


设备也会存在误报的情况,也许它也会喷到你的家人或朋友。因此提供一个专业的意见——在门上安装一个关闭设备的开关。
教程中如有误的地方请多多包涵与指教。希望你喜欢这个项目。
https://make.quwj.com/project/124
via

       
温馨提示:
1、在论坛里发表的文章仅代表作者本人的观点,与本网站立场无关。
2、论坛的所有内容都不保证其准确性,有效性,时间性。阅读本站内容因误导等因素而造成的损失本站不承担连带责任。
3、当政府机关依照法定程序要求披露信息时,论坛均得免责。
4、若因线路及非本站所能控制范围的故障导致暂停服务期间造成的一切不便与损失,论坛不负任何责任。
5、注册会员通过任何手段和方法针对论坛进行破坏,我们有权对其行为作出处理。并保留进一步追究其责任的权利。
回复 推荐到N格

使用道具 举报

大神点评(1)

您需要登录后才可以回帖 登录 | 立即注册
    云凌阁
    奇怪的酸 | 2020-5-22 15:33:57 | 显示全部楼层
    额,虽然看不懂在说神马,不过还是支持云凌阁~@_@
    回复 支持 反对

    使用道具 举报

    相关推荐
    云凌阁

    关注1

    粉丝0

    帖子94526

    发布主题