initial commit, moving files over from ardrone_autonomy fork

Esse commit está contido em:
Sameer Parekh
2012-10-23 05:51:14 -07:00
commit c7177c19d2
12 arquivos alterados com 1118 adições e 0 exclusões
+28
Ver Arquivo
@@ -0,0 +1,28 @@
# Compiled Object files
*.slo
*.lo
*.o
# Compiled Dynamic libraries
*.so
# Compiled Static libraries
*.lai
*.la
*.a
/build/CMakeFiles/
# Compiled python files
*.pyc
# emacs files
*~
# bag files
*.bag
# specific directories
bin/
build/
msg_gen/
srv_gen/
+30
Ver Arquivo
@@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
# Set the build type. Options are:
# Coverage : w/ debug symbols, w/o optimization, w/ code-coverage
# Debug : w/ debug symbols, w/o optimization
# Release : w/o debug symbols, w/ optimization
# RelWithDebInfo : w/ debug symbols, w/ optimization
# MinSizeRel : w/o debug symbols, w/ optimization, stripped binaries
#set(ROS_BUILD_TYPE RelWithDebInfo)
rosbuild_init()
#set the default path for built executables to the "bin" directory
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#set the default path for built libraries to the "lib" directory
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
#uncomment if you have defined messages
#rosbuild_genmsg()
#uncomment if you have defined services
#rosbuild_gensrv()
#common commands for building c++ executables and libraries
#rosbuild_add_library(${PROJECT_NAME} src/example.cpp)
#target_link_libraries(${PROJECT_NAME} another_library)
#rosbuild_add_boost_directories()
#rosbuild_link_boost(${PROJECT_NAME} thread)
#rosbuild_add_executable(example examples/example.cpp)
#target_link_libraries(example ${PROJECT_NAME})
+1
Ver Arquivo
@@ -0,0 +1 @@
include $(shell rospack find mk)/cmake.mk
+17
Ver Arquivo
@@ -0,0 +1,17 @@
<launch>
<node name="ardrone_driver" pkg="ardrone_autonomy" type="ardrone_driver" />
<node name="ardrone_tracker" pkg="falkor_ardrone" type="ardrone_tracker.py" output="screen" >
<param name="cascadefile" value="$(find falkor_ardrone)/cascade/lbpcascade_falkorlogobw.xml" />
</node>
<node name="ardrone_follow" pkg="falkor_ardrone" type="ardrone_follow.py" output="screen" />
<node name="ardrone_control" pkg="falkor_ardrone" type="ardrone_control.py" />
<node name="joy_node" pkg="joy" type="joy_node" >
<param name="dev" value="/dev/input/js1" />
</node>
<node pkg="rxtools" type="rxplot" name="plot_battery" args="/ardrone/navdata/batteryPercent" />
</launch>
+14
Ver Arquivo
@@ -0,0 +1,14 @@
/**
\mainpage
\htmlinclude manifest.html
\b falkor_ardrone
<!--
Provide an overview of your package.
-->
-->
*/
+21
Ver Arquivo
@@ -0,0 +1,21 @@
<package>
<description brief="falkor_ardrone">
falkor_ardrone
</description>
<author>Sameer Parekh</author>
<license>BSD</license>
<review status="unreviewed" notes=""/>
<url>http://ros.org/wiki/falkor_ardrone</url>
<depend package="rospy" />
<depend package="opencv2" />
<depend package="tf" />
<depend package="joy" />
<depend package="image_transport" />
<depend package="cv_bridge" />
<depend package="camera_info_manager" />
<depend package="sensor_msgs"/>
</package>
Arquivo executável
+73
Ver Arquivo
@@ -0,0 +1,73 @@
#!/usr/bin/env python
import roslib
roslib.load_manifest('falkor_ardrone')
import rospy
from geometry_msgs.msg import Twist
from std_msgs.msg import Empty
from ardrone_autonomy.msg import Navdata
import pid
import time
class ArdroneControl:
def __init__( self ):
self.nav_sub = rospy.Subscriber( "ardrone/navdata", Navdata, self.callback_navdata )
self.cmd_vel_pub = rospy.Publisher( "cmd_vel", Twist )
self.goal_vel_sub = rospy.Subscriber( "goal_vel", Twist, self.callback_goal_vel )
# gain_p, gain_i, gain_d
self.linearxpid = pid.Pid2( 0.5, 0.0, 0.5 )
self.linearypid = pid.Pid2( 0.5, 0.0, 0.5 )
self.vx = self.vy = self.vz = self.ax = self.ay = self.az = 0.0
self.last_time = None
self.goal_vel = Twist()
def callback_goal_vel( self, data ):
self.goal_vel = data
def callback_navdata( self, data ):
self.vx = data.vx/1e3
self.vy = data.vy/1e3
self.vz = data.vz/1e3
# these accelerations must take into account orientation, so we get acceleration relative
# to base_stabilized. This does not.
# self.ax = (data.ax*9.82)
# self.ay = (data.ay*9.82)
# self.az = (data.az - 1.0)*9.82
def update( self ):
if self.last_time == None:
self.last_time = rospy.Time.now()
dt = 0.0
else:
time = rospy.Time.now()
dt = ( time - self.last_time ).to_sec()
self.last_time = time
cmd = Twist()
cmd.angular.y = 0
cmd.angular.x = 0
cmd.angular.z = self.goal_vel.angular.z
cmd.linear.z = self.goal_vel.linear.z
cmd.linear.x = self.linearxpid.update( self.goal_vel.linear.x, self.vx, 0.0, dt )
cmd.linear.y = self.linearypid.update( self.goal_vel.linear.y, self.vy, 0.0, dt )
self.cmd_vel_pub.publish( cmd )
def main():
rospy.init_node( 'ardrone_control' )
control = ArdroneControl()
r = rospy.Rate(100)
try:
while not rospy.is_shutdown():
control.update()
r.sleep()
except KeyboardInterrupt:
print "Shutting down"
if __name__ == '__main__':
main()
Arquivo executável
+261
Ver Arquivo
@@ -0,0 +1,261 @@
#!/usr/bin/env python
import roslib
roslib.load_manifest('falkor_ardrone')
import sys
import rospy
import math
import pid
import cv2
import numpy as np
from cv_bridge import CvBridge, CvBridgeError
from geometry_msgs.msg import Point
from geometry_msgs.msg import Twist
from std_msgs.msg import Empty
from sensor_msgs.msg import Joy, Image
from ardrone_autonomy.msg import Navdata
from ardrone_autonomy.srv import LedAnim
class ArdroneFollow:
def __init__( self ):
self.led_service = rospy.ServiceProxy( "ardrone/setledanimation", LedAnim )
# print "waiting for driver to startup"
# rospy.wait_for_service( self.led_service )
self.tracker_sub = rospy.Subscriber( "ardrone_tracker/found_point",
Point, self.found_point_cb )
self.goal_vel_pub = rospy.Publisher( "goal_vel", Twist )
self.found_time = None
self.tracker_img_sub = rospy.Subscriber( "ardrone_tracker/image",
Image, self.image_cb )
self.tracker_image = None
self.timer = rospy.Timer( rospy.Duration( 0.10 ), self.timer_cb, False )
self.land_pub = rospy.Publisher( "ardrone/land", Empty )
self.takeoff_pub = rospy.Publisher( "ardrone/takeoff", Empty )
self.reset_pub = rospy.Publisher( "ardrone/reset", Empty )
self.angularZlimit = 3.141592 / 2
self.linearXlimit = 1.0
self.linearZlimit = 2.0
self.xPid = pid.Pid( 0.020, 0.0, 0.0, self.angularZlimit )
self.yPid = pid.Pid( 0.020, 0.0, 0.0, self.linearZlimit )
self.zPid = pid.Pid( 0.070, 0.0, 0.0, self.linearXlimit )
self.xPid.setPointMin = 40
self.xPid.setPointMax = 60
self.yPid.setPointMin = 40
self.yPid.setPointMax = 60
self.zPid.setPointMin = 17
self.zPid.setPointMax = 23
self.lastAnim = -1
self.found_point = Point( 0, 0, -1 )
self.old_cmd = self.current_cmd = Twist()
self.joy_sub = rospy.Subscriber( "joy", Joy, self.callback_joy )
self.manual_cmd = False
self.auto_cmd = False
self.bridge = CvBridge()
cv2.namedWindow( 'AR.Drone Follow', cv2.cv.CV_WINDOW_NORMAL )
def image_cb( self, data ):
try:
cv_image = self.bridge.imgmsg_to_cv( data, "passthrough" )
except CvBridgeError, e:
print e
self.tracker_image = np.asarray( cv_image )
def increase_z_setpt( self ):
self.zPid.setPointMin *= 1.01
self.zPid.setPointMax *= 1.01
def decrease_z_setpt( self ):
self.zPid.setPointMin /= 1.01
self.zPid.setPointMax /= 1.01
def callback_joy( self, data ):
empty_msg = Empty()
if data.buttons[12] == 1 and self.last_buttons[12] == 0:
self.takeoff()
if data.buttons[14] == 1 and self.last_buttons[14] == 0:
self.land()
if data.buttons[13] == 1 and self.last_buttons[13] == 0:
self.reset()
if data.buttons[15] == 1 and self.last_buttons[15] == 0:
self.auto_cmd = not self.auto_cmd
self.hover()
if data.buttons[4] == 1:
self.increase_z_setpt()
if data.buttons[6] == 1:
self.decrease_z_setpt()
self.last_buttons = data.buttons
# Do cmd_vel
self.current_cmd = Twist()
self.current_cmd.angular.x = self.current_cmd.angular.y = 0
self.current_cmd.angular.z = data.axes[2] * self.angularZlimit
self.current_cmd.linear.z = data.axes[3] * self.linearZlimit
self.current_cmd.linear.x = data.axes[1] * self.linearXlimit
self.current_cmd.linear.y = data.axes[0] * self.linearXlimit
if ( self.current_cmd.linear.x == 0 and
self.current_cmd.linear.y == 0 and
self.current_cmd.linear.z == 0 and
self.current_cmd.angular.z == 0 ):
self.manual_cmd = False
else:
self.setLedAnim( 9 )
self.manual_cmd = True
self.goal_vel_pub.publish( self.current_cmd )
def setLedAnim( self, animType, freq = 10 ):
if self.lastAnim == type:
return
msg = LedAnim();
msg.type = animType;
msg.freq = freq;
msg.duration = 3600;
self.led_service( type = animType, freq = freq, duration = 255 )
self.lastAnim = type
def takeoff( self ):
self.takeoff_pub.publish( Empty() )
self.setLedAnim( 9 )
def land( self ):
self.land_pub.publish( Empty() )
def reset( self ):
self.reset_pub.publish( Empty() )
def navdata_cb( self, data ):
self.vx = data.vx/1e3
self.vy = data.vy/1e3
self.vz = data.vz/1e3
self.ax = (data.ax*9.82)
self.ay = (data.ay*9.82)
self.az = (data.az - 1)*9.82
def found_point_cb( self, data ):
self.found_point = data
self.found_time = rospy.Time.now()
def hover( self ):
hoverCmd = Twist()
self.goal_vel_pub.publish( hoverCmd )
def hover_cmd_cb( self, data ):
self.hover()
def draw_picture( self ):
if self.tracker_image == None:
return
vis = self.tracker_image.copy()
(ySize, xSize, depth) = vis.shape
cx_min = int(self.xPid.setPointMin * xSize / 100)
cx_max = int(self.xPid.setPointMax * xSize / 100)
cx = int( ( cx_min + cx_max ) / 2 )
cy_min = int(self.yPid.setPointMin * ySize / 100)
cy_max = int(self.yPid.setPointMax * ySize / 100)
cy = int( ( cy_min + cy_max ) / 2 )
cv2.rectangle( vis, ( cx_min, cy_min ), ( cx_max, cy_max ),
( 0, 255, 255 ) )
areasqrt = np.sqrt( 640 * 480 )
side_min_half = int( self.zPid.setPointMin * areasqrt / 100 / 2 )
side_max_half = int( self.zPid.setPointMax * areasqrt / 100 / 2 )
cv2.rectangle( vis, ( cx - side_min_half, cy - side_min_half ),
( cx + side_min_half, cy + side_min_half ),
( 255, 255, 0 ) )
cv2.rectangle( vis, ( cx - side_max_half, cy - side_max_half ),
( cx + side_max_half, cy + side_max_half ),
( 255, 255, 0 ) )
if self.current_cmd.linear.x > 0:
line_color = ( 0, 255, 0 )
else:
line_color = ( 0, 0, 255 )
cv2.line( vis, ( 320, 180 ), ( int( xSize/2 - self.current_cmd.angular.z * 320 ),
int( ySize/2 - self.current_cmd.linear.z * 180 ) ),
line_color,
min( max( int( abs( self.current_cmd.linear.x ) * 255 ), 0 ), 255 ) )
cv2.imshow( 'AR.Drone Follow', vis )
cv2.waitKey( 1 )
def timer_cb( self, event ):
self.draw_picture()
# If we haven't received a found point in a second, let found_point be
# (0,0,-1)
if ( self.found_time == None or
( rospy.Time.now() - self.found_time ).to_sec() > 1 ):
self.found_point = Point( 0, 0, -1.0 )
self.found_time = rospy.Time.now()
if event.last_real == None:
dt = 0
else:
dt = ( event.current_real - event.last_real ).to_sec()
if self.found_point.z == -1.0:
self.current_cmd = Twist()
self.setLedAnim( 0, 2 )
else:
self.current_cmd.angular.z = self.xPid.get_output( self.found_point.x,
dt )
self.current_cmd.linear.z = self.yPid.get_output( self.found_point.y,
dt )
self.current_cmd.linear.x = self.zPid.get_output( self.found_point.z,
dt )
self.setLedAnim( 8, 2 )
if self.auto_cmd == False or self.manual_cmd == True:
self.setLedAnim( 9 )
return
self.goal_vel_pub.publish( self.current_cmd )
def main():
rospy.init_node( 'ardrone_follow' )
af = ArdroneFollow()
try:
rospy.spin()
except KeyboardInterrupt:
print "Keyboard interrupted"
if __name__ == '__main__':
main()
Arquivo executável
+62
Ver Arquivo
@@ -0,0 +1,62 @@
#!/usr/bin/env python
import roslib
roslib.load_manifest('falkor_ardrone')
import rospy
from geometry_msgs.msg import Twist
from sensor_msgs.msg import Joy
from std_msgs.msg import Empty
from ardrone_autonomy.msg import Navdata
import pid
import time
class ArdroneTeleopJoy:
def __init__( self ):
self.cmd_vel_pub = rospy.Publisher( "cmd_vel_interm", Twist )
self.land_pub = rospy.Publisher( "ardrone/land", Empty )
self.takeoff_pub = rospy.Publisher( "ardrone/takeoff", Empty )
self.reset_pub = rospy.Publisher( "ardrone/reset", Empty )
self.joy_sub = rospy.Subscriber( "joy", Joy, self.callback_joy )
def callback_joy( self, data ):
empty_msg = Empty()
if data.buttons[12] == 1 and self.last_buttons[12] == 0:
self.takeoff_pub.publish( empty_msg )
self.pause = 5.0
if data.buttons[14] == 1 and self.last_buttons[14] == 0:
self.land_pub.publish( empty_msg )
if data.buttons[13] == 1 and self.last_buttons[13] == 0:
self.reset_pub.publish( empty_msg )
self.last_buttons = data.buttons
# Do cmd_vel
cmd = Twist()
cmd.angular.x = cmd.angular.y = 0
cmd.angular.z = data.axes[2] * 3.14/2
cmd.linear.z = data.axes[3] * 2.0
cmd.linear.x = data.axes[1] * 1.0
cmd.linear.y = data.axes[0] * 1.0
self.cmd_vel_pub.publish( cmd )
def main():
rospy.init_node( 'ardrone_teleop_joy' )
teleop = ArdroneTeleopJoy()
try:
rospy.spin()
except KeyboardInterrupt:
print "Shutting down"
if __name__ == '__main__':
main()
Arquivo executável
+74
Ver Arquivo
@@ -0,0 +1,74 @@
#!/usr/bin/env python
import roslib
roslib.load_manifest('falkor_ardrone')
import sys
import rospy
import cv
import cv2
import math
from std_msgs.msg import String
from sensor_msgs.msg import Image
from geometry_msgs.msg import Point
from cv_bridge import CvBridge, CvBridgeError
import numpy as np
import tracker
class ardroneTracker:
def __init__(self, tracker):
self.point_pub = rospy.Publisher("/ardrone_tracker/found_point", Point )
self.bridge = CvBridge()
self.image_sub = rospy.Subscriber("/ardrone/front/image_raw",Image,self.callback)
self.image_pub = rospy.Publisher( "/ardrone_tracker/image", Image )
self.tracker = tracker
def callback(self,data):
try:
cv_image = self.bridge.imgmsg_to_cv(data, "bgr8")
except CvBridgeError, e:
print e
numpy_image = np.asarray( cv_image )
trackData = self.tracker.track( numpy_image )
if trackData:
x,y,z = trackData[0],trackData[1],trackData[2]
point = Point( x,y,z )
self.point_pub.publish( point )
else:
self.point_pub.publish( Point( 0, 0, -1 ) )
try:
vis = self.tracker.get_vis()
image_message = self.bridge.cv_to_imgmsg(cv2.cv.fromarray( vis ), encoding="passthrough")
self.image_pub.publish( image_message )
except CvBridgeError, e:
print e
def main():
rospy.init_node( 'ardrone_tracker' )
# ardroneTracker(tracker.LkTracker() )
# ardroneTracker(tracker.DummyTracker() )
# '/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml'
cascade_file = rospy.get_param( '~cascadefile', 'NULL' )
if cascade_file == 'NULL':
print "Must set cascadefile parameter!"
exit
ardroneTracker( tracker.CascadeTracker( cascade_file ) )
try:
rospy.spin()
except KeyboardInterrupt:
print "Shutting down"
cv.DestroyAllWindows()
if __name__ == '__main__':
# import cProfile
# cProfile.run('main()')
main()
+88
Ver Arquivo
@@ -0,0 +1,88 @@
#!/usr/bin/env python
class Pid2:
def __init__( self, gain_p = 0.0, gain_i = 0.0, gain_d = 0.0,
time_constant = 0.0, limit = -1.0 ):
self.gain_p = gain_p
self.gain_i = gain_i
self.gain_d = gain_d
self.time_constant = time_constant
self.limit = limit
self.input = 0.0
self.dinput = 0.0
self.output = 0.0
self.p = 0.0
self.i = 0.0
self.d = 0.0
def update( self, new_input, x, dx, dt ):
if self.limit > 0.0 and abs( new_input ) > self.limit:
if new_input < 0:
new_input = - self.limit
else:
new_input = self.limit
if dt + self.time_constant > 0.0:
self.dinput = ( new_input - self.input ) / ( dt + self.time_constant )
self.input = ( dt * new_input + self.time_constant * self.input ) / ( dt + self.time_constant )
self.p = self.input - x
self.d = self.dinput - dx
self.i = self.i + dt * self.p
# print self.p,self.d,self.i
self.output = self.gain_p * self.p + self.gain_d * self.d + self.gain_i * self.i
return self.output
def reset( self ):
self.input = self.dinput = 0.0
self.p = self.i = self.d = 0.0
class Pid:
def __init__( self, Kp = 0.0, Ti = 0.0, Td = 0.0, outputLimit = None ):
self.Kp = Kp
self.Ti = Ti
self.Td = Td
self.prev_error = 0.0
self.integral = 0.0
self.outputLimit = outputLimit
self.setPointMin = self.setPointMax = 0.0
def get_output( self, pv, dt ):
if( pv < self.setPointMax and pv > self.setPointMin ):
error = 0
else:
errorFromMax = self.setPointMax - pv
errorFromMin = self.setPointMin - pv
if abs( errorFromMax ) > abs( errorFromMin ):
error = errorFromMin
else:
error = errorFromMax
self.integral += error * dt
if dt != 0:
derivative = ( error - self.prev_error ) / dt
else:
derivative = 0
self.prev_error = error
if self.Ti == 0.0:
TiInv = 0
else:
TiInv = 1/self.Ti
output = self.Kp * ( error + TiInv * self.integral + self.Td * derivative )
if self.outputLimit != None:
limitedOutput = min( max( output, -self.outputLimit ),
self.outputLimit )
return limitedOutput
else:
return output
+449
Ver Arquivo
@@ -0,0 +1,449 @@
#!/usr/bin/env python
"""
Tracker classes must implement track( frame ) which returns a tuple (x,y,area)
if the tracker does not find an object then it will return None
"""
import numpy as np
import math
import cv2
import time
lk_params = dict( winSize = ( 30, 30 ),
maxLevel = 2,
criteria = ( cv2.TERM_CRITERIA_EPS |
cv2.TERM_CRITERIA_COUNT, 10, 0.03 ) )
feature_params = dict( maxCorners = 50,
qualityLevel = 0.3,
minDistance = 10,
blockSize = 10 )
class DummyTracker:
def track( self, frame ):
(y,x,n) = frame.shape
cv2.imshow( 'Dummy', frame )
return( 50, 50, 50 )
class LkTracker:
def __init__(self):
self.track_len = 10
self.detect_interval = 5
self.tracks = []
self.frame_idx = 0
self.frame = None
self.mouseDown = False
self.timers = {}
self.userRect = None
# cv2.namedWindow( 'LKTracker', cv2.cv.CV_WINDOW_NORMAL )
# cv2.cv.SetMouseCallback( 'LKTracker', self.on_mouse, None )
self.vis = None
def on_mouse( self, event, x, y, flags, param ):
if self.frame is None:
return
if event == cv2.cv.CV_EVENT_LBUTTONDOWN:
self.mouseDown = True
self.userRect = np.int32( ( ( x, y ), ( x, y ) ) )
elif event == cv2.cv.CV_EVENT_MOUSEMOVE and self.mouseDown == True:
xmin = min( self.userRect[0,0], self.userRect[1,0], x)
xmax = max( self.userRect[0,0], self.userRect[1,0], x)
ymin = min( self.userRect[0,1], self.userRect[1,1], y)
ymax = max( self.userRect[0,1], self.userRect[1,1], y)
self.userRect = np.int32( ( ( xmin, ymin ), ( xmax, ymax ) ) )
elif event == cv2.cv.CV_EVENT_LBUTTONUP:
self.mouseDown = False
self.pickFeatures()
self.initCamshift()
self.userRect = None
def initCamshift(self):
x0,y0,x1,y1 = (self.userRect[0,0],
self.userRect[0,1],
self.userRect[1,0],
self.userRect[1,1])
hsv_roi = self.hsv[ y0:y1, x0:x1 ]
mask_roi = self.hsv_mask[ y0:y1, x0:x1 ]
hist = cv2.calcHist( [hsv_roi], [0], mask_roi, [16], [0,180] )
cv2.normalize( hist, hist, 0, 255, cv2.NORM_MINMAX )
self.hist = hist.reshape(-1)
self.track_window = ( x0, y0, x1-x0, y1-y0 )
self.showHist()
def getCamShift(self):
prob = cv2.calcBackProject( [self.hsv], [0], self.hist, [0,180], 1 )
prob &= self.hsv_mask
term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )
track_box, self.track_window = cv2.CamShift( prob, self.track_window,
term_crit )
# cv2.imshow( 'Back Projection', prob )
return track_box
def showHist(self):
bin_count = self.hist.shape[0]
bin_w = 24
img = np.zeros((256, bin_count*bin_w, 3), np.uint8)
for i in xrange(bin_count):
h = int(self.hist[i])
cv2.rectangle(img, (i*bin_w+2, 255), ((i+1)*bin_w-2, 255-h), (int(180.0*i/bin_count), 255, 255), -1)
img = cv2.cvtColor(img, cv2.COLOR_HSV2BGR)
# cv2.imshow('hist', img)
def pickFeatures(self):
mask = np.zeros_like( self.frame_gray )
# import pdb; pdb.set_trace()
cv2.rectangle( mask, tuple( self.userRect[0] ), tuple( self.userRect[1] ), 255, -1 )
# cv2.imshow( 'userMask', mask )
start = cv2.getTickCount() / cv2.getTickFrequency()
p = cv2.goodFeaturesToTrack( self.frame_gray, mask = mask, **feature_params )
self.timers['GoodFeatures'] = cv2.getTickCount() / cv2.getTickFrequency() - start
if p is not None:
self.tracks = [ [ (x,y) ] for x, y in np.float32(p).reshape(-1, 2) ]
def equalizeHist(self, frame):
splits = cv2.split( frame )
equalized = map( cv2.equalizeHist, splits )
return cv2.merge( equalized )
def initializeFrame( self, frame ):
self.frame = cv2.pyrDown( frame )
self.hsv = cv2.cvtColor( self.frame, cv2.COLOR_BGR2HSV )
self.hsv = self.equalizeHist( self.hsv )
self.hsv_mask = cv2.inRange( self.hsv, np.array((0.0, 33.0, 33.0)),
np.array((180.0,254.,254.)) )
# dilate
self.hsv_mask = cv2.dilate( self.hsv_mask, None, iterations = 5 )
# self.frame_gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)
hsv_split = cv2.split( self.hsv )
self.frame_gray = hsv_split[0]
# cv2.imshow( 'sat', hsv_split[1] )
# cv2.imshow( 'vol', hsv_split[2] )
cv2.imshow( 'gray', self.frame_gray )
# cv2.imshow( 'hsv_mask', self.hsv_mask )
def filterOutliers( self, deviations ):
pts = np.int32( [ tr[-1] for tr in self.tracks ] )
if pts.size < 10: # 5 pts (10 bc x/y)
return
x_median = np.median( pts[:,0] )
y_median = np.median( pts[:,1] )
distances = ( np.square(pts[:,0] - x_median) +
np.square(pts[:,1] - y_median) )
distance_median = np.median( distances )
self.tracks = [ tr for (i,tr) in enumerate( self.tracks )
if distances[i] < distance_median *
np.square( deviations ) ]
def runOpticalFlow( self ):
if len(self.tracks) > 0:
img0, img1 = self.prev_gray, self.frame_gray
p0 = np.float32([tr[-1] for tr in self.tracks]).reshape(-1, 1, 2 )
start = cv2.getTickCount() / cv2.getTickFrequency()
p1, st, err = cv2.calcOpticalFlowPyrLK( img0, img1, p0, None, **lk_params )
p0r, st, err = cv2.calcOpticalFlowPyrLK( img1, img0, p1, None, **lk_params )
self.timers['LKTrack'] = cv2.getTickCount() / cv2.getTickFrequency() - start
d = abs( p0-p0r ).reshape(-1, 2).max(-1)
good = d < 1
new_tracks = []
for tr, (x, y), good_flag in zip( self.tracks, p1.reshape(-1,2), good ):
if not good_flag:
continue
tr.append((x, y))
if len(tr) > self.track_len:
del tr[0]
new_tracks.append(tr)
self.tracks = new_tracks
def reDetect( self, use_camshift = True, expand_pixels = 1 ):
if self.frame_idx % self.detect_interval == 0 and len(self.tracks) > 0:
if use_camshift:
mask_camshift = np.zeros_like( self.frame_gray )
ellipse_camshift = self.getCamShift()
cv2.ellipse( mask_camshift, ellipse_camshift, 255, -1 )
mask_tracked = np.zeros_like( self.frame_gray )
pts = np.int32( [ [tr[-1]] for tr in self.tracks ] )
if len(pts) > 5:
ellipse_tracked = cv2.fitEllipse( pts )
else:
ellipse_tracked = cv2.minAreaRect( pts )
boundingRect = cv2.boundingRect( pts )
# x0,y0,x1,y1 = ( boundingRect[0] - int(boundingRect[2] * 0.05),
# boundingRect[1] - int(boundingRect[3] * 0.05),
# boundingRect[0] + int(boundingRect[2] * 1.05),
# boundingRect[1] + int(boundingRect[3] * 1.05))
x0,y0,x1,y1 = ( boundingRect[0] - expand_pixels,
boundingRect[1] - expand_pixels,
boundingRect[0] + boundingRect[2] + expand_pixels,
boundingRect[1] + boundingRect[3] + expand_pixels )
if len( pts ) > 2:
cv2.rectangle( mask_tracked, (x0,y0), (x1,y1), 255, -1 )
cv2.ellipse( mask_tracked, ellipse_tracked, 255, -1 )
# cv2.imshow( 'mask_camshift', mask_camshift )
# cv2.imshow( 'mask_tracked', mask_tracked )
if use_camshift:
mask = mask_camshift & mask_tracked
else:
mask = mask_tracked
for x, y in [np.int32(tr[-1]) for tr in self.tracks]:
cv2.circle(mask, (x,y), 5, 0, -1 )
# cv2.imshow( 'mask', mask )
start = cv2.getTickCount() / cv2.getTickFrequency()
p = cv2.goodFeaturesToTrack( self.frame_gray, mask = mask, **feature_params )
self.timers['GoodFeatures'] = cv2.getTickCount() / cv2.getTickFrequency() - start
if p is not None:
for x, y in np.float32(p).reshape(-1, 2):
self.tracks.append([(x,y)])
def drawAndGetTrack( self ):
vis = self.frame.copy()
if len(self.tracks) > 0:
cv2.polylines( vis, [ np.int32(tr) for tr in self.tracks ], False, ( 0, 255, 0 ) )
pts = np.int32( [ [tr[-1]] for tr in self.tracks ] )
for [(x,y)] in pts:
cv2.circle( vis, (x, y), 2, (0, 255, 0), -1 )
if len( pts ) > 2:
boundingRect = cv2.boundingRect( pts )
x0,y0,x1,y1 = ( boundingRect[0], boundingRect[1],
boundingRect[0] + boundingRect[2],
boundingRect[1] + boundingRect[3] )
area = boundingRect[3] * boundingRect[2]
cx,cy = ( boundingRect[0] + boundingRect[2]/2,
boundingRect[1] + boundingRect[3]/2 )
cv2.rectangle( vis, (x0,y0), (x1,y1), (0,255,255), 3, 8, 0 )
cv2.circle( vis, (cx,cy), 5, (0,255,255), -1, 8, 0 )
if self.userRect != None:
cv2.rectangle( vis, tuple( self.userRect[0] ), tuple( self.userRect[1] ), ( 255, 255, 255 ) )
i = 0
total = 0
for ( timer, time ) in self.timers.items():
i += 1
total += time
cv2.putText( vis, '%s: %.1f ms' % ( timer, time * 1e3 ),
( 20, i*20 ), cv2.FONT_HERSHEY_PLAIN, 1.0,
(255, 255, 255) )
cv2.putText( vis, '%s: %.1f ms' % ( timer, time * 1e3 ),
( 20, i*20 ), cv2.FONT_HERSHEY_PLAIN, 1.0,
( 0, 0, 0), thickness = 2 )
i += 1
cv2.putText( vis, 'Total: %.1f ms' % ( total * 1e3 ),
( 20, i*20 ), cv2.FONT_HERSHEY_PLAIN, 1.0,
(255, 255, 255) )
cv2.putText( vis, 'Total: %.1f ms' % ( total * 1e3 ),
( 20, i*20 ), cv2.FONT_HERSHEY_PLAIN, 1.0,
( 0, 0, 0), thickness = 2 )
self.vis = vis.copy()
# cv2.imshow( 'LKTracker', self.vis )
# cv2.waitKey( 1 )
if len( self.tracks ) > 2:
imageSize = self.frame.shape
imageArea = imageSize[0]*imageSize[1]
xRel = cx*100/imageSize[1]
yRel = cy*100/imageSize[0]
areaRel = math.sqrt( float( area ) / float( imageArea ) ) * 100
return xRel,yRel,areaRel,cx,cy
else:
return None
def get_vis( self ):
return self.vis
def track(self, frame):
self.initializeFrame( frame )
self.runOpticalFlow()
self.filterOutliers( 3 )
self.reDetect()
trackData = self.drawAndGetTrack()
self.frame_idx += 1
self.prev_gray = self.frame_gray
return trackData
class CascadeTracker( LkTracker ):
def __init__( self, cascadeFn ):
self.cascade = cv2.CascadeClassifier( cascadeFn )
self.trackData = None
self.cascade_interval = 30
LkTracker.__init__( self )
def initCamshift( self ):
pass
def track( self, frame ):
self.frame = frame # cv2.pyrDown( frame )
self.frame_gray = cv2.cvtColor( self.frame, cv2.COLOR_BGR2GRAY )
self.frame_gray = cv2.equalizeHist( self.frame_gray )
# do optical flow if we have it
self.runOpticalFlow()
self.trackData = self.drawAndGetTrack()
# now look for the object every 5th frame
detectedObject = self.detectObject()
# if we don't have it redetect optical flow
if detectedObject == None:
self.filterOutliers( 4 )
self.reDetect( False, 0 )
# If we do have it, then re-select optical flow features
else:
# import pdb; pdb.set_trace()
self.userRect = [ [ detectedObject[0],
detectedObject[1] ],
[ detectedObject[0] + detectedObject[2],
detectedObject[1] + detectedObject[3] ] ]
self.pickFeatures()
# Add points at the corners
corners = [ [ ( detectedObject[0], detectedObject[1] ) ],
[ ( detectedObject[0] + detectedObject[2],
detectedObject[1] ) ],
[ ( detectedObject[0],
detectedObject[1] + detectedObject[3] ) ],
[ ( detectedObject[0] + detectedObject[2],
detectedObject[1] + detectedObject[3] ) ]
]
self.tracks.extend( corners )
self.userRect = None
self.trackData = self.drawAndGetTrack()
# imageSize = frame.shape
# imageArea = imageSize[0]*imageSize[1]
# area = detectedObject[2] * detectedObject[3]
# cx = detectedObject[0] + detectedObject[2]/2
# cy = detectedObject[1] + detectedObject[3]/2
# xRel = cx*100/imageSize[1]
# yRel = cy*100/imageSize[0]
# areaRel = math.sqrt( float( area ) / float( imageArea ) ) * 100
# trackData = xRel,yRel,areaRel
self.frame_idx += 1
self.prev_gray = self.frame_gray
return self.trackData
def detectObject( self ):
# don't do a cascade every frame
if self.frame_idx % self.cascade_interval != 0:
return None
start = cv2.getTickCount() / cv2.getTickFrequency()
objects = self.cascade.detectMultiScale( self.frame_gray,
scaleFactor=1.3,
minNeighbors=4,
minSize=(15, 15),
flags = cv2.cv.CV_HAAR_SCALE_IMAGE)
self.timers['Cascade'] = cv2.getTickCount() / cv2.getTickFrequency() - start
vis = self.frame_gray.copy()
if len( objects ) > 0:
for i in objects:
cv2.rectangle( vis,
( int(i[0]), int(i[1]) ),
( int(i[0]+i[2]), int(i[1]+i[3]) ),
cv2.cv.CV_RGB(0,255,0), 3, 8, 0)
# cv2.imshow( "objects", vis )
# if we have only one object return that
# or if we have no trackData, return the first object
# if we have trackData and multiple objects, return the object
# closest to the trackData
if len( objects ) > 0:
if len( objects ) == 1 or not self.trackData:
return objects[0]
else:
distances_squared = ( np.square(objects[:,0]+objects[:,2]/2 -
self.trackData[3]) +
np.square(objects[:,1]+objects[:,2]/2 -
self.trackData[4]) )
min_index = np.argmin( distances_squared )
return objects[min_index]
else:
return None
def main():
import sys
try: video_src = sys.argv[1]
except: video_src = 0
tracker = CascadeTracker(
'/home/sameer/ros/falkor_ardrone/cascade/haarcascade_falkorlogopaper.xml' )
cam = cv2.VideoCapture( video_src )
while True:
ret, frame = cam.read()
if ret:
trackData = tracker.track( frame )
if trackData:
print trackData
ch = 0xFF & cv2.waitKey(1)
if ch == 27:
break
if __name__ == '__main__':
main()