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