#
# Copyright (c) Madrid 2008
# BIT, ETSI Telecomunicacion, UPM
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#
#
import wx
from lxml import etree
from string import atof
import math
GlobalColors = ["white", "red", "blue", "green", "yellow", "cyan" ]
class Section:
def init_from_node(self, node):
if node.tag != "section":
raise ValueError("expected 'section' got '%s'" % (node.tag))
self.points = []
self.color = node.get("color")
for n in node:
if (n.tag == 'point'):
x = atof(n.get("x"))
y = atof(n.get("y"))
self.points.append( (x,y) )
def __init__(self, color=None, points=None, node=None):
self.thickness = 1
if node is not None:
self.init_from_node(node)
else:
self.init_from_color_points(color,points)
def init_from_color_points(self, color, points):
if color is not None:
self.color = color
else:
self.color = GlobalColors[0]
if points:
self.points = points
else:
self.points = []
def Draw(self, dc):
pen = wx.Pen(self.color, self.thickness, wx.SOLID)
brush = wx.Brush(self.color, wx.CROSS_HATCH)
dc.SetPen(pen)
dc.SetBrush(brush)
dc.DrawPolygon(self.points)
def Invert(self):
self.points.reverse()
def Save(self, frame):
section = etree.Element("section", color=self.color)
frame.append(section)
for p in self.points:
cx = "%f" % (p[0])
cy = "%f" % (p[1])
section.append(etree.Element("point", x=cx, y=cy))
def SetPoints(self, points, zoom):
self.points = []
for p in points:
self.points.append( ( p[0] / zoom, p[1] / zoom) )
def GetPoints(self, zoom):
points = []
for p in self.points:
points.append( ( p[0] * zoom, p[1] * zoom) )
return points
def __eq__(self, other):
if (self.color != other.color):
return False
if len(self.points) != len(other.points):
return False
return self.points == other.points
class Star:
def __init__(self, points=None, value=None, node=None):
if points is not None:
self.__init_from_points(points)
elif value is not None:
self.__init_from_values(value)
elif node is not None:
self.__init_from_node(node)
else:
raise ValueError("No points given")
def __init_from_node(self, node):
if node.tag != "star":
raise ValueError("expected 'star' got '%s'" % (node.tag))
self.rays = []
self.center = (atof(node.get("x")), atof(node.get("y")))
rstring = node.get("r")
if rstring is not None:
self.radius = atof(rstring)
else:
self.radius = 1
for n in node:
if (n.tag == 'point'):
sx = atof(n.get("x"))
sy = atof(n.get("y"))
self.rays.append( (sx,sy) )
def __init_from_values(self, values):
self.center = values[0]
self.rays = values[1]
self.radius = values[2]
def __len(self, a, b):
x = a[0] - b[0]
y = a[1] - b[1]
return math.sqrt(x * x + y * y)
def __calc_ray(self, point):
x = point[0] - self.center[0]
y = point[1] - self.center[1]
norm = math.sqrt(x * x + y * y)
x = x / norm
y = y / norm
return (x,y)
def __calc_bc(self, a,b,c):
return a * a *( b * b + c * c - a *a )
def __calc_circumcenter(self, p):
if len(p) != 3:
raise ValueError("Can only init from 3 points")
a = self.__len(p[1], p[2])
b = self.__len(p[2], p[0])
c = self.__len(p[0], p[1])
x = []
x.append(self.__calc_bc(a, b, c))
x.append(self.__calc_bc(b, c, a))
x.append(self.__calc_bc(c, a, b))
sum = x[0] + x[1] + x[2]
for i in range(len(x)):
x[i] = x[i] / sum
yy = 0.0
yx = 0.0
for i in range(len(x)):
yx = yx + x[i] * p[i][0]
yy = yy + x[i] * p[i][1]
return (yx, yy)
def __init_from_points(self, p):
self.center = self.__calc_circumcenter(p)
self.radius = self.__len(self.center, p[0])
print self.radius
self.rays = []
r = self.__calc_ray(p[0])
self.rays.append( r )
c = -0.5
s = math.sqrt(0.75)
ray = ( c * r[0] - s * r[1], c * r[1] + s * r[0])
if ray[0] > 0:
self.rays.append( ray )
else:
self.rays.append( (-ray[0], -ray[1] ))
ray = ( c * r[0] + s * r[1], c * r[1] - s * r[0])
if ray[0] > 0:
self.rays.append( ray )
else:
self.rays.append( (-ray[0], -ray[1] ))
def GetCenter(self):
return self.center
def GetRays(self):
return self.rays
def GetRadius(self):
return self.radius
def GetRayLines(self, size):
lines = []
for r in self.rays:
if abs(r[0]) > abs(r[1]):
a = r[1] / r[0]
start = (0, self.center[1] - a * self.center[0])
end = (size[0], a * (size[0] - self.center[0]) + self.center[1])
lines.append((start, end))
else:
a = r[0] / r[1]
start = (-a * self.center[1] + self.center[0], 0)
end = (a * (size[1] - self.center[1]) + self.center[0], size[1])
lines.append((start, end))
return lines
def Save(self, root):
cx = "%f" % (self.center[0])
cy = "%f" % (self.center[1])
cr = "%f" % (self.radius)
star = etree.Element("star", x=cx, y=cy, r = cr )
for r in self.rays:
x = "%f" % (r[0])
y = "%f" % (r[1])
star.append(etree.Element("point", x=x, y=y ))
root.append(star)
def __eq__(self, other):
if self.center != other.center:
return False
if self.radius != other.radius:
return False
return self.rays == other.rays
class ImageSegmentation:
def __init__(self, image=None, sections=None, node=None):
self.star = None
self.Sections = []
if image is not None:
self.__init_from_image_and_sections(image, sections)
elif node is not None:
self.__init_from_node(node)
else:
raise ValueError("No image file or node given")
self.image = wx.Image(self.image_file, type=wx.BITMAP_TYPE_ANY, index = -1)
def __init_from_image_and_sections(self, image, sections):
self.image_file = image
if sections is not None:
self.Sections = sections
def __init_from_node(self, node):
if node.tag != "frame":
raise ValueError("Expected 'frame' got '%s' instead" % node.tag)
self.image_file = node.get("image")
for n in node:
if n.tag == "section":
self.Sections.append(Section(node=n))
if n.tag == "star":
self.star = Star(node=n)
def GetImage(self):
return self.image
def Save(self, root):
frame = etree.Element("frame", image=self.image_file)
if self.star is not None:
self.star.Save(frame)
if len(self.Sections) > 0:
for sections in self.Sections:
sections.Save( frame )
else:
frame.append(etree.Element("placeholder"))
root.append(frame)
def GetStar(self, zoom):
if not self.star:
return None
new_c = (self.star.center[0] * zoom, self.star.center[1] * zoom)
return Star( value=(new_c, self.star.rays, self.star.radius * zoom))
def SetStar(self, star, zoom):
new_c = (star.center[0] / zoom, star.center[1] / zoom)
if self.star is not None:
self.star.center = new_c
self.star.radius = star.radius/ zoom
else:
self.star = Star( value=(new_c, star.rays, star.radius/ zoom))
def SetSections(self, sections, zoom):
self.Sections = []
for s in sections:
self.Sections.append(Section(s.color, s.GetPoints(1.0/zoom)))
def GetSections(self, zoom):
sections = []
for s in self.Sections:
sections.append(Section(s.color, s.GetPoints(zoom)))
return sections
def __eq__(self, other):
if len(self.Sections) != len(other.Sections):
return False
for s in self.Sections:
if not (s in other.Sections):
return False
return self.image_file == other.image_file
class WorkSet:
def __init__(self, images=None, node=None):
if node is not None:
self.load(node)
else:
self.init(images)
def load(self, workset):
self.frames = []
if workset.tag != "workset":
raise ValueError("Expected 'workset' got '%s'" % workset.tag)
for f in workset:
self.frames.append( ImageSegmentation( node=f ) )
def init(self, images):
self.frames = []
if not images:
raise ValueError("No images given")
for i in images:
self.frames.append(ImageSegmentation(image=i))
def GetFrameNumber(self):
return len(self.frames)
def GetFrame(self, i):
if i > self.GetFrameNumber():
raise ValueError("Requested frame out of range")
return self.frames[i]
def Save(self):
root = etree.Element("workset")
for f in self.frames:
f.Save(root)
return etree.tostring(root, pretty_print=True)