content: '''
  SimpleCV Detection Library
  
  This library includes classes for finding things in images
  
  FYI -
  All angles shalt be described in degrees with zero pointing east in the
  plane of the image with all positive rotations going counter-clockwise.
  Therefore a rotation from the x-axis to to the y-axis is positive and follows
  the right hand rule.
  '''
  
  #load required libraries
  from SimpleCV.base import *
  from SimpleCV.ImageClass import *
  from SimpleCV.Color import *
  from SimpleCV.Features.Features import Feature, FeatureSet
  
  class Corner(Feature):
      """
      **SUMMARY**
  
      The Corner feature is a point returned by the FindCorners function
      Corners are used in machine vision as a very computationally efficient way
      to find unique features in an image.  These corners can be used in
      conjunction with many other algorithms.
  
      **SEE ALSO**
  
      :py:meth:`findCorners`
      """
      def __init__(self, i, at_x, at_y):
  
          points = [(at_x-1,at_y-1),(at_x-1,at_y+1),(at_x+1,at_y+1),(at_x+1,at_y-1)]
          super(Corner, self).__init__(i, at_x, at_y,points)
          #can we look at the eigenbuffer and find direction?
  
      def draw(self, color = (255, 0, 0),width=1):
          """
          **SUMMARY**
  
          Draw a small circle around the corner.  Color tuple is single parameter, default is Red.
  
          **PARAMETERS**
  
          * *color* - An RGB color triplet.
          * *width* - if width is less than zero we draw the feature filled in, otherwise we draw the
            contour using the specified width.
  
  
          **RETURNS**
  
          Nothing - this is an inplace operation that modifies the source images drawing layer.
  
          """
          self.image.drawCircle((self.x, self.y), 4, color,width)
  
  ######################################################################
  class Line(Feature):
      """
      **SUMMARY**
  
      The Line class is returned by the findLines function, but can also be initialized with any two points.
  
      >>> l = Line(Image, (point1, point2))
  
      Where point1 and point2 are (x,y) coordinate tuples.
  
      >>> l.points
  
      Returns a tuple of the two points
  
  
      """
      #TODO - A nice feature would be to calculate the endpoints of the line.
  
      def __init__(self, i, line):
          self.image = i
          self.vector = None
          self.yIntercept = None
          self.end_points = copy(line)
          #print self.end_points[1][1], self.end_points[0][1], self.end_points[1][0], self.end_points[0][0]
          if self.end_points[1][0] - self.end_points[0][0] == 0:
              self.slope = float("inf")
          else:
              self.slope = float(self.end_points[1][1] - self.end_points[0][1])/float(self.end_points[1][0] - self.end_points[0][0])
          #coordinate of the line object is the midpoint
          at_x = (line[0][0] + line[1][0]) / 2
          at_y = (line[0][1] + line[1][1]) / 2
          xmin = int(np.min([line[0][0],line[1][0]]))
          xmax = int(np.max([line[0][0],line[1][0]]))
          ymax = int(np.min([line[0][1],line[1][1]]))
          ymin = int(np.max([line[0][1],line[1][1]]))
          points = [(xmin,ymin),(xmin,ymax),(xmax,ymax),(xmax,ymin)]
          super(Line, self).__init__(i, at_x, at_y,points)
  
      def draw(self, color = (0, 0, 255),width=1):
          """
          Draw the line, default color is blue
  
          **SUMMARY**
  
          Draw a small circle around the corner.  Color tuple is single parameter, default is Red.
  
          **PARAMETERS**
  
          * *color* - An RGB color triplet.
          * *width* - Draw the line using the specified width.
  
          **RETURNS**
  
          Nothing - this is an inplace operation that modifies the source images drawing layer.
  
  
          """
          self.image.drawLine(self.end_points[0], self.end_points[1], color,width)
  
      def length(self):
          """
  
          **SUMMARY**
  
          This method returns the length of the line.
  
          **RETURNS**
  
          A floating point length value.
  
          **EXAMPLE**
  
          >>> img = Image("OWS.jpg")
          >>> lines = img.findLines
          >>> for l in lines:
          >>>    if l.length() > 100:
          >>>       print "OH MY! - WHAT A BIG LINE YOU HAVE!"
          >>>       print "---I bet you say that to all the lines."
  
          """
          return float(spsd.euclidean(self.end_points[0], self.end_points[1]))
  
      def crop(self):
          """
          **SUMMARY**
  
          This function crops the source image to the location of the feature and returns
          a new SimpleCV image.
  
          **RETURNS**
  
          A SimpleCV image that is cropped to the feature position and size.
  
          **EXAMPLE**
  
          >>> img = Image("../sampleimages/EdgeTest2.png")
          >>> l = img.findLines()
          >>> myLine = l[0].crop()
  
          """
          tl = self.topLeftCorner()
          return self.image.crop(tl[0],tl[1],self.width(),self.height())
  
      def meanColor(self):
          """
          **SUMMARY**
  
          Returns the mean color of pixels under the line.  Note that when the line falls "between" pixels, each pixels color contributes to the weighted average.
  
  
          **RETURNS**
  
          Returns an RGB triplet corresponding to the mean color of the feature.
  
          **EXAMPLE**
  
          >>> img = Image("lenna")
          >>> l = img.findLines()
          >>> c = l[0].meanColor()
  
          """
          (pt1, pt2) = self.end_points
          #we're going to walk the line, and take the mean color from all the px
          #points -- there's probably a much more optimal way to do this
          (maxx,minx,maxy,miny) = self.extents()
  
          d_x = maxx - minx
          d_y = maxy - miny
          #orient the line so it is going in the positive direction
  
          #if it's a straight one, we can just get mean color on the slice
          if (d_x == 0.0):
              return self.image[pt1[0]:pt1[0] + 1, miny:maxy].meanColor()
          if (d_y == 0.0):
              return self.image[minx:maxx, pt1[1]:pt1[1] + 1].meanColor()
  
          error = 0.0
          d_err = d_y / d_x  #this is how much our "error" will increase in every step
          px = []
          weights = []
          if (d_err < 1):
              y = miny
              #iterate over X
              for x in range(minx, maxx):
                  #this is the pixel we would draw on, check the color at that px
                  #weight is reduced from 1.0 by the abs amount of error
                  px.append(self.image[x, y])
                  weights.append(1.0 - abs(error))
  
                  #if we have error in either direction, we're going to use the px
                  #above or below
                  if (error > 0): #
                      px.append(self.image[x, y+1])
                      weights.append(error)
  
                  if (error < 0):
                      px.append(self.image[x, y-1])
                      weights.append(abs(error))
  
                  error = error + d_err
                  if (error >= 0.5):
                      y = y + 1
                      error = error - 1.0
          else:
              #this is a "steep" line, so we iterate over X
              #copy and paste.  Ugh, sorry.
              x = minx
              for y in range(miny, maxy):
                  #this is the pixel we would draw on, check the color at that px
                  #weight is reduced from 1.0 by the abs amount of error
                  px.append(self.image[x, y])
                  weights.append(1.0 - abs(error))
  
                  #if we have error in either direction, we're going to use the px
                  #above or below
                  if (error > 0): #
                      px.append(self.image[x + 1, y])
                      weights.append(error)
  
                  if (error < 0):
                      px.append(self.image[x - 1, y])
                      weights.append(abs(error))
  
                  error = error + (1.0 / d_err) #we use the reciprocal of error
                  if (error >= 0.5):
                      x = x + 1
                      error = error - 1.0
  
          #once we have iterated over every pixel in the line, we avg the weights
          clr_arr = np.array(px)
          weight_arr = np.array(weights)
  
          weighted_clrs = np.transpose(np.transpose(clr_arr) * weight_arr)
          #multiply each color tuple by its weight
  
          temp = sum(weighted_clrs) / sum(weight_arr)  #return the weighted avg
          return (float(temp[0]),float(temp[1]),float(temp[2]))
  
      def findIntersection(self, line):
          """
          **SUMMARY**
  
          Returns the interesction point of two lines.
  
          **RETURNS**
  
          A point tuple.
  
          **EXAMPLE**
  
          >>> img = Image("lenna")
          >>> l = img.findLines()
          >>> c = l[0].findIntersection[1]
  
  
          TODO: THIS NEEDS TO RETURN A TUPLE OF FLOATS
          """
          if self.slope == float("inf"):
              x = self.end_points[0][0]
              y = line.slope*(x-line.end_points[1][0])+line.end_points[1][1]
              return (x, y)
  
          if line.slope == float("inf"):
              x = line.end_points[0][0]
              y = self.slope*(x-self.end_points[1][0])+self.end_points[1][1]
              return (x, y)
  
          m1 = self.slope
          x12, y12 = self.end_points[1]
          m2 = line.slope
          x22, y22 = line.end_points[1]
  
          x = (m1*x12 - m2*x22 + y22 - y12)/float(m1-m2)
          y = (m1*m2*(x12-x22) - m2*y12 + m1*y22)/float(m1-m2)
  
          return (x, y)
  
      def isParallel(self, line):
          """
          **SUMMARY**
  
          Checks whether two lines are parallel or not.
  
          **RETURNS**
  
          Bool. True or False
  
          **EXAMPLE**
  
          >>> img = Image("lenna")
          >>> l = img.findLines()
          >>> c = l[0].isParallel(l[1])
  
          """
          if self.slope == line.slope:
              return True
          return False
  
      def isPerpendicular(self, line):
          """
          **SUMMARY**
  
          Checks whether two lines are perpendicular or not.
  
          **RETURNS**
  
          Bool. True or False
  
          **EXAMPLE**
  
          >>> img = Image("lenna")
          >>> l = img.findLines()
          >>> c = l[0].isPerpendicular(l[1])
  
          """
          if self.slope == float("inf"):
              if line.slope == 0:
                  return True
              return False
  
          if line.slope == float("inf"):
              if self.slope == 0:
                  return True
              return False
  
          if self.slope*line.slope == -1:
              return True
          return False
  
      def imgIntersections(self, img):
          """
          **SUMMARY**
  
          Returns a set of pixels where the line intersects with the binary image.
  
          **RETURNS**
  
          list of points.
  
          **EXAMPLE**
  
          >>> img = Image("lenna")
          >>> l = img.findLines()
          >>> c = l[0].imgIntersections(img.binarize())
  
          """
          pixels = []
          if self.slope == float("inf"):
              for y in range(self.end_points[0][1], self.end_points[1][1]+1):
                  pixels.append((self.end_points[0][0], y))
          else:
              for x in range(self.end_points[0][0], self.end_points[1][0]+1):
                  pixels.append((x, int(self.end_points[1][1] + self.slope*(x-self.end_points[1][0]))))
              for y in range(self.end_points[0][1], self.end_points[1][1]+1):
                  pixels.append((int(((y-self.end_points[1][1])/self.slope)+self.end_points[1][0]), y))
          pixels = list(set(pixels))
          matched_pixels=[]
          for pixel in pixels:
              if img[pixel[0], pixel[1]] == (255.0, 255.0, 255.0):
                  matched_pixels.append(pixel)
          matched_pixels.sort()
  
          return matched_pixels
  
      def angle(self):
          """
          **SUMMARY**
  
          This is the angle of the line, from the leftmost point to the rightmost point
          Returns angle (theta) in radians, with 0 = horizontal, -pi/2 = vertical positive slope, pi/2 = vertical negative slope
  
          **RETURNS**
  
          An angle value in degrees.
  
          **EXAMPLE**
  
          >>> img = Image("OWS.jpg")
          >>> ls = img.findLines
          >>> for l in ls:
          >>>    if l.angle() == 0:
          >>>       print "I AM HORIZONTAL."
  
  
          """
          #first find the leftmost point
          a = 0
          b = 1
          if (self.end_points[a][0] > self.end_points[b][0]):
              b = 0
              a = 1
  
          d_x = self.end_points[b][0] - self.end_points[a][0]
          d_y = self.end_points[b][1] - self.end_points[a][1]
          #our internal standard is degrees
          return float(360.00 * (atan2(d_y, d_x)/(2 * np.pi))) #formerly 0 was west
  
      def cropToImageEdges(self):
          """
          **SUMMARY**
          
          Returns the line with endpoints on edges of image. If some endpoints lies inside image 
          then those points remain the same without extension to the edges.
  
          **RETURNS**
  
          Returns a :py:class:`Line` object. If line does not cross the image's edges or cross at one point returns None.
  
          **EXAMPLE**
  
          >>> img = Image("lenna")
          >>> l = Line(img, ((-100, -50), (1000, 25))
          >>> cr_l = l.cropToImageEdges()
  
          """
          pt1, pt2 = self.end_points
          pt1, pt2 = min(pt1, pt2), max(pt1, pt2)
          x1, y1 = pt1
          x2, y2 = pt2
          w, h = self.image.width-1, self.image.height-1
          slope = self.slope
                 
          ep = []
          if slope == float('inf'):
              if 0 <= x1 <= w and 0 <= x2 <= w:
                  ep.append((x1, 0))
                  ep.append((x2, h))
          elif slope == 0:
              if 0 <= y1 <= w and 0 <= y2 <= w:
                  ep.append((0, y1))
                  ep.append((w, y2))
          else:
              x = (slope*x1 - y1)/slope   # top edge y = 0
              if 0 <= x <= w:
                  ep.append((int(round(x)), 0))
  
              x = (slope*x1 + h - y1)/slope   # bottom edge y = h
              if 0 <= x <= w:
                  ep.append((int(round(x)), h))
              
              y = -slope*x1 + y1  # left edge x = 0
              if 0 <= y <= h:
                  ep.append( (0, (int(round(y)))) )
              
              y = slope*(w - x1) + y1 # right edge x = w
              if 0 <= y <= h:
                  ep.append( (w, (int(round(y)))) )
  
          ep = list(set(ep))  # remove duplicates of points if line cross image at corners
          ep.sort()
          if len(ep) == 2:
              # if points lies outside image then change them
              if not (0 < x1 < w and 0 < y1 < h):
                  pt1 = ep[0]
              if not (0 < x2 < w and 0 < y2 < h):
                  pt2 = ep[1]
          elif len(ep) == 1:
              logger.warning("Line cross the image only at one point")
              return None
          else:
              logger.warning("Line does not cross the image")
              return None
          
          return Line(self.image, (pt1, pt2))
          
      def getVector(self):
          # this should be a lazy property
          if( self.vector is None):
              self.vector = [float(self.end_points[1][0]-self.end_points[0][0]),
                             float(self.end_points[1][1]-self.end_points[0][1])]
          return self.vector
  
      def dot(self,other):
          return np.dot(self.getVector(),other.getVector())
  
      def cross(self,other):
          return np.cross(self.getVector(),other.getVector())
  
      def getYIntercept(self):
          """
          **SUMMARY**
          
          Returns the y intercept based on the lines equation.  Note that this point is potentially not contained in the image itself
  
          **RETURNS**
  
          Returns a floating point intersection value
  
          **EXAMPLE**
  
          >>> img = Image("lenna")
          >>> l = Line(img, ((50, 150), (2, 225))
          >>> b = l.getYIntercept()
          """
          if self.yIntercept is None:
              pt1, pt2 = self.end_points
              m = self.slope
              #y = mx + b | b = y-mx
              self.yIntercept = pt1[1] - m * pt1[0]
          return self.yIntercept
  
      def extendToImageEdges(self):
          """
          **SUMMARY**
          
          Returns the line with endpoints on edges of image. 
  
          **RETURNS**
  
          Returns a :py:class:`Line` object. If line does not lies entirely inside image then returns None.
  
          **EXAMPLE**
  
          >>> img = Image("lenna")
          >>> l = Line(img, ((50, 150), (2, 225))
          >>> cr_l = l.extendToImageEdges()
  
          """
          pt1, pt2 = self.end_points
          pt1, pt2 = min(pt1, pt2), max(pt1, pt2)
          x1, y1 = pt1
          x2, y2 = pt2
          w, h = self.image.width-1, self.image.height-1
          slope = self.slope
          
          if not 0 <= x1 <= w or not 0 <= x2 <= w or not 0 <= y1 <= w or not 0 <= y2 <= w:
              logger.warning("At first the line should be cropped")
              return None
                 
          ep = []
          if slope == float('inf'):
              if 0 <= x1 <= w and 0 <= x2 <= w:
                  return Line(self.image, ((x1, 0), (x2, h)))
          elif slope == 0:
              if 0 <= y1 <= w and 0 <= y2 <= w:
                  return Line(self.image, ((0, y1), (w, y2)))
          else:
              x = (slope*x1 - y1)/slope   # top edge y = 0
              if 0 <= x <= w:
                  ep.append((int(round(x)), 0))
  
              x = (slope*x1 + h - y1)/slope   # bottom edge y = h
              if 0 <= x <= w:
                  ep.append((int(round(x)), h))
              
              y = -slope*x1 + y1  # left edge x = 0
              if 0 <= y <= h:
                  ep.append( (0, (int(round(y)))) )
              
              y = slope*(w - x1) + y1 # right edge x = w
              if 0 <= y <= h:
                  ep.append( (w, (int(round(y)))) )
  
          ep = list(set(ep))  # remove duplicates of points if line cross image at corners
          ep.sort()
          
          return Line(self.image, ep)
  
  
  ######################################################################
  class Barcode(Feature):
      """
      **SUMMARY**
  
      The Barcode Feature wrappers the object returned by findBarcode(), a zbar symbol
  
      * The x,y coordinate is the center of the code.
      * points represents the four boundary points of the feature.  Note: for QR codes, these points are the reference rectangls, and are quadrangular, rather than rectangular with other datamatrix types.
      * data is the parsed data of the code.
  
      **SEE ALSO**
  
      :py:meth:`ImageClass.findBarcodes()`
      """
      data = ""
  
      #given a ZXing bar
      def __init__(self, i, zbsymbol):
          self.image = i
  
          locs = zbsymbol.location
          if len(locs) > 4:
              xs = [l[0] for l in locs]
              ys = [l[1] for l in locs]
              xmax = np.max(xs)
              xmin = np.min(xs)
              ymax = np.max(ys)
              ymin = np.min(ys)
              points = ((xmin, ymin),(xmin,ymax),(xmax, ymax),(xmax,ymin))
          else:
              points = copy(locs) # hopefully this is in tl clockwise order
  
          super(Barcode, self).__init__(i, 0, 0,points)
          self.data = zbsymbol.data
          self.points = copy(points)
          numpoints = len(self.points)
          self.x = 0
          self.y = 0
  
          for p in self.points:
              self.x += p[0]
              self.y += p[1]
  
          if (numpoints):
              self.x /= numpoints
              self.y /= numpoints
  
      def __repr__(self):
          return "%s.%s at (%d,%d), read data: %s" % (self.__class__.__module__, self.__class__.__name__, self.x, self.y, self.data)
  
      def draw(self, color = (255, 0, 0),width=1):
          """
  
          **SUMMARY**
  
          Draws the bounding area of the barcode, given by points.  Note that for
          QR codes, these points are the reference boxes, and so may "stray" into
          the actual code.
  
  
          **PARAMETERS**
  
          * *color* - An RGB color triplet.
          * *width* - if width is less than zero we draw the feature filled in, otherwise we draw the
            contour using the specified width.
  
  
          **RETURNS**
  
          Nothing - this is an inplace operation that modifies the source images drawing layer.
  
  
          """
          self.image.drawLine(self.points[0], self.points[1], color,width)
          self.image.drawLine(self.points[1], self.points[2], color,width)
          self.image.drawLine(self.points[2], self.points[3], color,width)
          self.image.drawLine(self.points[3], self.points[0], color,width)
  
      def length(self):
          """
          **SUMMARY**
  
          Returns the longest side of the quandrangle formed by the boundary points.
  
          **RETURNS**
  
          A floating point length value.
  
          **EXAMPLE**
  
          >>> img = Image("mycode.jpg")
          >>> bc = img.findBarcode()
          >>> print bc[-1].length()
  
          """
          sqform = spsd.squareform(spsd.pdist(self.points, "euclidean"))
          #get pairwise distances for all points
          #note that the code is a quadrilateral
          return max(sqform[0][1], sqform[1][2], sqform[2][3], sqform[3][0])
  
      def area(self):
          """
          **SUMMARY**
  
          Returns the area defined by the quandrangle formed by the boundary points
  
   
          **RETURNS**
  
          An integer area value.
  
          **EXAMPLE**
  
          >>> img = Image("mycode.jpg")
          >>> bc = img.findBarcode()
          >>> print bc[-1].area()
  
  
          """
          #calc the length of each side in a square distance matrix
          sqform = spsd.squareform(spsd.pdist(self.points, "euclidean"))
  
          #squareform returns a N by N matrix
          #boundry line lengths
          a = sqform[0][1]
          b = sqform[1][2]
          c = sqform[2][3]
          d = sqform[3][0]
  
          #diagonals
          p = sqform[0][2]
          q = sqform[1][3]
  
          #perimeter / 2
          s = (a + b + c + d)/2.0
  
          #i found the formula to do this on wikihow.  Yes, I am that lame.
          #http://www.wikihow.com/Find-the-Area-of-a-Quadrilateral
          return sqrt((s - a) * (s - b) * (s - c) * (s - d) - (a * c + b * d + p * q) * (a * c + b * d - p * q) / 4)
  
  ######################################################################
  class HaarFeature(Feature):
      """
      **SUMMARY**
  
      The HaarFeature is a rectangle returned by the FindHaarFeature() function.
  
      * The x,y coordinates are defined by the center of the bounding rectangle.
      * The classifier property refers to the cascade file used for detection .
      * Points are the clockwise points of the bounding rectangle, starting in upper left.
  
      """
      classifier = ""
      _width = ""
      _height = ""
      neighbors = ''
      featureName = 'None'
  
      def __init__(self, i, haarobject, haarclassifier = None, cv2flag=True):
          self.image = i
          if cv2flag == False:
              ((x, y, width, height), self.neighbors) = haarobject
          elif cv2flag == True:
              (x, y, width, height) = haarobject
          at_x = x + width/2
          at_y = y + height/2 #set location of feature to middle of rectangle
          points = ((x, y), (x + width, y), (x + width, y + height), (x, y + height))
  
           #set bounding points of the rectangle
          self.classifier = haarclassifier
          if( haarclassifier is not None ):
              self.featureName = haarclassifier.getName()
  
          super(HaarFeature, self).__init__(i, at_x, at_y, points)
  
  
      def draw(self, color = (0, 255, 0),width=1):
          """
          **SUMMARY**
  
          Draw the bounding rectangle, default color green.
  
          **PARAMETERS**
  
          * *color* - An RGB color triplet.
          * *width* - if width is less than zero we draw the feature filled in, otherwise we draw the
            contour using the specified width.
  
  
          **RETURNS**
  
          Nothing - this is an inplace operation that modifies the source images drawing layer.
  
          """
          self.image.drawLine(self.points[0], self.points[1], color,width)
          self.image.drawLine(self.points[1], self.points[2], color,width)
          self.image.drawLine(self.points[2], self.points[3], color,width)
          self.image.drawLine(self.points[3], self.points[0], color,width)
  
      def __getstate__(self):
          dict = self.__dict__.copy()
          if 'classifier' in dict:
              del dict["classifier"]
          return dict
  
      def meanColor(self):
          """
          **SUMMARY**
  
          Find the mean color of the boundary rectangle.
  
          **RETURNS**
  
          Returns an  RGB triplet that corresponds to the mean color of the feature.
  
          **EXAMPLE**
  
          >>> img = Image("lenna")
          >>> face = HaarCascade("face.xml")
          >>> faces = img.findHaarFeatures(face)
          >>> print faces[-1].meanColor()
  
          """
          crop = self.image[self.points[0][0]:self.points[1][0], self.points[0][1]:self.points[2][1]]
          return crop.meanColor()
  
  
      def area(self):
          """
          **SUMMARY**
  
          Returns the area of the feature in pixels.
  
          **RETURNS**
  
          The area of the feature in pixels.
  
          **EXAMPLE**
  
          >>> img = Image("lenna")
          >>> face = HaarCascade("face.xml")
          >>> faces = img.findHaarFeatures(face)
          >>> print faces[-1].area()
  
          """
          return self.width() * self.height()
  
  ######################################################################
  class Chessboard(Feature):
      """
      **SUMMARY**
  
      This class is used for Calibration, it uses a chessboard
      to calibrate from pixels to real world measurements.
      """
      spCorners = []
      dimensions = ()
  
      def __init__(self, i, dim, subpixelCorners):
          self.dimensions = dim
          self.spCorners = subpixelCorners
          at_x = np.average(np.array(self.spCorners)[:, 0])
          at_y = np.average(np.array(self.spCorners)[:, 1])
  
          posdiagsorted = sorted(self.spCorners, key = lambda corner: corner[0] + corner[1])
          #sort corners along the x + y axis
          negdiagsorted = sorted(self.spCorners, key = lambda corner: corner[0] - corner[1])
          #sort corners along the x - y axis
  
          points = (posdiagsorted[0], negdiagsorted[-1], posdiagsorted[-1], negdiagsorted[0])
          super(Chessboard, self).__init__(i, at_x, at_y, points)
  
  
      def draw(self, no_needed_color = None):
          """
          **SUMMARY**
  
  
          Draws the chessboard corners.  We take a color param, but ignore it.
  
          **PARAMETERS**
  
          * *no_needed_color* - An RGB color triplet that isn't used
  
  
          **RETURNS**
  
          Nothing - this is an inplace operation that modifies the source images drawing layer.
  
          """
          cv.DrawChessboardCorners(self.image.getBitmap(), self.dimensions, self.spCorners, 1)
  
      def area(self):
          """
          **SUMMARY**
  
          Returns the mean of the distance between corner points in the chessboard
          Given that the chessboard is of a known size, this can be used as a
          proxy for distance from the camera
  
          **RETURNS**
  
          Returns the mean distance between the corners.
  
          **EXAMPLE**
  
          >>> img = Image("corners.jpg")
          >>> feats = img.findChessboardCorners()
          >>> print feats[-1].area()
  
          """
          #note, copying this from barcode means we probably need a subclass of
          #feature called "quandrangle"
          sqform = spsd.squareform(spsd.pdist(self.points, "euclidean"))
          a = sqform[0][1]
          b = sqform[1][2]
          c = sqform[2][3]
          d = sqform[3][0]
          p = sqform[0][2]
          q = sqform[1][3]
          s = (a + b + c + d)/2.0
          return 2 * sqrt((s - a) * (s - b) * (s - c) * (s - d) - (a * c + b * d + p * q) * (a * c + b * d - p * q) / 4)
  
  ######################################################################
  class TemplateMatch(Feature):
      """
      **SUMMARY**
  
      This class is used for template (pattern) matching in images.
      The template matching cannot handle scale or rotation.
  
      """
  
      template_image = None
      quality = 0
      w = 0
      h = 0
  
      def __init__(self, image, template, location, quality):
          self.template_image = template # -- KAT - TRYING SOMETHING
          self.image = image
          self.quality = quality
          w = template.width
          h = template.height
          at_x = location[0]
          at_y = location[1]
          points = [(at_x,at_y),(at_x+w,at_y),(at_x+w,at_y+h),(at_x,at_y+h)]
  
          super(TemplateMatch, self).__init__(image, at_x, at_y, points)
  
      def _templateOverlaps(self,other):
          """
          Returns true if this feature overlaps another template feature.
          """
          (maxx,minx,maxy,miny) = self.extents()
          overlap = False
          for p in other.points:
              if( p[0] <= maxx and p[0] >= minx and p[1] <= maxy and p[1] >= miny ):
                  overlap = True
                  break
  
          return overlap
  
  
      def consume(self, other):
          """
          Given another template feature, make this feature the size of the two features combined.
          """
          (maxx,minx,maxy,miny) = self.extents()
          (maxx0,minx0,maxy0,miny0) = other.extents()
  
          maxx = max(maxx,maxx0)
          minx = min(minx,minx0)
          maxy = max(maxy,maxy0)
          miny = min(miny,miny0)
          self.x = minx
          self.y = miny
          self.points = [(minx,miny),(minx,maxy),(maxx,maxy),(maxx,miny)]
          self._updateExtents()
  
  
      def rescale(self,w,h):
          """
          This method keeps the feature's center the same but sets a new width and height
          """
          (maxx,minx,maxy,miny) = self.extents()
          xc = minx+((maxx-minx)/2)
          yc = miny+((maxy-miny)/2)
          x = xc-(w/2)
          y = yc-(h/2)
          self.x = x
          self.y = y
          self.points = [(x,y),
                         (x+w,y),
                         (x+w,y+h),
                         (x,y+h)]
          self._updateExtents()
  
      def crop(self):
          (maxx,minx,maxy,miny) = self.extents()
          return self.image.crop(minx,miny,maxx-minx,maxy-miny)
  
      def draw(self, color = Color.GREEN, width = 1):
          """
          **SUMMARY**
  
          Draw the bounding rectangle, default color green.
  
          **PARAMETERS**
  
          * *color* - An RGB color triplet.
          * *width* - if width is less than zero we draw the feature filled in, otherwise we draw the
            contour using the specified width.
  
          **RETURNS**
  
          Nothing - this is an inplace operation that modifies the source images drawing layer.
          """
          self.image.dl().rectangle((self.x,self.y), (self.width(), self.height()), color = color, width=width)
  ######################################################################
  class Circle(Feature):
      """
      **SUMMARY**
  
      Class for a general circle feature with a center at (x,y) and a radius r
  
      """
      x = 0.00
      y = 0.00
      r = 0.00
      image = "" #parent image
      points = []
      avgColor = None
  
      def __init__(self, i, at_x, at_y, r):
          self.r = r
          self.avgColor = None
          points = [(at_x-r,at_y-r),(at_x+r,at_y-r),(at_x+r,at_y+r),(at_x-r,at_y+r)]
          super(Circle, self).__init__(i, at_x, at_y, points)
          segments = 18
          rng = range(1,segments+1)
          self.mContour = []
          for theta in rng:
              rp = 2.0*math.pi*float(theta)/float(segments)
              x = (r*math.sin(rp))+at_x
              y = (r*math.cos(rp))+at_y
              self.mContour.append((x,y))
  
  
  
      def draw(self, color = Color.GREEN,width=1):
          """
          **SUMMARY**
  
          With no dimension information, color the x,y point for the feature.
  
          **PARAMETERS**
  
          * *color* - An RGB color triplet.
          * *width* - if width is less than zero we draw the feature filled in, otherwise we draw the
            contour using the specified width.
  
          **RETURNS**
  
          Nothing - this is an inplace operation that modifies the source images drawing layer.
  
          """
          self.image.dl().circle((self.x,self.y),self.r,color,width)
  
      def show(self, color = Color.GREEN):
          """
          **SUMMARY**
  
          This function will automatically draw the features on the image and show it.
          It is a basically a shortcut function for development and is the same as:
  
          **PARAMETERS**
  
          * *color* - the color of the feature as an rgb triplet.
  
          **RETURNS**
  
          Nothing - this is an inplace operation that modifies the source images drawing layer.
  
          **EXAMPLE**
  
          >>> img = Image("logo")
          >>> feat = img.findCircle()
          >>> feat[0].show()
  
          """
          self.draw(color)
          self.image.show()
  
      def distanceFrom(self, point = (-1, -1)):
          """
          **SUMMARY**
  
          Given a point (default to center of the image), return the euclidean distance of x,y from this point.
  
          **PARAMETERS**
  
          * *point* - The point, as an (x,y) tuple on the image to measure distance from.
  
          **RETURNS**
  
          The distance as a floating point value in pixels.
  
          **EXAMPLE**
  
          >>> img = Image("OWS.jpg")
          >>> blobs = img.findCircle()
  