CHDK Wiki
Register
(Created page with "video|right|300px right|300px This page describes how you can use CHDK to capture fotos and videos of birds. ('''''It is a work in p...")
 
m (cat)
(7 intermediate revisions by 3 users not shown)
Line 1: Line 1:
  +
This page describes how you can use CHDK to capture fotos and videos of birds.
[[File:Placeholder|video|right|300px]] [[File:Placeholder|right|300px]]
 
This page describes how you can use CHDK to capture fotos and videos of birds. ('''''It is a work in progress''''')
 
   
==Location setup==
+
==Pose Your Birds==
   
  +
Bird feeders are a great way to attract birds to your camera.
j
 
  +
#Build a feeder that forces the bird to perch at a set distance from the camera.
  +
#Site the feeder in sunlight but watch for the camera casting a shadow.
  +
#Leave the feeder out for a while without the camera so they get used to it.
  +
#Use a bird cutout on a clothes peg to frame your shot.
   
  +
Here is a very simple feeder made from coat hanger wire and an old bottle top.
==Useful Scripts==
 
   
  +
[[File:Feeder.jpg|thumb|Coat hanger feeder]]
DaveCam - Video events recorder that records all bird visits and combines all visits into a single file.
 
  +
  +
==Lazy CHDK Birding==
  +
This is a very easy way to get great bird fotos from your CHDK camera.
  +
#Set up your feeder as above with your camera near it on a tripod.
  +
#Turn on Mute in your Canon menu to prevent scaring the birds.
  +
#Lock the subject distance using CHDK menu>Enhanced Photo Operations>Override Subject Distance.
  +
#Load script "interval.lua" and set interval to 1 second.
  +
#Start script running.
  +
CHDK will start taking fotos which you can sort thru to find any goodies like these.
  +
  +
<gallery type="slider">
  +
coaltit1.jpg
  +
coaltit2.jpg
  +
</gallery>
  +
  +
  +
  +
==DaveCam Script==
  +
  +
