Skip to content

Commit

Permalink
Merge pull request #11 from IQTLabs/tracker
Browse files Browse the repository at this point in the history
Adding in Object Tracking
  • Loading branch information
luke-iqt committed Mar 17, 2021
2 parents 2a78a48 + 6c38484 commit 4cab902
Show file tree
Hide file tree
Showing 23 changed files with 1,796 additions and 28 deletions.
124 changes: 107 additions & 17 deletions axis-ptz/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,18 @@
cameraZoom = None
cameraMoveSpeed = None
cameraDelay = None
object_topic = None
flight_topic = None
pan = 0
tilt = 0
actualPan = 0
actualTilt = 0
follow_x = 0
follow_y = 0
actualX = 0
actualY = 0
currentPlane=None
object_timeout=0

# https://stackoverflow.com/questions/45659723/calculate-the-difference-between-two-compass-headings-python

Expand All @@ -58,6 +65,14 @@ def getHeadingDiff(h1, h2):
else:
return absDiff - 360

def setXY(x,y):
global follow_x
global follow_y

follow_x = int(x)
follow_y = int(y)


def setPan(bearing):
global pan
camera_bearing = args.bearing
Expand Down Expand Up @@ -109,6 +124,7 @@ def get_jpeg_request(): # 5.2.4.1
"""
payload = {
'resolution': "1920x1080",
'compression': 5,
'camera': 1,
}
url = 'https://' + args.axis_ip + '/axis-cgi/jpg/image.cgi'
Expand All @@ -132,25 +148,84 @@ def get_jpeg_request(): # 5.2.4.1
text += str(resp.text)
return text

def get_bmp_request(): # 5.2.4.1
"""
The requests specified in the JPEG/MJPG section are supported by those video products
that use JPEG and MJPG encoding.
Args:
resolution: Resolution of the returned image. Check the product’s Release notes.
camera: Selects the source camera or the quad stream.
square_pixel: Enable/disable square pixel correction. Applies only to video encoders.
compression: Adjusts the compression level of the image.
clock: Shows/hides the time stamp. (0 = hide, 1 = show)
date: Shows/hides the date. (0 = hide, 1 = show)
text: Shows/hides the text. (0 = hide, 1 = show)
text_string: The text shown in the image, the string must be URL encoded.
text_color: The color of the text shown in the image. (black, white)
text_background_color: The color of the text background shown in the image.
(black, white, transparent, semitransparent)
rotation: Rotate the image clockwise.
text_position: The position of the string shown in the image. (top, bottom)
overlay_image: Enable/disable overlay image.(0 = disable, 1 = enable)
overlay_position:The x and y coordinates defining the position of the overlay image.
(<int>x<int>)
Returns:
Success ('image save' and save the image in the file folder) or Failure (Error and
description).
"""
payload = {
'resolution': "1920x1080",
'camera': 1,
}
url = 'https://' + args.axis_ip + '/axis-cgi/bitmap/image.bmp'
resp = requests.get(url, auth=HTTPDigestAuth(args.axis_username, args.axis_password),
params=payload)

if resp.status_code == 200:
captureDir = "capture/{}".format(currentPlane["type"])
try:
os.makedirs(captureDir)
except OSError as e:
if e.errno != errno.EEXIST:
raise # This was not a "directory exist" error..
filename = "{}/{}_{}.bmp".format(captureDir, currentPlane["icao24"],datetime.now().strftime('%Y-%m-%d-%H-%M-%S'))

with open(filename, 'wb') as var:
var.write(resp.content)
return str('Image saved')

text = str(resp)
text += str(resp.text)
return text

def moveCamera():
global actualPan
global actualTilt
global actualX
global actualY
global camera


while True:
lockedOn = False
if actualTilt != tilt or actualPan != pan:
logging.info("Moving camera to Tilt: %d & Pan: %d"%(tilt, pan))
actualTilt = tilt
actualPan = pan
lockedOn = True
camera.absolute_move(pan, tilt, cameraZoom, cameraMoveSpeed)
time.sleep(0.3)
get_jpeg_request()


if (object_timeout < time.mktime(time.gmtime())):
if actualTilt != tilt or actualPan != pan:
logging.info("Moving camera to Tilt: %d & Pan: %d"%(tilt, pan))
actualTilt = tilt
actualPan = pan
lockedOn = True
camera.absolute_move(pan, tilt, cameraZoom, cameraMoveSpeed)
time.sleep(cameraDelay)
get_jpeg_request()
#get_bmp_request()
else:
if actualX != follow_x or actualY != follow_y:
actualX = follow_x
actualY = follow_y
#camera.center_move(actualX, actualY, cameraMoveSpeed)
pan_tilt = str(actualX) + "," + str(actualY)
camera._camera_command({'center': pan_tilt, 'speed': cameraMoveSpeed, 'imagewidth': '1280', 'imageheight': '720'})
#time.sleep(cameraDelay)
#if lockedOn == True:
# filename = "capture/{}_{}".format(datetime.now().strftime('%Y-%m-%d-%H-%M-%S'), currentPlane)
# camera.capture("{}.jpeg".format(filename))
Expand All @@ -163,6 +238,8 @@ def moveCamera():
#############################################
def on_message(client, userdata, message):
global currentPlane
global object_timeout

command = str(message.payload.decode("utf-8"))
#rint(command)
try:
Expand All @@ -179,10 +256,17 @@ def on_message(client, userdata, message):
except:
print("Caught it!")

logging.info("{}\tBearing: {} \tElevation: {}".format(update["icao24"],update["bearing"],update["elevation"]))
bearingGood = setPan(update["bearing"])
setTilt(update["elevation"])
currentPlane = update
if message.topic == object_topic:
logging.info("Got Object Topic")
setXY(update["x"], update["y"])
object_timeout = time.mktime(time.gmtime()) + 5
elif message.topic == flight_topic:
logging.info("{}\tBearing: {} \tElevation: {}".format(update["icao24"],update["bearing"],update["elevation"]))
bearingGood = setPan(update["bearing"])
setTilt(update["elevation"])
currentPlane = update
else:
logging.info("Message: {} Object: {} Flight: {}".format(message.topic, object_topic, flight_topic))

def main():
global args
Expand All @@ -194,12 +278,15 @@ def main():
global cameraMoveSpeed
global cameraZoom
global cameraConfig
global flight_topic
global object_topic

parser = argparse.ArgumentParser(description='An MQTT based camera controller')

parser.add_argument('-b', '--bearing', help="What bearing is the font of the PI pointed at (0-360)", default=0)
parser.add_argument('-m', '--mqtt-host', help="MQTT broker hostname", default='127.0.0.1')
parser.add_argument('-t', '--mqtt-topic', help="MQTT topic to subscribe to", default="SkyScan")
parser.add_argument('-t', '--mqtt-flight-topic', help="MQTT topic to subscribe to", default="skyscan/flight/json")
parser.add_argument( '--mqtt-object-topic', help="MQTT topic to subscribe to", default="skyscan/object/json")
parser.add_argument('-u', '--axis-username', help="Username for the Axis camera", required=True)
parser.add_argument('-p', '--axis-password', help="Password for the Axis camera", required=True)
parser.add_argument('-a', '--axis-ip', help="IP address for the Axis camera", required=True)
Expand Down Expand Up @@ -237,14 +324,17 @@ def main():
threading.Thread(target = moveCamera, daemon = True).start()
# Sleep for a bit so we're not hammering the HAT with updates
time.sleep(0.005)
print("connecting to MQTT broker at "+ args.mqtt_host+", channel '"+args.mqtt_topic+"'")
flight_topic=args.mqtt_flight_topic
object_topic = args.mqtt_object_topic
print("connecting to MQTT broker at "+ args.mqtt_host+", channel '"+flight_topic+"'")
client = mqtt.Client("skyscan-axis-ptz-camera-" + ID) #create new instance

client.on_message=on_message #attach function to callback

client.connect(args.mqtt_host) #connect to broker
client.loop_start() #start the loop
client.subscribe(args.mqtt_topic+"/#")
client.subscribe(flight_topic+"/#")
client.subscribe(object_topic+"/#")
client.publish("skyscan/registration", "skyscan-axis-ptz-camera-"+ID+" Registration", 0, False)

#############################################
Expand Down
6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:

tracker:
build: ./tracker
entrypoint: "./flighttracker.py -m mqtt -l ${LAT} -L ${LONG} -a ${ALT} -P skyscan/planes/json -T skyscan/tracking/json -M ${MIN_ELEVATION} -c ${CAMERA_LEAD}"
entrypoint: "./flighttracker.py -m mqtt -l ${LAT} -L ${LONG} -a ${ALT} -P skyscan/planes/json -T skyscan/flight/json -M ${MIN_ELEVATION} -c ${CAMERA_LEAD}"
depends_on:
- mqtt
restart: unless-stopped
Expand All @@ -21,7 +21,7 @@ services:

pan-tilt-pi:
build: ./pan-tilt-pi
entrypoint: "./camera.py -m mqtt -t skyscan/tracking/json"
entrypoint: "./camera.py -m mqtt -t skyscan/flight/json"
volumes:
- /opt/vc:/opt/vc
- ./capture:/app/capture
Expand All @@ -36,7 +36,7 @@ services:

axis-ptz:
build: ./axis-ptz
entrypoint: "./camera.py -m mqtt -t skyscan/tracking/json -u ${AXIS_USERNAME} -p ${AXIS_PASSWORD} -a ${AXIS_IP} -z ${CAMERA_ZOOM} -s ${CAMERA_MOVE_SPEED} -d ${CAMERA_DELAY}"
entrypoint: "./camera.py -m mqtt -t skyscan/flight/json -u ${AXIS_USERNAME} -p ${AXIS_PASSWORD} -a ${AXIS_IP} -z ${CAMERA_ZOOM} -s ${CAMERA_MOVE_SPEED} -d ${CAMERA_DELAY}"
volumes:
- ./capture:/app/capture
depends_on:
Expand Down
2 changes: 2 additions & 0 deletions object-tracker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
all_models/
**__pycache__
28 changes: 28 additions & 0 deletions object-tracker/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# How to Contribute

We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.

## Contributor License Agreement

Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution;
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.

You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.

## Code reviews

All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.

## Community Guidelines

This project follows [Google's Open Source Community
Guidelines](https://opensource.google.com/conduct/).
Loading

0 comments on commit 4cab902

Please sign in to comment.