elonmuskistheman
Posts: 7
Joined: Mon Nov 24, 2014 3:52 pm

Motion Detection

Wed Dec 17, 2014 3:00 pm

Hi, new programmer here attempting to find out how to use motion detection for determining when a flame is extinguished. I guess there would be multiple ways to do this, but I have tried a few prewritten codes and so far none seem to work for me.

1) Lighweight motion detection - Camera launches, but doesn't seem to be taking pictures when I wave my hand across the camera and the preview becomes locked on the screen and is hard to close. After closing can't find pictures anywhere.
http://www.raspberrypi.org/forums/viewtopic.php?t=45235

2) PiCamera Raw Image Capture (RGB) - First got a TypeError: astype() takes no keyword arguments, deleted the dtype reference and then got a ValueError: total size of new array must be unchanged. Tried to change the height and width variable to match the fheight and fwidth, but that didn't work...
http://picamera.readthedocs.org/en/rele ... ipes2.html

3) Linux User Motion detection - SyntaxError: invalid syntax
File "MotionUTF8.txt", line 19
camera.capture(stream, format="bmp') stream.seek(0)
^
http://www.linuxuser.co.uk/tutorials/ra ... -detection

Are there any programs out there that you would recommend as being simple to run for a noob. I've tried over 5 codes so far (forgotten some of the other links), but so far no luck.

Thanks,

elonmuskistheman

elonmuskistheman
Posts: 7
Joined: Mon Nov 24, 2014 3:52 pm

Re: Motion Detection

Tue Apr 21, 2015 2:32 pm

Well, finally found one that worked from Linux User posted below (Not sure why I couldn't get the others to work.) For this one, it works for physical motion like a wave of the hand, but can't get it to detect the motion of a flame. So far, I tried to edit difference and pixels, but still didn't pick it up. Can I modify this one, or would I need to go another route?

Thanks,

elonmuskistheman

import io
import os
import picamera
import time
from datetime import datetime
from PIL import Image

camera = picamera.PiCamera()

difference = 10
pixels = 25

width = 1280
height = 960

def compare():
camera.resolution = (100, 75)
stream = io.BytesIO()
camera.capture(stream, format = "bmp")
stream.seek(0)
im = Image.open(stream)
buffer = im.load()
stream.close()
return im, buffer

def newimage(width, height):
time = datetime.now()
filename = "motion-%04d%02d%02d-%02d%02d%02d.jpg" % (time.year, time.month, time.day, time.hour, time.minute, time.second)
camera.resolution = (width, height)
camera.capture(filename)
print "Captured %s" % filename

image1, buffer1 = compare()

timestamp = time.time()

while (True):

image2, buffer2 = compare()

changedpixels = 0
for x in xrange(0, 100):
for y in xrange(0, 75):
pixdiff = abs(buffer1[x,y][1] - buffer2[x,y][1])
if pixdiff > difference:
changedpixels += 1

if changedpixels > pixels:
timestamp = time.time()
newimage(width, height)

image1 = image2
buffer1 = buffer2

gordon77
Posts: 5075
Joined: Sun Aug 05, 2012 3:12 pm

Re: Motion Detection

Tue Apr 21, 2015 2:34 pm

Could you just look at the brightness of the flame ?

Gordon

User avatar
dickon
Posts: 1587
Joined: Sun Dec 09, 2012 3:54 pm
Location: Home, just outside Reading

Re: Motion Detection

Wed Apr 22, 2015 6:38 am

Or do it the other way in hardware: flames, being plasma, conduct electricity, so in theory at least it can function as a switch on a GPIO pin.

elonmuskistheman
Posts: 7
Joined: Mon Nov 24, 2014 3:52 pm

Re: Motion Detection

Mon May 18, 2015 8:49 pm

Could you just look at the brightness of the flame ?

Gordon

That sounds like a great idea. Was able to find some sample code on the picamera site that moves the rgb values into a numpy array. When I try to print those values, though, it shows up as a truncated list with only 36 items in the array. If I change the default to:

for i in stream.array
print i

it then prints 100 items, but does so 10 times. Will keep at it, but unsure what it's doing at this point...

import time
import picamera
import picamera.array

with picamera.PiCamera() as camera:
with picamera.array.PiRGBArray(camera) as stream:
camera.resolution = (100, 100)
camera.start_preview()
time.sleep(2)
camera.capture(stream, 'rgb')
# Show size of RGB data
print(stream.array.shape)

gordon77
Posts: 5075
Joined: Sun Aug 05, 2012 3:12 pm

Re: Motion Detection

Mon May 18, 2015 9:07 pm

Try doing a numpy.average of the image that should give you a value related to the brightness

elonmuskistheman
Posts: 7
Joined: Mon Nov 24, 2014 3:52 pm

Re: Motion Detection

Tue May 19, 2015 1:44 pm

Looks like it is a possible solution, should find out later today, but so far tried on 5 objects and with the lighting in the lab saw:

notebook paper = 100.7
hand = 30.1
foil wrapper = 108
carboard = 32.9
black trashbag = 0.02

so it might be sensitive enough to detect as is. I would imagine it would be if I could restrict the analysis to the flame object. What does the camera.resolution of 100, 100 do? Perform the analysis on a centered 100 x 100 pixel block of the picture?

Thanks, and will let you know if the as is worked.

gordon77
Posts: 5075
Joined: Sun Aug 05, 2012 3:12 pm

Re: Motion Detection

Tue May 19, 2015 2:20 pm

I think camera.resolution is size of the picture you are getting from the camera eg 800 x600, I would assume it will resize the full image to this not crop it.

To crop a numpy.array

newarray = oldarray[y-crop:y+crop,x-crop:x+crop]

where crop is 1/2 the size of the cropped section so for 100x100 use crop = 50, x and y are the centre position of the crop.

so for the centre 100x 100 of a 640 x 480 image use

crop = 50
x = 320
y = 240

Gordon

elonmuskistheman
Posts: 7
Joined: Mon Nov 24, 2014 3:52 pm

Re: Motion Detection

Tue May 19, 2015 8:30 pm

Very good, I think I will crop it at least to half, maybe to 1/4 size next time.

Checked 10 readings of avg and sum and looked pretty stable so should be a good baseline. Ended up not being able to test the whole run, though. Was running a closed furnace at 850C and had to get the camera like a foot from the flame so had to move the camera when opening, as this run the flame stays lit til 400C, whereas others it goes out after 850C step ends.

I think this average pixel method can most likely work with the above cropped code added in, so will be sure to do that next time.

Thanks a lot for the tips, both were extremely helpful.

elonmuskistheman

Avg Sum
Mean 75.56 2267200.1
Std Dev 0.407921561 12367.63636
COV 0.539864427 0.545502638
Range Low 75.1 2253322
Range High 76.5 2295697
Range Diff 1.4 42375

User avatar
jbeale
Posts: 3688
Joined: Tue Nov 22, 2011 11:51 pm
Contact: Website

Re: Motion Detection

Tue May 19, 2015 8:49 pm

Probably best to keep the camera some distance from high-temperature processes :-). If the original R-Pi camera is too wide-angle for you, you can get aftermarket alternative cameras with interchangeable M12 lenses including 8 or 16 mm which is a long telephoto on this sensor. Search for "raspberry camera board M12" on ebay or Amazon. Be aware that some of these knockoff boards do not have IR filters. In that case your flame will be likely overexposed and no color information will be present, unless you add your own filter.

gordon77
Posts: 5075
Joined: Sun Aug 05, 2012 3:12 pm

Re: Motion Detection

Tue May 19, 2015 9:07 pm

Can you upload a picture of what the camera is seeing and what the flame looks like.

gordon77
Posts: 5075
Joined: Sun Aug 05, 2012 3:12 pm

Re: Motion Detection

Wed May 20, 2015 9:47 am

Here's a program to try. It uses the Pi camera and Opencv so you may need to install that with sudo apt-get install python-opencv

You should see 3 windows, 1 with the camera image with a red rectangle to show where it is detecting, click on the image to move this, a 2nd control window where you can set the camera, detection window size, zoom in/out etc and a 3rd window showing the detected area.

When it sees movement you will see FLAME in the Control window.

Note I don't know what this flame looks like so it may not detect movement so you chose between motion or light level.

Code: Select all

import cv2
import numpy as np
import time
import os
from decimal import *

print "Press ESC to EXIT"
print " "
print "Left Click on control buttons to Decrement, Right Click to Increment"

if os.path.exists('/dev/video0') == False:
  path = 'sudo modprobe bcm2835-v4l2 max_video_width=2592 max_video_height=1944'
  os.system (path)
  time.sleep(1)

def onmouse(event,a,b,flags,params):
  global ix,iy
  if event == cv2.EVENT_LBUTTONDOWN:
    if a < width - xcrop and a > xcrop:
       if b < height - ycrop and b > ycrop:
         ix,iy = a,b

def onmouse2(event,x,y,flags,params):
  global ix2,iy2
  if event == cv2.EVENT_LBUTTONDOWN:
     ix2 = (int(x/64)*10) + int(y/32) + 10
     iy2 = -1
     
  if event == cv2.EVENT_RBUTTONDOWN:
     ix2 = (int(x/64)*10) + int(y/32) + 10
     iy2 = 1
     
def keys (cn,rn,bh,kr,kg,kb,kf):
  kx = (cn * 64) + 1
  ky = (rn * 32) + 1
  cv2.rectangle(q,(kx,ky+(bh*15)),(kx+62,ky+30),(kb,kg,kr),kf)

def text (cn,rn,th,text,tf,tr,tg,tb,tw):
  tx = (cn * 64) + (29 - (len(text))*3)
  ty = (rn*32)+ (th*14) +12
  cv2.putText(q,text,(tx,ty), font, tf,(tb,tg,tr),tw)
  cv2.imshow( winName2,q)

width = 640
height = 480
cam = cv2.VideoCapture(0)
cam.set(3,width)
cam.set(4,height)
filno = 0
ix2 = 0
iy2 = 0
ix = 320
iy = 240
xcrop = 20
ycrop =40
thres = 20
trigger = 10
zoom = 0
AutoE = 0
ExpT = 100
ISO = 0
AEB = 12
FPS = 15
brightness = 50
contrast = 30
timeout = 5
detect = 0

rpiwidth = [640,800,960,1280,1920,2592]
rpiheight = [480,600,720,960,1440,1944]
width = rpiwidth[zoom]
height = rpiheight[zoom]

winName = "Flame Indicator"
winName2 = "Control"
winName3 = "Cropped"
cv2.namedWindow(winName, cv2.CV_WINDOW_AUTOSIZE)
cv2.namedWindow(winName2, cv2.CV_WINDOW_AUTOSIZE)
cv2.namedWindow(winName3, cv2.CV_WINDOW_AUTOSIZE)
q = np.zeros((320,128,3), np.uint8)
s = np.zeros((height,width,3), np.uint8)
s1 = np.zeros((height,width,3), np.uint8)
z = np.zeros((ycrop,xcrop,3), np.uint8)

font = cv2.FONT_HERSHEY_SIMPLEX
b = 0
while b < 10:
  keys (0,b,0,128,128,128,-1)
  b +=1
b = 0
while b < 10:
  keys (1,b,0,128,128,128,-1)
  b +=1
text (0,0,0,'xCrop',.4,255,255,255,1)
text (0,0,1,str(xcrop),.4,255,0,0,1)
text (0,1,0,'yCrop',.4,255,255,255,1)
text (0,1,1,str(ycrop),.4,255,0,0,1)
text (0,2,0,'Threshold',.4,255,255,255,1)
text (0,2,1,str(thres),.4,255,0,0,1)
text (0,3,0,'Trigger',.4,255,255,255,1)
text (0,3,1,str(trigger)+"%",.4,255,0,0,1)
text (1,0,0,'Zoom',.4,255,255,255,1)
text (1,0,1,str(zoom),.4,255,0,0,1)
text (1,5,0,'Brightness',.4,255,255,255,1)
text (1,5,1,str(brightness),.4,255,0,0,1)
text (1,6,0,'Contrast',.4,255,255,255,1)
text (1,6,1,str(contrast),.4,255,0,0,1)
text (1,9,0,'Timeout',.4,255,255,255,1)
text (1,9,1,str(timeout),.4,255,0,0,1)
if AutoE == 0:
  text (0,4,0,'Auto Exp',.4,0,255,0,1)
else:
  text (0,4,0,'Auto Exp',.4,255,255,255,1)
  path = 'v4l2-ctl --set-ctrl=autoexposure=1'
  os.system (path)
  if AutoE == 1:
    path = 'v4l2-ctl --set-ctrl=exposure_time_absolute=' + str(ExpT)
    os.system (path)
if AutoE == 0:
   text (0,5,0,'Exp Time',.4,255,255,255,1)
else:
   text (0,5,0,'Exp Time',.4,0,255,0,1)
text (0,5,1,str(ExpT/10)+"mS",.4,255,0,0,1)
text (0,6,0,'ISO',.4,255,255,255,1)
if ISO == 0:
   text (0,6,1,"Auto",.4,255,0,0,1)
if ISO == 1:
   text (0,6,1,"100",.4,255,0,0,1)
if ISO == 2:
   text (0,6,1,"200",.4,255,0,0,1)
if ISO == 3:
   text (0,6,1,"400",.4,255,0,0,1)
if ISO == 4:
   text (0,6,1,"800",.4,255,0,0,1)
text (0,7,0,'AEB',.4,255,255,255,1)
text (0,7,1,str(AEB-12),.4,255,0,0,1)
text (0,8,0,'FPS',.4,255,255,255,1)
text (0,8,1,str(FPS),.4,255,0,0,1)
if detect == 0:
  text (1,4,0,'Motion',.4,0,255,0,1)
  text (0,2,0,'Threshold',.4,255,255,255,1)
  text (0,2,1,str(thres),.4,255,0,0,1)
else:
  text (1,4,0,'Light',.4,255,255,255,1)
  text (0,2,0,'Threshold',.4,50,50,50,1)
  text (0,2,1,str(thres),.4,50,0,0,1)

cv2.imshow( winName2,q)
t0 = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
t = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
cv2.setMouseCallback(winName,onmouse)
cv2.setMouseCallback(winName2,onmouse2)
start = time.time()
keys (0,9,0,0,0,0,-1)
 
while True:
  if ix2 > 0:
    if ix2 == 10:
      if iy2 < 0 and xcrop > 10:
         xcrop = xcrop - 2
      if iy2 > 0 and xcrop < 100:
         xcrop = xcrop + 2
      keys (0,0,1,128,128,128,-1)
      text (0,0,1,str(xcrop),.4,255,0,0,1)
      cv2.imshow( winName2,q)
      ix2 = 0
      iy2 = 0
      
    if ix2 == 11:
      if iy2 < 0 and ycrop > 10:
         ycrop = ycrop - 2
      if iy2 > 0 and ycrop < 100:
         ycrop = ycrop + 2
      keys (0,1,1,128,128,128,-1)
      text (0,1,1,str(ycrop),.4,255,0,0,1)
      cv2.imshow( winName2,q)
      ix2 = 0
      iy2 = 0

    if ix2 == 12:
      if iy2 < 0 and thres > 2:
         thres = thres - 2
      if iy2 > 0 and thres < 253:
         thres = thres + 2
      keys (0,2,1,128,128,128,-1)
      text (0,2,1,str(thres),.4,255,0,0,1)
      ix2 = 0
      iy2 = 0
      
    if ix2 == 13:
      if iy2 < 0 and trigger > 2:
         trigger = trigger - 2
      if iy2 > 0 and trigger < 97:
         trigger = trigger + 2
      keys (0,3,1,128,128,128,-1)
      text (0,3,1,str(trigger)+"%",.4,255,0,0,1)
      ix2 = 0
      iy2 = 0

    if ix2 == 14:
      if AutoE == 0:
         AutoE = 1
         text (0,4,0,'Auto Exp',.4,255,255,255,1)
         text (0,5,0,'Exp Time',.4,0,255,0,1)
         path = 'v4l2-ctl --set-ctrl=auto_exposure=1'
         os.system (path)
         path = 'v4l2-ctl --set-ctrl=exposure_time_absolute=' + str(ExpT)
         os.system (path)
         ix2 = 0
      else:
         AutoE = 0
         text (0,4,0,'Auto Exp',.4,0,255,0,1)
         text (0,5,0,'Exp Time',.4,255,255,255,1)
         path = 'v4l2-ctl --set-ctrl=auto_exposure=0'
         os.system (path)
         path = 'v4l2-ctl --set-ctrl=auto_exposure=0'
         os.system (path)
         ix2 = 0
         cam.set(3,width)
         cam.set(4,height)
         
    if ix2 == 15:
      if iy2 < 0 and ExpT > 10:
         ExpT = ExpT - 10
      if iy2 > 0 and ExpT < int(Decimal(Decimal(1)/Decimal(FPS))*10000):
         ExpT = ExpT + 10
      keys (0,5,1,128,128,128,-1)
      text (0,5,1,str(ExpT/10)+"mS",.4,255,0,0,1)
      path = 'v4l2-ctl --set-ctrl=exposure_time_absolute=' + str(ExpT)
      os.system (path)
      path = 'v4l2-ctl --set-ctrl=auto_exposure=1'
      os.system (path)
      AutoE = 1
      text (0,4,0,'Auto Exp',.4,255,255,255,1)
      text (0,5,0,'Exp Time',.4,0,255,0,1)
      ix2 = 0
      iy2 = 0
      
    if ix2 == 16:
      if iy2 < 0 and ISO > 0:
         ISO = ISO - 1
      if iy2 > 0 and ISO < 4:
         ISO = ISO + 1
      keys (0,6,1,128,128,128,-1)
      if ISO == 0:
         ISO2 = 0
         text (0,6,1,"Auto",.4,255,0,0,1)
      if ISO == 1:
         ISO2 = 100
         text (0,6,1,"100",.4,255,0,0,1)
      if ISO == 2:
         ISO2 = 200
         text (0,6,1,"200",.4,255,0,0,1)
      if ISO == 3:
         ISO2 = 400
         text (0,6,1,"400",.4,255,0,0,1)
      if ISO == 4:
         ISO2 = 800
         text (0,6,1,"800",.4,255,0,0,1)
      
      path = 'v4l2-ctl --set-ctrl=iso_sensitivity=' + str(ISO)
      os.system (path)
      path = 'v4l2-ctl --set-ctrl=auto_exposure=0'
      os.system (path)
      ix2 = 0
      iy2 = 0
      
    if ix2 == 17:
      if iy2 < 0 and AEB > 0:
         AEB = AEB - 1
      if iy2 > 0 and AEB < 24:
         AEB = AEB + 1
      keys (0,7,1,128,128,128,-1)
      text (0,7,1,str(AEB-12),.4,255,0,0,1)
      path = 'v4l2-ctl --set-ctrl=auto_exposure=0'
      os.system (path)
      path = 'v4l2-ctl --set-ctrl=auto_exposure_bias=' + str(AEB)
      os.system (path)
      AutoE = 0
      text (0,4,0,'Auto Exp',.4,0,255,0,1)
      text (0,5,0,'Exp Time',.4,255,255,255,1)
      ix2 = 0
      iy2 = 0
      
    if ix2 == 18:
      if iy2 < 0 and FPS > 3:
         FPS = FPS - 1
      if iy2 > 0 and FPS < 60:
         FPS = FPS + 1
      keys (0,8,1,128,128,128,-1)
      text (0,8,1,str(FPS),.4,255,0,0,1)
      path = 'v4l2-ctl -p ' + str(FPS)
      os.system (path)
      if ExpT > int(Decimal(Decimal(1)/Decimal(FPS))*10000):
         ExpT = 10*((int(Decimal(Decimal(1)/Decimal(FPS))*10000))/10)
         keys (0,5,1,128,128,128,-1)
         text (0,5,1,str(ExpT/10)+"mS",.4,255,0,0,1)
         if AutoE == 1:
            path = 'v4l2-ctl --set-ctrl=exposure_time_absolute=' + str(ExpT)
            os.system (path)
      ix2 = 0
      iy2 = 0

    if ix2 == 20:
      if iy2 < 0 and zoom > 0:
         zoom = zoom - 1
      if iy2 > 0 and zoom < 5:
         zoom = zoom + 1
      keys (1,0,1,128,128,128,-1)
      text (1,0,1,str(zoom),.4,255,0,0,1)
      cv2.imshow( winName2,q)
      width = rpiwidth[zoom]
      height = rpiheight[zoom]
      cam.set(3,width)
      cam.set(4,height)
      path = 'v4l2-ctl --set-ctrl=auto_exposure=0'
      os.system (path)
      AutoE = 0
      text (0,4,0,'Auto Exp',.4,0,255,0,1)
      text (0,5,0,'Exp Time',.4,255,255,255,1)
      s = np.zeros((height,width,3), np.uint8)
      s1 = np.zeros((height,width,3), np.uint8)

      ix2 = 0
      iy2 = 0

    if ix2 == 24:
      if detect == 0:
         detect = 1
         keys (1,4,0,128,128,128,-1)
         text (1,4,0,'Light',.4,0,255,0,1)
         text (0,2,0,'Threshold',.4,50,50,50,1)
         text (0,2,1,str(thres),.4,50,0,0,1)
         ix2 = 0
      else:
         detect = 0
         keys (1,4,0,128,128,128,-1)
         text (1,4,0,'Motion',.4,0,255,0,1)
         text (0,2,0,'Threshold',.4,255,255,255,1)
         text (0,2,1,str(thres),.4,255,0,0,1)
      ix2 = 0
      iy2 = 0
         
      
    if ix2 == 25:
      if iy2 < 0 and brightness > 0:
         brightness = brightness - 2
      if iy2 > 0 and brightness < 100:
         brightness = brightness + 2
      keys (1,5,1,128,128,128,-1)
      text (1,5,1,str(brightness),.4,255,0,0,1)
      cv2.imshow( winName2,q)
      path = 'v4l2-ctl --set-ctrl=brightness=' + str(brightness)
      os.system (path)
      ix2 = 0
      iy2 = 0
      
    if ix2 == 26:
      if iy2 < 0 and contrast > -100:
         contrast = contrast - 5
      if iy2 > 0 and contrast < 100:
         contrast = contrast + 5
      keys (1,6,1,128,128,128,-1)
      text (1,6,1,str(contrast),.4,255,0,0,1)
      cv2.imshow( winName2,q)
      path = 'v4l2-ctl --set-ctrl=contrast=' + str(contrast)
      os.system (path)
      ix2 = 0
      iy2 = 0
      
    if ix2 == 29:
      if iy2 < 0 and timeout > 1:
         timeout = timeout - 1
      if iy2 > 0 and timeout < 100:
         timeout = timeout + 1
      keys (1,9,1,128,128,128,-1)
      text (1,9,1,str(timeout),.4,255,0,0,1)
      cv2.imshow( winName2,q)
      ix2 = 0
      iy2 = 0
      
  s = cam.read()[1]
  s1 = s[(height/2)-240:(height/2)+240,(width/2)-320:(width/2)+320]
  cv2.rectangle(s1,(ix-(xcrop+1),iy-(ycrop+1)),(ix+(xcrop+1),iy+(ycrop+1)),(0,0,255),1)
  cv2.imshow( winName,s1)
  t = cv2.cvtColor(s1,cv2.COLOR_RGB2GRAY)
  av = t[iy-ycrop:iy+ycrop,ix-xcrop:ix+xcrop]
  now = time.time()
  if now < start:
    start = time.time()
  if now > start + timeout:
    keys (0,9,0,0,0,0,-1)
  if len(t) == len(t0):
    l = t[iy-ycrop:iy+ycrop,ix-xcrop:ix+xcrop]
    im = cv2.absdiff(t, t0)
    c = im[iy-ycrop:iy+ycrop,ix-xcrop:ix+xcrop]
    c[c < thres] = 0
    c[c >= thres] = 200
    cv2.imshow( winName3,c)
    total = np.sum(c)/200
    trig =(xcrop*ycrop*4)/(100/trigger)
    trigl = np.average(av)
    cv2.imshow( winName2,q)
    keys (0,9,1,0,0,0,-1)
    #print trigl , ((Decimal(trigger)/Decimal(100))*255)
    if (total > trig and detect == 0) or (trigl > ((Decimal(trigger)/Decimal(100))*255) and detect == 1):
      
      text (0,9,1,'FLAME',.4,0,255,0,1)
      text (0,9,0,'FLAME',.4,0,255,0,1)
      
      start = time.time()

  t0 = t
 
  key = cv2.waitKey(10)
  if key == 27:
    cv2.destroyWindow(winName)
    break
 
print "Goodbye"

Return to “Camera board”