DaveCam continuously records video clips of bird visits to your feeder station. It deletes any clips without visits as it goes along. It also produces an [http://avisynth.org/mediawiki/Main_Page AviSynth] file which trims the remaining videos and combines them into a single clip. This clip can be played in media players or edited in [http://virtualdub.org/ VirtualDub].
  +
  +
The forum thread for the script is [http://chdk.setepontos.com/index.php?topic=9645.new#new here] and the parameters are :
  +
  +
'''Subject distance (cm)''' - the camera focus is locked at this distance.<br />'''Video FPS''' - the frame rate of your video.<br />'''Trigger threshold '''- change in scene brightnessthat will trigger the start of an event.<br />'''Release threshold '''- the event will be judged to have ended when the scene brightness returns to within this value.<br />'''Grid options - '''standard motion detection grid options.<br />'''Detection lag 1/10s -''' time taken for camera to recognise an event (my A810 value is 14).<br />'''Interval between events (s)''' - time to wait for a subsequent event before closing the clip. Allows for several closely spaced events on each clip.<br />'''Longest event (s) -''' maximum event duration. Used to prevent false events keeping clip open.<br />'''Frames before event '''- adds frames to AviSynth file before event occurs. This lets you see the bird landing.<br />'''Frames after event '''- similar to above.<br />'''Clip length (s)''' - clip will be deleted if no events occur during this time.
  +
  +
You will need to install AviSynth on your PC to view the combined clip. You will also need to install the [http://tateu.net/ QTSource] plugin.
  +
  +
DaveCam was written for an A810 which records Quicktime (.mov) videos and has a dedicated video button.<br />
  +
  +
<syntaxhighlight lang="lua">
  +
--[[
  +
@title DaveCam by Davo
  +
@param d Subject distance (cm)
  +
@default d 20
  +
@param f Video FPS
  +
@default f 30
  +
@param t Trigger threshold
  +
@default t 30
  +
@param n Release threshold
  +
@default n 10
  +
@param g Grid options
  +
@default g 0
  +
@range g 0 3
  +
@param l Detection lag 1/10s
  +
@default l 14
  +
@param v Interval between events (s)
  +
@default v 30
  +
@param z Longest event (s)
  +
@default z 120
  +
@param b Frames before event
  +
@default b 30
  +
@param a Frames after event
  +
@default a 30
  +
@param c Clip length (s)
  +
@default c 300
  +
--]]
  +
  +
-- md variables
  +
ma = 8 -- columns
  +
mb = 6 -- rows
  +
mc = 1 -- measure mode
  +
mf = t -- trigger threshold for m
  +
mg = g -- draw grid
  +
mh = 0 -- not used in LUA
  +
mi = 0 -- region masking mode
  +
mj = 0 -- first column
  +
mk = 0 -- first row
  +
ml = 0 -- last column
  +
mm = 0 -- last row
  +
mn = 0 -- optional parameters
  +
mo = 1 -- pixel step
  +
mp = 0 -- trigger Delay (mSec)
  +
noise = n -- background noise
  +
timeout = z * 1000
  +
interval = v * 1000
  +
  +
-- Edit variables
  +
frames_before = b
  +
frames_after = a
  +
max_clip = c * 1000
  +
fps = f
  +
md_lag = l * 100 -- camera md lag time (ms)
  +
  +
-- Other variables
  +
md_original = {}
  +
md_trigger = {}
  +
md_current = {}
  +
clips = 0
  +
filename = ""
  +
subject_distance = 10 * d
  +
events = 0
  +
tot_events = 0
  +
avs_text = ""
  +
timed_out = false
  +
  +
-- Functions
  +
function fill_md_array(name)
  +
for row = 1, mb do
  +
for col = 1, ma do
  +
name[(row - 1) * ma + col] = md_get_cell_val(col,row)
  +
end -- for col
  +
end -- for row
  +
end -- fill_array()
  +
  +
function compare_scenes(original, current, sensitivity)
  +
for row = 1, mb do
  +
for col = 1, ma do
  +
difference = math.abs(original[(row - 1) * ma + col] - current[(row - 1) * ma + col])
  +
if difference >= sensitivity then
  +
return false
  +
end -- if
  +
end -- for col
  +
end -- for row
  +
return true
  +
end -- compare_scenes()
  +
  +
function get_current_folder()
  +
dir = os.listdir("A/DCIM", false)
  +
count = table.getn(dir)
  +
return(dir[count])
  +
end
  +
  +
function get_last_clip_name()
  +
dir = os.listdir("A/DCIM/" .. get_current_folder(), false)
  +
count = table.getn(dir)
  +
return(dir[count])
  +
end -- end of get_last_clip_name()
  +
  +
function update_avs_file()
  +
last_clip = get_last_clip_name()
  +
if clips == 1 then
  +
filename = "A/DCIM/" .. get_current_folder() .. "/" .. string.sub(last_clip, 1, 8) .. ".AVS"
  +
end
  +
avs_text = "trim(QTInput(\"" .. last_clip .. "\", audio = 1)," .. f_start[1] .. "," .. f_end[1] .. ")\r\n"
  +
if events > 1 then
  +
for i = 2, events do
  +
if f_start[i] < f_end[i-1] then -- remove overlaps
  +
f_start[i] = f_end[i-1] + 1
  +
end
  +
avs_text = avs_text .. "\\++ " .. "trim(QTInput(\"" .. last_clip .. "\", audio = 1)," .. f_start[i] .. "," .. f_end[i] .. ")\r\n"
  +
end
  +
end
  +
if clips == 1 then
  +
tfile = io.open(filename, "w")
  +
tfile:write(avs_text)
  +
tfile:close()
  +
else
  +
avs_text = "\\++ " .. avs_text
  +
tfile = io.open(filename, "a")
  +
tfile:write(avs_text)
  +
tfile:close()
  +
end
  +
print("Updated AVS file")
  +
end
  +
  +
function restore()
  +
--print(get_movie_status())
  +
if get_movie_status() == 4 then
  +
post_levent_to_ui('PressMovieButton')
  +
end
  +
print("User stopped script")
  +
tfile = io.open(filename, "a")
  +
tfile:write("Subtitle(\"DaveCam\", align=3)")
  +
tfile:close()
  +
end
  +
  +
repeat
  +
avs_text = ""
  +
finished = false
  +
timed_out = false
  +
events = 0
  +
f_start = {}
  +
f_end = {}
  +
set_focus(subject_distance)
  +
sleep(500)
  +
press("shoot_half")
  +
sleep(1000)
  +
click("left")
  +
sleep(1000)
  +
release("shoot_half")
  +
clip_start = get_tick_count()
  +
press("video")
  +
sleep(2000)
  +
release("video")
  +
  +
-- Get original scene
  +
zones = md_detect_motion( ma, mb, mc, 200, 100, 900, mg, mh, mi, mj, mk, ml, mm, mn, mo, mp)
  +
fill_md_array(md_original)
  +
  +
repeat
  +
if events == 0 then
  +
zones = md_detect_motion( ma, mb, mc, max_clip, 100, mf, mg, mh, mi, mj, mk, ml, mm, mn, mo, mp)
  +
else
  +
zones = md_detect_motion( ma, mb, mc, interval, 100, mf, mg, mh, mi, mj, mk, ml, mm, mn, mo, mp)
  +
end
  +
if zones == 0 then
  +
finished = true
  +
else
  +
events = events + 1
  +
tot_events = tot_events + 1
  +
print("Clip " .. clips + 1 .. ", event " .. events)
  +
t_start = get_tick_count()
  +
f_start[events] = ((fps * (t_start - clip_start - md_lag)) / 1000) - frames_before
  +
repeat
  +
zones = md_detect_motion( ma, mb, mc, 200, 100, 900, mg, mh, mi, mj, mk, ml, mm, mn, mo, mp)
  +
fill_md_array(md_current)
  +
if (get_tick_count() - t_start) > timeout then
  +
timed_out = true
  +
finished = true
  +
end
  +
until compare_scenes(md_original, md_current, noise) == true or timed_out == true
  +
f_end[events] = ((fps * (get_tick_count() - clip_start - md_lag)) / 1000) + frames_after
  +
end
  +
until finished == true
  +
  +
if timed_out == true then
  +
sleep(2000 + frames_after * 1000 / fps)
  +
end
  +
press("video")
  +
sleep(2000)
  +
release("video")
  +
sleep(500)
  +
  +
-- Clip management
  +
if events == 0 then
  +
-- delete clip
  +
clip_name = get_last_clip_name()
  +
rubbish = "A/DCIM/" .. get_current_folder() .. "/" .. clip_name
  +
os.remove(rubbish)
  +
--print("Deleted " .. clip_name)
  +
else
  +
-- update AVS file
  +
clips = clips + 1
  +
update_avs_file()
  +
end
  +
  +
until false
  +
</syntaxhighlight>
  +
  +
[[Category:Scripts]]
  +
[[Category:Lua]]

Revision as of 08:01, 25 August 2013

This page describes how you can use CHDK to capture fotos and videos of birds.

Pose Your Birds

Bird feeders are a great way to attract birds to your camera.

  1. Build a feeder that forces the bird to perch at a set distance from the camera.
  2. Site the feeder in sunlight but watch for the camera casting a shadow.
  3. Leave the feeder out for a while without the camera so they get used to it.
  4. Use a bird cutout on a clothes peg to frame your shot.

Here is a very simple feeder made from coat hanger wire and an old bottle top.

Feeder

Coat hanger feeder

Lazy CHDK Birding

This is a very easy way to get great bird fotos from your CHDK camera.

  1. Set up your feeder as above with your camera near it on a tripod.
  2. Turn on Mute in your Canon menu to prevent scaring the birds.
  3. Lock the subject distance using CHDK menu>Enhanced Photo Operations>Override Subject Distance.
  4. Load script "interval.lua" and set interval to 1 second.
  5. Start script running.

CHDK will start taking fotos which you can sort thru to find any goodies like these.



DaveCam Script

DaveCam continuously records video clips of bird visits to your feeder station. It deletes any clips without visits as it goes along. It also produces an AviSynth file which trims the remaining videos and combines them into a single clip. This clip can be played in media players or edited in VirtualDub.

The forum thread for the script is here and the parameters are :

Subject distance (cm) - the camera focus is locked at this distance.
Video FPS - the frame rate of your video.
Trigger threshold - change in scene brightnessthat will trigger the start of an event.
Release threshold - the event will be judged to have ended when the scene brightness returns to within this value.
Grid options - standard motion detection grid options.
Detection lag 1/10s - time taken for camera to recognise an event (my A810 value is 14).
Interval between events (s) - time to wait for a subsequent event before closing the clip. Allows for several closely spaced events on each clip.
Longest event (s) - maximum event duration. Used to prevent false events keeping clip open.
Frames before event - adds frames to AviSynth file before event occurs. This lets you see the bird landing.
Frames after event - similar to above.
Clip length (s) - clip will be deleted if no events occur during this time.

You will need to install AviSynth on your PC to view the combined clip. You will also need to install the QTSource plugin.

DaveCam was written for an A810 which records Quicktime (.mov) videos and has a dedicated video button.

--[[
@title DaveCam by Davo
@param d Subject distance (cm)
@default d 20
@param f Video FPS
@default f 30
@param t Trigger threshold
@default t 30 
@param n Release threshold
@default n 10
@param g Grid options
@default g 0
@range g 0 3
@param l Detection lag 1/10s
@default l 14
@param v Interval between events (s)
@default v 30
@param z Longest event (s)
@default z 120
@param b Frames before event
@default b 30
@param a Frames after event
@default a 30
@param c Clip length (s)
@default c 300
--]] 

-- md variables
ma = 8 -- columns
mb = 6 -- rows
mc = 1 -- measure mode
mf = t -- trigger threshold for m
mg = g -- draw grid  
mh = 0 -- not used in LUA 
mi = 0 -- region masking mode
mj = 0 --   first column
mk = 0 --   first row
ml = 0 --   last column
mm = 0 --   last row
mn = 0 -- optional parameters
mo = 1 -- pixel step
mp = 0 -- trigger Delay (mSec)
noise = n -- background noise
timeout = z * 1000
interval = v * 1000

-- Edit variables
frames_before = b
frames_after = a
max_clip = c * 1000
fps = f
md_lag = l * 100 -- camera md lag time (ms)

-- Other variables
md_original = {}
md_trigger = {}
md_current = {}
clips = 0
filename = ""
subject_distance = 10 * d
events = 0
tot_events = 0
avs_text = ""
timed_out = false

-- Functions
function fill_md_array(name)
	for row = 1, mb do
		for col = 1, ma do
			name[(row - 1) * ma + col] = md_get_cell_val(col,row)
		end -- for col
	end -- for row
end -- fill_array()

function compare_scenes(original, current, sensitivity)
	for row = 1, mb do
		for col = 1, ma do
			difference = math.abs(original[(row - 1) * ma + col] - current[(row - 1) * ma + col])
			if difference >= sensitivity then
				return false
			end -- if
		end -- for col
	end -- for row
	return true
end -- compare_scenes()

function get_current_folder()
	dir = os.listdir("A/DCIM", false)
	count = table.getn(dir)
	return(dir[count])
end

function get_last_clip_name()
	dir = os.listdir("A/DCIM/" .. get_current_folder(), false)
	count = table.getn(dir)
	return(dir[count])
end -- end of get_last_clip_name()

function update_avs_file()
		last_clip = get_last_clip_name()
		if clips == 1 then
			filename = "A/DCIM/" .. get_current_folder() .. "/" .. string.sub(last_clip, 1, 8) .. ".AVS"
		end		
		avs_text = "trim(QTInput(\"" .. last_clip .. "\", audio = 1)," .. f_start[1] .. "," .. f_end[1] .. ")\r\n"
		if events > 1 then
			for i = 2, events do				
				if f_start[i] < f_end[i-1] then -- remove overlaps
					f_start[i] = f_end[i-1] + 1
				end
				avs_text = avs_text .. "\\++ " .. "trim(QTInput(\"" .. last_clip .. "\", audio = 1)," .. f_start[i] .. "," .. f_end[i] .. ")\r\n"
			end
		end		
		if clips == 1 then
			tfile = io.open(filename, "w")
			tfile:write(avs_text)
			tfile:close()		
		else
			avs_text = "\\++ " .. avs_text
			tfile = io.open(filename, "a")
			tfile:write(avs_text)
			tfile:close()			
		end
		print("Updated AVS file")		
end

function restore()
	--print(get_movie_status())
	if get_movie_status() == 4 then
		post_levent_to_ui('PressMovieButton')
	 end
	print("User stopped script")
	tfile = io.open(filename, "a")
	tfile:write("Subtitle(\"DaveCam\", align=3)")
	tfile:close()			
end

repeat
	avs_text = ""
	finished = false
	timed_out = false
	events = 0
	f_start = {}
	f_end = {}
	set_focus(subject_distance)
	sleep(500)
	press("shoot_half")
	sleep(1000)
	click("left")
	sleep(1000)
	release("shoot_half")	
	clip_start = get_tick_count()
	press("video")
	sleep(2000)
	release("video")	
	
	-- Get original scene
	zones = md_detect_motion( ma, mb, mc, 200, 100, 900, mg, mh, mi, mj, mk, ml, mm, mn, mo, mp)
	fill_md_array(md_original)	
	
	repeat
		if events == 0 then
			zones = md_detect_motion( ma, mb, mc, max_clip, 100, mf, mg, mh, mi, mj, mk, ml, mm, mn, mo, mp)
		else
			zones = md_detect_motion( ma, mb, mc, interval, 100, mf, mg, mh, mi, mj, mk, ml, mm, mn, mo, mp)
		end		
		if zones ==  0 then
			finished = true
		else
			events = events + 1
			tot_events = tot_events + 1
			print("Clip " .. clips + 1 .. ", event " .. events)
			t_start = get_tick_count()
			f_start[events] = ((fps * (t_start - clip_start - md_lag)) / 1000) - frames_before 
			repeat
				zones = md_detect_motion( ma, mb, mc, 200, 100, 900, mg, mh, mi, mj, mk, ml, mm, mn, mo, mp)
				fill_md_array(md_current)
				if (get_tick_count() - t_start) > timeout then
					timed_out = true
					finished = true
				end				
			until compare_scenes(md_original, md_current, noise) == true or timed_out == true
			f_end[events] = ((fps * (get_tick_count() - clip_start - md_lag)) / 1000) + frames_after
		end		
	until finished == true
	
	if timed_out == true then
		sleep(2000 + frames_after * 1000 / fps)
	end
	press("video")
	sleep(2000)
	release("video")	
	sleep(500)
	
	-- Clip management
	if events == 0 then
		-- delete clip
		clip_name = get_last_clip_name()
		rubbish = "A/DCIM/" .. get_current_folder() .. "/" .. clip_name
		os.remove(rubbish)    
		--print("Deleted " .. clip_name)	
	else
		-- update AVS file
		clips = clips + 1
		update_avs_file()
	end

until false