Here’s a an app I wrote a while ago that I thought I’d share.
The original idea was a mobile application for tradesmen to work with. The main (and currently only) feature allows you to use the phone’s camera to work out the angle on something.
There’s no fancy computer vision unfortunately, you take a photo and are presented with the image and a cursor. move the cursor around the image until you have clicked on one side of the “angle”, then the pivot, then the other side. Using matrix operations it will then tell you the angle of your selection.
I wrote this to run on the Nokia 6630, but it should be easily portable to any other S60 phone. Check out the video of the app in action:
And here’s the code:
#Title: TradesMan
#Author: Mike Terzza
#Summary: An application to measure angles from images taken by a phone's camera
#Version: 1.3.2
#Date: 26/01/08
#
#Import all nessecary modules
import e32, camera, appuifw, key_codes, graphics, math
#
#Define variables for image use
#
#The current mode of the program
mode = None
#Cursor coordinates
x = 80
y = 60
#Variables for angle coordinates
dotax = 1
dotay = 1
dotbx = 1
dotby = 1
dotcx = 1
dotcy = 1
#The main image variable
imgFile = None
def handle_redraw(rect):
"""Callback function to redraw the screen if necessary"""
if imgFile:
canvas.blit(imgFile, target = (0, 0, w, 0.75 * w), scale = 1)
def handle_event(event):
"""Handles Keypress events and calls the necessary functions"""
ev = event['keycode']
if mode != None:
if event['type'] == appuifw.EEventKeyDown:
pass
elif ev == key_codes.EKeySelect:
select()
if ev == key_codes.EKeyUpArrow:
up()
elif ev == key_codes.EKeyRightArrow:
right()
elif ev == key_codes.EKeyDownArrow:
down()
elif ev == key_codes.EKeyLeftArrow:
left()
else:
pass
def up():
"""Code for when the 'up' button is pressed"""
global y
if imgFile != None:
canvas.blit(imgFile, target = (0, 0, w, 0.75 * w), scale = 1)
y -= 5
drawDot()
else:
pass
def down():
"""Code for when the 'down' button is pressed"""
global y
if imgFile != None:
canvas.blit(imgFile, target = (0, 0, w, 0.75 * w), scale = 1)
y += 5
drawDot()
else:
pass
def left():
"""Code for when the 'left' button is pressed"""
global x
if imgFile != None:
canvas.blit(imgFile, target = (0, 0, w, 0.75 * w), scale = 1)
x -= 5
drawDot()
else:
pass
def right():
"""Code for when the 'right' button is pressed"""
global x
if imgFile != None:
canvas.blit(imgFile, target = (0, 0, w, 0.75 * w), scale = 1)
x += 5
drawDot()
else:
pass
def select():
"""Code for when the 'select' button is pressed"""
global dotax, dotay, dotbx, dotby, dotcx, dotcy, mode, imgFile
if mode == 0:
shoot()
dotStart()
elif mode == 1:
dotax = x
dotay = y
mode = 2
elif mode == 2:
dotbx = x
dotby = y
mode = 3
imgFile.line((dotax, dotay, dotbx, dotby)\
, outline = (0, 255, 0), width = 2)
elif mode == 3:
dotcx = x
dotcy = y
imgFile.line((dotax, dotay, dotbx, dotby), outline = (0, 255, 0)\
, width = 2)
imgFile.line((dotbx, dotby, dotcx, dotcy), outline = (0, 255, 0)\
, width = 2)
appuifw.query(u'The angle is: %.0f Degrees' % angleCalc(), "query")
mode = 4
loadImg()
elif mode == 4:
quit()
def angleCalc():
"""Takes the co-ordinates from the points and returns the angle"""
ax = dotax - dotbx
ay = dotby - dotay
bx = dotcx - dotbx
by = dotby - dotcy
aLen = math.sqrt((ax**2 + ay**2))
bLen = math.sqrt((bx**2 + by**2))
dotProd = (ax * bx + ay * by)
angle = degrees(math.acos((dotProd / (aLen * bLen))))
return angle
def degrees(angle):
"""Converts radians to Degrees"""
return (180 * angle) / math.pi
def viewfinder(img):
"""CallBack Function for camera.start_finder() that takes the stream of
images and displays them on the canvas """
canvas.blit(img, target = (0, 0, w, 0.75 * w), scale = 1)
def shoot():
"""Take photo and saves it to disk, then calls the loadImg() function to
display it to the canvas"""
global imgFile, mode
mode = 1
photo = camera.take_photo(size = (160, 120))
photo.save('e:\\Images\\photo.jpg')
loadImg()
def startFinder():
"""Starts camera viewfinder"""
camera.start_finder(viewfinder, size = (160, 120))
def loadImg():
"""Takes saved image file and blits it to the screen and
if necessary, adds lines of the angle"""
global imgFile
imgFile = graphics.Image.open('e:\\Images\\photo.jpg')
camera.stop_finder()
canvas.blit(imgFile, target = (0, 0, w, 0.75 * w), scale = 1)
if mode > 2:
imgFile.line((dotax, dotay, dotbx, dotby), outline = (0, 0, 255)\
, width = 2)
if mode > 3:
imgFile.line((dotbx, dotby, dotcx, dotcy), outline = (0, 0, 255)\
, width = 2)
def drawDot():
"""Draws the dot (cursor) on screen and when necessary, adds the
interactive angle lines to the screen"""
loadImg()
imgFile.point((x, y), outline = (255, 0, 0), width = 5)
if mode == 2:
imgFile.line((dotax, dotay, x, y), outline = (0, 255, 0), width = 2)
if mode == 3:
imgFile.line((dotbx, dotby, x, y), outline = (0, 255, 0), width = 2)
def dotStart():
"""Stops the camera and viewfinder and starts the dot drawing"""
camera.stop_finder()
drawDot()
def splashScreen():
"""Introductory Splash Screen, welcoming you to the application"""
imgFile = graphics.Image.new((w, h))
imgFile.clear((61, 89, 171))
imgFile.ellipse((23, 37, 153, 107), outline = (0, 0, 255)\
, fill = (0, 0, 128), width = 5)
imgFile.text((62, 75), u'TradesMan', fill = (202, 255, 255))
imgFile.text((55, 140), u'By Mike Terzza', fill = (202, 255, 255))
canvas.blit(imgFile, target = (0, 0, w, 0.75 * w), scale = 1)
e32.ao_sleep(2)
def quit():
"""Quits the application"""
app_lock.signal()
#######################
#
#Set user interface options
#
appuifw.app.screen = "normal"
canvas = appuifw.Canvas(redraw_callback = handle_redraw\
, event_callback = handle_event)
appuifw.app.body = canvas
appuifw.app.title = u"TradesMan"
appuifw.app.exit_key_handler = quit
#Find out canvas size
w, h = canvas.size
#
#Show SplashScreen then start Camera Viewfinder
#
splashScreen()
mode = 0
startFinder()
#
#App_lock - App waits for commands and doesn't just exit sequentially
#
app_lock = e32.Ao_lock()
app_lock.wait()
I aim to add more features and compile it to a sis / sisx file eventually, but for now I thought I’d just upload it as an example of a working S60 script for you to play with.
As requested, Download the source here:
Make a download link, so somebody does not lost how to get that on the phone ;)
Very userful
Cheers
Alba/Taavit
Dear friend,
Use Nokia’s Computer Vision technology for Python, it can help you make a code that will give the measure directly be moving the camera on the angle diagram.
Download Link ‘Nokia’s Computer Vision technology for Python’:
http://research.nokia.com/files/PyNcvLib-1.0_0.zip
This makes the phone recognize and process the inputs from camera.
So no need to mark the lines manually by pressing the keys.
Search more on Google or goto http://research.nokia.com/ to know more!!!
Great work!!!
Raavi
…Using same mobile & same language to code different…