def init(self, xform):
        """Initialize with the given xform, calculating python-only variables"""
        self.xform = xform

        corners = (Vec3(-0.5, -0.5),
                   Vec3(-0.5,  0.5),
                   Vec3( 0.5,  0.5),
                   Vec3( 0.5, -0.5))
        self.world_vertices = [xform.transform(c) for c in corners]
        self.world_normal = xform.transform_vector(-Vec3.z_axis()).normalize()
        self.world_center = xform.transform(Vec3.origin())

        # Point upwards by rotating up vector by -90, -180, or -270 degrees.
        # Direction is the rotation angle (in units of 90-degrees).
        #     0=up, 1=left, 2=down, 3=right
        # In image space, up is negative.
        up = xform.transform_vector(-Vec3.y_axis()).normalized()
        direc = 0
        if abs(up.x) > abs(up.y):
            rot = Mat4.new_rotate_axis(self.world_normal, math.pi*0.5)
            up = rot.transform(up)
            direc = 1
        if  up.y < 0:
            rot = Mat4.new_rotate_axis(self.world_normal, math.pi)
            up = rot.transform(up)
            direc += 2
        self.world_up = up
        self.world_direction = direc
    def init(self, xform):
        """Initialize with the given xform, calculating python-only variables"""
        self.xform = xform

        corners = (Vec3(-0.5, -0.5), Vec3(-0.5,
                                          0.5), Vec3(0.5,
                                                     0.5), Vec3(0.5, -0.5))
        self.world_vertices = [xform.transform(c) for c in corners]
        self.world_normal = xform.transform_vector(-Vec3.z_axis()).normalize()
        self.world_center = xform.transform(Vec3.origin())

        # Point upwards by rotating up vector by -90, -180, or -270 degrees.
        # Direction is the rotation angle (in units of 90-degrees).
        #     0=up, 1=left, 2=down, 3=right
        # In image space, up is negative.
        up = xform.transform_vector(-Vec3.y_axis()).normalized()
        direc = 0
        if abs(up.x) > abs(up.y):
            rot = Mat4.new_rotate_axis(self.world_normal, math.pi * 0.5)
            up = rot.transform(up)
            direc = 1
        if up.y < 0:
            rot = Mat4.new_rotate_axis(self.world_normal, math.pi)
            up = rot.transform(up)
            direc += 2
        self.world_up = up
        self.world_direction = direc
def _get_change_basis_xform(center, up, normal):
    """Return a matrix that changes from the given basis to the x-y-z
    basis. Basically, this 'straightens' out the plane described by
    the basis. The 'right' axis is calculated from the up and normal."""
    normal = normal.normalized()
    right = up.cross(normal).normalize()
    up    = normal.cross(right).normalize()

    xform = Mat4.new_translate(*center)
    xform *= Mat4.new_change_basis(right, up, normal, center).inverse()
    return xform
def _get_camera_xform(image):
    """Return the xform that maps world coordinates to image
    coordinates. Uses the Iphone's lens characteristics."""
    film_size    = 6.35 # Iphone sensor size, in mm
    focal_length = 3.85 # Iphone focal length, in mm
    width, height = image.size
    aspect = float(width) / height
    fov_y = 2 * math.atan2(film_size/aspect, 2 * focal_length)
    xform = Mat4.new_translate(width/2.0,  height/2.0, 0)
    xform.scale(-width/2.0, -height/2.0, 1)
    xform *= Mat4.new_perspective(fov_y, aspect, 1, 10)
    return xform
def detect(image, confidence_threshold=0.5, debug=False, debug_image=False):
    """Find marker glyphs in the image. 
    Try different thresholds, accumulate the results and return the
    best.  TODO: Look at local neighborhoods to find the best
    per-pixel threshold. Note: ARToolkitPlus autothresh is lame."""

    # Make grayscale if necessary
    grayimage = image if image.mode == "L" else ImageOps.grayscale(image)

    # Create the detector
    detector = _create(grayimage.size[0], grayimage.size[1], debug)

    # Build a map from marker-id to a list of markers with that id
    # detected at each successive threshold.
    allmarkers = {}

    # Systematically try different thresholds
    data = grayimage.tostring()
    for thresh in xrange(16, 255, 16):

        # Set the current threshold and extract the markers
        _set_thresholds(detector, thresh, False, 0)
        num = _detect(detector, data)
        markers = [_get_marker(detector, m).contents for m in xrange(num)]
        if debug:
            msg = str(
                sorted([(m.id, m.confidence) for m in markers
                        if m.confidence > 0]))
            logging.debug("Thresh {0} found {1} {2}".format(thresh, num, msg))

        # Add markers with high enough confidence to the map
        for marker in markers:
            if marker.confidence >= confidence_threshold:
                # Copy because it will be overwritten on the next detection
                marker = copy.deepcopy(marker)
                xform = Mat4()
                _get_marker_transform(detector, marker, xform.ctypes)
                xform.transpose()
                marker.init(xform)

                # If confidence is higher than current highest, replace list
                if (not marker.id in allmarkers or marker.confidence >
                        allmarkers[marker.id][0].confidence):
                    allmarkers[marker.id] = [marker]

                # Otherwise append to the list
                else:
                    allmarkers[marker.id].append(marker)

    # At this point, the markers in each individual list have the same
    # confidence. To pick the 'best' marker, first throw out any
    # markers that don't share the median direction, then pick the
    # marker with the median area. This should exclude bad detections.
    # For clarity, use a loop rather than list comprehensions.
    markerlists = allmarkers.values()
    markers = []
    for markerlist in markerlists:
        markerlist = sorted(markerlist, key=lambda m: m.direction)
        direction = markerlist[len(markerlist) / 2].direction
        markerlist = [
            marker for marker in markerlist if marker.direction == direction
        ]
        markerlist = sorted(markerlist, key=lambda m: m.area)
        markers.append(markerlist[len(markerlist) / 2])

    # Print found markers and draw on the original image.
    if debug:
        logging.debug("Final markers:")
        logging.debug(str_markers(markers))
        if debug_image:
            draw_markers(markers, image)

    return markers