def project_point_through_rect_onto_camera(self, point, rect): """ Find pixels covered by projection of a point through a rectangle """ h, w = self.camera_shape x1 = w x2 = 0 y1 = h y2 = 0 for corner in rect: l = geom.Line.FromPoints(point, corner) p = geom.intersect_line_with_plane(l, self.camera_rect) x,y = self.point_to_camera_pixel(p) x = clamp(int(x+1e-5),0,w-1) y = clamp(int(y+1e-5),0,h-1) if x < x1: x1 = x if y < y1: y1 = y if x > x2: x2 = x if y > y2: y2 = y return [x1, y1, x2, y2]
def project_point_through_rect_onto_camera(self, point, rect): """ Find pixels covered by projection of a point through a rectangle """ h, w = self.camera_shape x1 = w x2 = 0 y1 = h y2 = 0 for corner in rect: l = geom.Line.FromPoints(point, corner) p = geom.intersect_line_with_plane(l, self.camera_rect) x, y = self.point_to_camera_pixel(p) x = clamp(int(x + 1e-5), 0, w - 1) y = clamp(int(y + 1e-5), 0, h - 1) if x < x1: x1 = x if y < y1: y1 = y if x > x2: x2 = x if y > y2: y2 = y return [x1, y1, x2, y2]
def mockup_calibration_matrix(self, dx=0.5, dy=0.5): """ Create a theoretical calibration matrix for the designed spectrometer geometry. """ h, w = self.camera_shape calib = np.zeros((h, w)) d0 = lattice_constants[self.xtal_type] # XXX this assumes the crystal is cubic (all that we currently use are) # it would be good to generalize this though d = d0 / norm(self.xtal_cut) images = self.image_points() bounds = [] pixels = self.camera_pixel_locations(dx, dy) # find image points and xtal projection boundaries for xtal_plane, image, entrance_aperture in izip( self.xtal_rects, images, self.entrance_aperture): exit_projection = self.project_point_through_rect_onto_camera( image, self.exit_aperture) active_region = [ geom.intersect_line_with_plane( geom.Line.FromPoints(self.sample, corner), xtal_plane) for corner in entrance_aperture ] active_projection = self.project_point_through_rect_onto_camera( image, active_region) x1 = max(exit_projection[0], active_projection[0]) y1 = max(exit_projection[1], active_projection[1]) x2 = min(exit_projection[2], active_projection[2]) y2 = min(exit_projection[3], active_projection[3]) bounds.append([x1, y1, x2, y2]) rw = x2 - x1 rh = y2 - y1 dn = pixels[y1:y2, x1:x2].reshape((rw * rh, 3)) - image length = np.sqrt((dn**2).sum(1)) cos_theta = np.abs((dn * xtal_plane.n).sum(1)) / length energy = HC / (2 * d) / cos_theta energy = energy.reshape((rh, rw)) calib[y1:y2, x1:x2] = energy self.images = images self.projection_bounds = bounds return calib
def mockup_calibration_matrix(self, dx=0.5, dy=0.5): """ Create a theoretical calibration matrix for the designed spectrometer geometry. """ h,w = self.camera_shape calib = np.zeros((h,w)) d0 = lattice_constants[self.xtal_type] # XXX this assumes the crystal is cubic (all that we currently use are) # it would be good to generalize this though d = d0 / norm(self.xtal_cut) images = self.image_points() bounds = [] pixels = self.camera_pixel_locations(dx,dy) # find image points and xtal projection boundaries for xtal_plane, image, entrance_aperture in izip(self.xtal_rects, images, self.entrance_aperture): exit_projection = self.project_point_through_rect_onto_camera(image, self.exit_aperture) active_region = [ geom.intersect_line_with_plane( geom.Line.FromPoints(self.sample, corner), xtal_plane ) for corner in entrance_aperture ] active_projection = self.project_point_through_rect_onto_camera(image, active_region) x1 = max(exit_projection[0], active_projection[0]) y1 = max(exit_projection[1], active_projection[1]) x2 = min(exit_projection[2], active_projection[2]) y2 = min(exit_projection[3], active_projection[3]) bounds.append([x1,y1,x2,y2]) rw = x2-x1 rh = y2-y1 dn = pixels[y1:y2, x1:x2].reshape((rw*rh,3)) - image length = np.sqrt((dn**2).sum(1)) cos_theta = np.abs((dn*xtal_plane.n).sum(1)) / length energy = HC / (2 * d) / cos_theta energy = energy.reshape((rh,rw)) calib[y1:y2,x1:x2] = energy self.images = images self.projection_bounds = bounds return calib
def calculate_projection_bounds(self): """ Determine exposed region on camera from each xtal. Finds projection of specular radiation from source point through entrance aperture, off xtal, through exit aperture and onto camera. For now, this finds top left and bottom right corners (in camera coords) and assumes region to be rectangular. TODO: should be easy to extend this to calculate full trapezoidal region or, could add option to give largest rect inside, or smallest rect outside... """ bounds = [] images = self.image_points() for xtal_plane, image, entrance_aperture in izip( self.xtal_rects, images, self.entrance_aperture): # project image points through exit aperture onto camera exit_projection = self.project_point_through_rect_onto_camera( image, self.exit_aperture) # find region of crystals exposed by source active_region = [ geom.intersect_line_with_plane( geom.Line.FromPoints(self.sample, corner), xtal_plane) for corner in entrance_aperture ] # project images through active region on to camera active_projection = self.project_point_through_rect_onto_camera( image, active_region) # "intersect" (not complete intersection... see TODO above) x1 = max(exit_projection[0], active_projection[0]) y1 = max(exit_projection[1], active_projection[1]) x2 = min(exit_projection[2], active_projection[2]) y2 = min(exit_projection[3], active_projection[3]) # add it to the list bounds.append([x1, y1, x2, y2]) return bounds
def calculate_projection_bounds(self): """ Determine exposed region on camera from each xtal. Finds projection of specular radiation from source point through entrance aperture, off xtal, through exit aperture and onto camera. For now, this finds top left and bottom right corners (in camera coords) and assumes region to be rectangular. TODO: should be easy to extend this to calculate full trapezoidal region or, could add option to give largest rect inside, or smallest rect outside... """ bounds = [] images = self.image_points() for xtal_plane, image, entrance_aperture in izip(self.xtal_rects, images, self.entrance_aperture): # project image points through exit aperture onto camera exit_projection = self.project_point_through_rect_onto_camera(image, self.exit_aperture) # find region of crystals exposed by source active_region = [ geom.intersect_line_with_plane( geom.Line.FromPoints(self.sample, corner), xtal_plane ) for corner in entrance_aperture ] # project images through active region on to camera active_projection = self.project_point_through_rect_onto_camera(image, active_region) # "intersect" (not complete intersection... see TODO above) x1 = max(exit_projection[0], active_projection[0]) y1 = max(exit_projection[1], active_projection[1]) x2 = min(exit_projection[2], active_projection[2]) y2 = min(exit_projection[3], active_projection[3]) # add it to the list bounds.append([x1,y1,x2,y2]) return bounds