initial commit, moving files over from ardrone_autonomy fork
Esse commit está contido em:
@@ -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/
|
||||||
@@ -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})
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
include $(shell rospack find mk)/cmake.mk
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
\mainpage
|
||||||
|
\htmlinclude manifest.html
|
||||||
|
|
||||||
|
\b falkor_ardrone
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Provide an overview of your package.
|
||||||
|
-->
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||||
@@ -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
|
||||||
@@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Referência em uma Nova Issue
Bloquear um usuário