Пример #1
0
    def run(self):
        print 'Initializing planner!'

        self.planner = Planner.get(self.rconfig)
        print 'Running planner'
        b = Benchmark()
        self.planner.run()
        b.stop()
        print 'Planner done!  Took : %s' % str(b)
        self.plannerDone.emit()
Пример #2
0
	def project_diffusion(self):
		print 'Projecting diffusion...'
		bench = Benchmark()
		start_polygons = len(self.diffusion.polygons)
		# Save in case we want to reference it
		self.diffusion_original = self.diffusion
		if False:
			self.diffusion.show()
			self.polysilicon.show()
		
		#self.diffusioni = self.diffusion_original.subtract(self.polysilicon)
		#self.diffusion = self.diffusioni.to_layer()		
		
		self.diffusion = self.diffusion_original.subtract(self.polysilicon)
		
		# Find intersection with poly to form transistors
		# Require 2, some chips use diffusion for conduction to bypass metal
		# 4003 overlaps diffusion and poly because they split a contact across them
		
		# Subtract out the poly from diffusion
		# We can then use the same proximity algorithm as before
		# However, we will save intersections to get a better idea of correct transistor mapping
		end_polygons = len(self.diffusion.polygons)
		print 'Projected diffusion %d => %d polygons in %s' % (start_polygons, end_polygons, repr(bench))
		
		if False:
			self.diffusion.show()
			#self.polysilicon.show()
			#self.diffusion_original.show()
			sys.exit(1)
Пример #3
0
    def run(self):
        bench = Benchmark()
        
        # The following will assume all of the images have the same size
        self.verify_images()
        
        fns = []
        # Copy project so we can trash it
        project = self.project.copy()
        for il in project.get_image_lines():
            fns.append(il.get_name())
        self.icm = ImageCoordinateMap.from_tagged_file_names(fns)

        pre_opt(project, self.icm)
        prepare_pto(project, reoptimize=False)
        
        # "PToptimizer out.pto"
        args = ["PToptimizer"]
        args.append(project.get_a_file_name())
        print 'Optimizing %s' % project.get_a_file_name()
        #raise Exception()
        #self.project.save()
        rc = execute.without_output(args)
        if rc != 0:
            raise Exception('failed position optimization')
        # API assumes that projects don't change under us
        project.reopen()
        
        # final rms error 24.0394 units
        rms_error = None
        for l in project.get_comment_lines():
            if l.find('final rms error') >= 00:
                rms_error = float(l.split()[4])
                break
        print 'Optimize: RMS error of %f' % rms_error
        # Filter out gross optimization problems
        if self.rms_error_threshold and rms_error > self.rms_error_threshold:
            raise Exception("Max RMS error threshold %f but got %f" % (self.rms_error_threshold, rms_error))
        
        print 'Merging project...'
        merge_pto(project, self.project)
        if self.debug:
            print self.project
        
        bench.stop()
        print 'Optimized project in %s' % bench
Пример #4
0
 def rebuild_qt(self):
     bench = Benchmark()
     rect_l = list()
     for polygon in self.polygons:
         rect_l.append(QTUVPolygon(polygon))
     self.qt = PolygonQuadTree(rect_l)
     print 'Finished building %s quadtree (%d elements), took: %s' % (
         self.name, len(rect_l), repr(bench))
Пример #5
0
    def run(self):
        bench = Benchmark()
        
        # The following will assume all of the images have the same size
        self.verify_images()
        
        fns = []
        # Copy project so we can trash it
        project = self.project.copy()
        for il in project.get_image_lines():
            fns.append(il.get_name())
        self.icm = ImageCoordinateMap.from_tagged_file_names(fns)

        print 'Verbose: %d' % self.debug
        print 'working direclty on %s' % self.project.get_a_file_name()
        pre_opt(self.project, self.icm, verbose=self.debug, stdev=self.stdev)
        
        bench.stop()
        print 'Optimized project in %s' % bench
Пример #6
0
    def process_image(self, pim, st_bounds):
        '''
        A tile is valid if its in a safe location
        There are two ways for the location to be safe:
        -No neighboring tiles as found on canvas edges
        -Sufficiently inside the blend area that artifacts should be minimal
        '''
        bench = Benchmark()
        [x0, x1, y0, y1] = st_bounds
        gen_tiles = 0
        print
        # TODO: get the old info back if I miss it after yield refactor
        print 'Phase 4: chopping up supertile'
        self.msg('step(x: %d, y: %d)' % (self.tw, self.th), 3)
        #self.msg('x in xrange(%d, %d, %d)' % (xt0, xt1, self.tw), 3)
        #self.msg('y in xrange(%d, %d, %d)' % (yt0, yt1, self.th), 3)

        for (y, x) in self.gen_supertile_tiles(st_bounds):
            # If we made it this far the tile can be constructed with acceptable enblend artifacts
            row = self.y2row(y)
            col = self.x2col(x)

            # Did we already do this tile?
            if self.is_done(row, col):
                # No use repeating it although it would be good to diff some of these
                if self.verbose:
                    print 'Rejecting tile x%d, y%d / r%d, c%d: already done' % (
                        x, y, row, col)
                continue

            # note that x and y are in whole pano coords
            # we need to adjust to our frame
            # row and col on the other hand are used for global naming
            self.make_tile(pim, x - x0, y - y0, row, col)
            gen_tiles += 1
        bench.stop()
        print 'Generated %d new tiles for a total of %d / %d in %s' % (
            gen_tiles, len(
                self.closed_list), self.net_expected_tiles, str(bench))
        if gen_tiles == 0:
            raise Exception("Didn't generate any tiles")
Пример #7
0
	def find_and_merge_nets(self):
		# Combine polygons at a net level on the same layer
		# Only needed if you have bad input polygons
		# Really would be better to pre-process input to combine them
		#bench = Benchmark()
		#self.condense_polygons()
		#print 'Polygons condensed in %s' % repr(bench)
		#self.show_nets()
		#sys.exit(1)
		self.verify_net_index()
		
		# Note that you cannot have diffusion and poly, via is for one or the other		
		bench = Benchmark()
		self.merge_metal_vias()
		print 'Metal and vias merged in %s' % repr(bench)
		#self.show_nets()
		#self.verify_net_index()
		#sys.exit(1)
		
		self.via_check(2)
		
		# Connected poly to metal
		
		bench = Benchmark()
		self.merge_poly_vias_layers()
		print 'Poly and vias merged in %s' % repr(bench)
		#self.show_nets()
		self.verify_net_index()
		
		# Connect diffusion to metal
		bench = Benchmark()
		self.merge_diffusion_vias_layers()
		print 'Diffusion and vias merged in %s' % repr(bench)
		#self.show_nets()
		self.verify_net_index()
		
		self.via_check(3)
		
		#self.show_nets()
		
		print 'Finished merge'
Пример #8
0
 def processCncProgress(self, pictures_to_take, pictures_taken, image, first):
     print 'Processing CNC progress'
     if first:
         print 'First CB with %d items' % pictures_to_take
         self.pb.setMinimum(0)
         self.pb.setMaximum(pictures_to_take)
         self.bench = Benchmark(pictures_to_take)
     else:
         print 'took %s at %d / %d' % (image, pictures_taken, pictures_to_take)
         self.bench.set_cur_items(pictures_taken)
         print self.bench
         
     self.pb.setValue(pictures_taken)
Пример #9
0
 def process_image(self, pim, st_bounds):
     '''
     A tile is valid if its in a safe location
     There are two ways for the location to be safe:
     -No neighboring tiles as found on canvas edges
     -Sufficiently inside the blend area that artifacts should be minimal
     '''
     bench = Benchmark()
     [x0, x1, y0, y1] = st_bounds
     gen_tiles = 0
     print
     # TODO: get the old info back if I miss it after yield refactor
     print 'Phase 4: chopping up supertile'
     self.msg('step(x: %d, y: %d)' % (self.tw, self.th), 3)
     #self.msg('x in xrange(%d, %d, %d)' % (xt0, xt1, self.tw), 3)
     #self.msg('y in xrange(%d, %d, %d)' % (yt0, yt1, self.th), 3)
 
     for (y, x) in self.gen_supertile_tiles(st_bounds):    
         # If we made it this far the tile can be constructed with acceptable enblend artifacts
         row = self.y2row(y)
         col = self.x2col(x)
     
         # Did we already do this tile?
         if self.is_done(row, col):
             # No use repeating it although it would be good to diff some of these
             if self.verbose:
                 print 'Rejecting tile x%d, y%d / r%d, c%d: already done' % (x, y, row, col)
             continue
     
         # note that x and y are in whole pano coords
         # we need to adjust to our frame
         # row and col on the other hand are used for global naming
         self.make_tile(pim, x - x0, y - y0, row, col)
         gen_tiles += 1
     bench.stop()
     print 'Generated %d new tiles for a total of %d / %d in %s' % (gen_tiles, len(self.closed_list), self.net_expected_tiles, str(bench))
     if gen_tiles == 0:
         raise Exception("Didn't generate any tiles")
Пример #10
0
    if args.stampout:
        _outdate = IOTimestamp(sys, 'stdout')
        _errdate = IOTimestamp(sys, 'stderr')

    if exist:
        _outlog.out_fd.write('\n')
        _outlog.out_fd.write('\n')
        _outlog.out_fd.write('\n')
        _outlog.out_fd.write('*' * 80 + '\n')
        _outlog.out_fd.write('*' * 80 + '\n')
        _outlog.out_fd.write('*' * 80 + '\n')
    print 'pr0npto starting'
    print 'In: %s' % pto_in
    print 'Out: %s' % pto_out
    bench = Benchmark()

    pto = PTOProject.from_file_name(pto_in)
    # Make sure we don't accidently override the original
    pto.remove_file_name()
    
    if args.center is True:
        center(pto)
    
    if args.anchor:
        print 'Re-finding anchor'
        center_anchor(pto)
    
    if args.basename:
        print 'Converting to basename'
        make_basename(pto)
Пример #11
0
    def run(self):
        if self.dry:
            print 'Dry run abort'
            return

        bench = Benchmark()

        if not self.output_project_file_name:
            raise Exception("need project file")
        #if not self.output_project_file_name:
            #self.project_temp_file = ManagedTempFile.get()
            #self.output_project_file_name = self.project_temp_file.file_name
        print 'Beginning stitch'
        print 'output project file name: %s' % self.output_project_file_name

        #sys.exit(1)
        self.init_failures()

        # Generate control points and merge them into a master project
        self.control_point_gen = get_cp_engine()
        # How many rows and cols to go to each side
        # If you hand took the pictures, this might suit you
        self.project = PTOProject.from_blank()
        if self.output_project_file_name:
            self.project.set_file_name(self.output_project_file_name)
            if os.path.exists(self.output_project_file_name):
                # Otherwise, we merge into it
                print 'WARNING: removing old project file: %s' % self.output_project_file_name
                os.remove(self.output_project_file_name)
        else:
            self.project.get_a_file_name(None, "_master.pto")

        self.project.image_file_names = self.image_file_names

        try:
            '''
            Generate control points
            '''
            self.generate_control_points()
            print 'Soften try: %s' % (self.soften_try,)
            print 'Soften ok: %s' % (self.soften_ok,)

            print 'Post stitch fixup...'
            optimize_xy_only(self.project)
            fixup_i_lines(self.project)
            fixup_p_lines(self.project)


            print
            print '***PTO project baseline final (%s / %s) data length %d***' % (self.project.file_name, self.output_project_file_name, len(self.project.get_text()))
            print

            self.failure_json_w()
            print

            # Make dead sure its saved up to date
            self.project.save()
            # having issues with this..
            if self.output_project_file_name and not self.project.file_name == self.output_project_file_name:
                raise Exception('project file name changed %s %s', self.project.file_name, self.output_project_file_name)

            # TODO: missing calc opt size/width/height/fov and crop

        except Exception as e:
            sys.stdout.flush()
            sys.stderr.flush()
            print
            print 'WARNING: stitch FAILED'
            traceback.print_exc()
            try:
                fn = self.project.file_name + ".failed"
                print 'Attempting to save intermediate result to %s' % fn
                self.project.save_as(fn)
            except:
                print 'WARNING: failed intermediate save'
            raise e
        finally:
            bench.stop()
            print 'Stitch done in %s' % bench
Пример #12
0
    if args.stampout:
        _outdate = IOTimestamp(sys, 'stdout')
        _errdate = IOTimestamp(sys, 'stderr')

    if exist:
        _outlog.out_fd.write('\n')
        _outlog.out_fd.write('\n')
        _outlog.out_fd.write('\n')
        _outlog.out_fd.write('*' * 80 + '\n')
        _outlog.out_fd.write('*' * 80 + '\n')
        _outlog.out_fd.write('*' * 80 + '\n')
    print 'pr0npto starting'
    print 'In: %s' % pto_in
    print 'Out: %s' % pto_out
    bench = Benchmark()

    pto = PTOProject.from_file_name(pto_in)
    # Make sure we don't accidently override the original
    pto.remove_file_name()

    if args.center is True:
        center(pto)

    if args.anchor:
        print 'Re-finding anchor'
        center_anchor(pto)

    if args.basename:
        print 'Converting to basename'
        make_basename(pto)
Пример #13
0
	def from_cif_init(self, file_name = "in.cif"):
		self.vias = Layer()
		self.metal = Layer()
		self.polysilicon = Layer()
		self.diffusion = Layer()
		self.labels = Layer()
		self.metal_gnd = None
		self.metal_vcc = None
		self.default_layer_names()
		
		parsed = CIFParser.parse(file_name)
		
		print 'CIF width: %d' % parsed.width
		print 'CIF height: %d' % parsed.height
		
		self.rebuild_layer_lists(False)
		# Make sizes the furthest point found
		for layer in self.layers + [self.labels]:
			#print 'Setting %s to %s' % (layer.name, parsed.width)
			layer.width = parsed.width
			layer.height = parsed.height
		
		def add_cif_polygons(uv_layer, cif_layer):
			print '%s: adding %d boxes' % (uv_layer.name, len(cif_layer.boxes)) 
			for box in cif_layer.boxes:
				'''
				CIF uses lower left coordinate system
				Convert to internal representation, upper left
				
				UL
					Vertical
						B 22 94 787 2735
					Horizontal
						B 116 22 740 2793
				'''
				#print '.',
				if False:
					print 'start'
					print box.xpos
					print box.ypos
					print box.width
					print box.height
				# FIXME: change this into one operation since this now takes non-negligible amount of time
				#uvp = UVPolygon.from_rect(box.xpos, box.ypos, box.width, box.height)
				uvp = UVPolygon.from_rect_ex(box.xpos, box.ypos, box.width, box.height, flip_height = uv_layer.height)
				if False:
					print uvp
					uvp.show()
				#uvp.flip_horizontal(uv_layer.height)
				#print uvp
				#uvp.show()
				uv_layer.add_uvpolygon(uvp)
				#sys.exit(1)
			# uv_layer.show()
			#sys.exit(1)
			
		print 'Width: %d, height: %d' % (parsed.width, parsed.height)
		print 'Parsed labels: %d' % len(parsed.labels)
		for label in parsed.labels:
			# Make it a smallish object
			# Really 1 pix should be fine...but I'm more afraid of corner cases breaking things
			# Get it working first and then debug corner cases if needed
			# Maybe length should be related to text length
			uvpoly = UVPolygon.from_rect_ex(label.x, label.y, 20, 20, flip_height = parsed.height)
			uvpoly.text = label.text
			print uvpoly 
			#uvpoly.show()
			self.labels.add_uvpolygon(uvpoly)
		#self.labels.show()
		#sys.exit(1)
				
		for layer_id in parsed.layers:
			layer = parsed.layers[layer_id]
			bench = Benchmark()
			# NMOS metal
			if layer_id == CIFLayer.NM:
				add_cif_polygons(self.metal, layer)
			# NMOS poly
			elif layer_id == CIFLayer.NP:
				add_cif_polygons(self.polysilicon, layer)
			# NMOS diffusion
			elif layer_id == CIFLayer.ND:
				add_cif_polygons(self.diffusion, layer)
			# NMOS contact
			elif layer_id == CIFLayer.NC:
				add_cif_polygons(self.vias, layer)
			else:
				raise Exception('Unsupported layer type %s' % repr(layer_id))
			print bench
			
		#self.compute_wh()
		self.init()
Пример #14
0
    def run(self):
        bench = Benchmark()

        # The following will assume all of the images have the same size
        self.verify_images()

        # Copy project so we can trash it
        self.opt_project = self.project.copy()
        self.prepare_pto(self.opt_project)

        print 'Building image coordinate map'
        i_fns = []
        for il in self.opt_project.image_lines:
            i_fns.append(il.get_name())
        self.icm = ImageCoordinateMap.from_file_names(i_fns)
        print 'Built image coordinate map'

        if self.icm.width() <= self.tw:
            raise Exception('Decrease tile width')
        if self.icm.height() <= self.th:
            raise Exception('Decrease tile height')

        order = 2
        '''
        Phase 1: baseline
        Fully optimize a region in the center of our pano
        '''
        print 'Phase 1: baseline'
        x0 = (self.icm.width() - self.tw) / 2
        if x0 % order != 0:
            x0 += 1
        x1 = x0 + self.tw - 1
        y0 = (self.icm.height() - self.th) / 2
        if y0 % order != 0:
            y0 += 1
        y1 = y0 + self.th - 1
        (center_pto, center_cplis) = self.partial_optimize(x0, x1, y0, y1)
        merge_pto(center_pto, self.opt_project, center_cplis)
        '''
        Phase 2: predict
        Now use base center project to predict optimization positions for rest of project
        Assume that scanning left/right and that backlash will cause rows to alternate ("order 2")
        Note this will also fill in position estimates for unmatched images
        x = c0 * c + c1 * r + c2
        y = c3 * c + c4 * r + c5
        XXX: is there reason to have order 2 y coordinates?
        '''
        print 'Phase 2: predict'
        ((c0s, c1s, c2s), (c3s, c4s, c5s)) = linearize(self.opt_project,
                                                       center_pto,
                                                       allow_missing=False,
                                                       order=order)
        # Exclude filenames directly optimized
        center_is = set()
        for il in center_pto.get_image_lines():
            center_is.add(self.opt_project.i2i(center_pto, il.get_index()))
        for row in xrange(self.icm.width()):
            for col in xrange(self.icm.height()):
                fn = self.icm.get_image(col, row)
                il = self.project.img_fn2l(fn)
                # Skip directly optimized lines
                if il.get_index() in center_is:
                    continue
                # Otherwise predict position
                x = c0s[col % order] * col + c1s[col % order] * row + c2s[
                    col % order]
                il.set_variable('d', x)
                y = c3s[row % order] * col + c4s[row % order] * row + c5s[
                    row % order]
                il.set_variable('e', y)
        '''
        Phase 3: optimize
        Moving out from center, optimize sub-sections based off of prediction
        Move in a cross pattern
            Left
            Right
            Up
            Down
            Expand scope
        '''
        '''
        x0 = self.icm.width() / 2
        if x0 % order != 0:
            x0 += 1
        x1 = x0 + self.tw - 1
        y0 = self.icm.height() / 2
        if y0 % order != 0:
            y0 += 1
        y1 = y0 + self.th - 1
        (center_pto, center_cplis) = self.partial_optimize(x0, x1, y0, y1)
        merge_pto(center_pto, self.opt_project, center_cplis)
        '''

        if self.debug:
            print self.project

        bench.stop()
        print 'Optimized project in %s' % bench
Пример #15
0
	def init(self):
		set_debug_width(self.metal.width)
		set_debug_height(self.metal.height)
		#print g_width, g_height
		#sys.exit(1)
	
		self.default_layer_names()
	
		# Clip as early as possible to avoid extra operations
		self.clip()
		
		self.color_layers()
	
		self.metal.index = Layer.METAL
		
		if self.metal_gnd:
			self.metal_gnd.potential = Net.GND
			self.metal_gnd.index = Layer.METAL
		if self.metal_vcc:
			self.metal_vcc.potential = Net.VCC
			self.metal_vcc.index = Layer.METAL
		
		self.polysilicon.index = Layer.POLYSILICON
		
		# visual6502 net numbers seem to start at 1, not 0
		self.min_net_number = 1
				
		self.transdefs = Transdefs()
		
		self.reset_net_number()
		# Skip some checks before nets are setup, but make the reference availible
		self.nets = None
		#self.polygon_nets = dict()
		self.remove_polygon = self.remove_polygon_no_nets
		
		self.vdd = None
		self.vss = None
		
		# Deals with small non-intersecting delta issues, but does distort the result
		print 'Enlarging layers...'
		bench = Benchmark()
		for layer in self.layers:
			layer.enlarge(None, 1.0)
		print 'Layers enlarged in %s' % repr(bench)
		
		# Must be done before projrection or can result in complex geometries
		# Well you can still get them, but its much easier if you don't do this first
		bench = Benchmark()
		self.condense_polygons()
		print 'Polygons condensed in %s' % repr(bench)

		# net to set of polygons
		# Used for merging nets
		# number to net object
		self.nets = Nets()
		self.remove_polygon = self.remove_polygon_regular
		
		if Options.transistors_by_intersect:
			self.project_diffusion()
		#print 'Polygons: %d' % len(self.diffusion.polygons)
		#self.diffusion.show_polygons()
		#sys.exit(1)
		#self.diffusion.index = Layer.UNKNOWN_DIFFUSION


		#self.buried_contacts = Layer(Options.DEFAULT_IMAGE_FILE_BURIED_CONTACTS)
		#self.transistors = Layer(Options.DEFAULT_IMAGE_FILE_TRANSISTORS)
		self.transistors = Transistors()
		
		self.rebuild_layer_lists()
		
		self.verify_layer_sizes_after_load()
		
		for layer in self.layers:
			layer.show()
Пример #16
0
	def try_supertile(self, x0, x1, y0, y1):
		'''x0/1 and y0/1 are global absolute coordinates'''
		# First generate all of the valid tiles across this area to see if we can get any useful work done?
		# every supertile should have at least one solution or the bounds aren't good
		
		bench = Benchmark()
		try:
			temp_file = ManagedTempFile.get(None, '.tif')

			bounds = [x0, x1, y0, y1]
			#out_name_base = "%s/r%03d_c%03d" % (self.out_dir, row, col)
			#print 'Working on %s' % out_name_base
			stitcher = PartialStitcher(self.pto, bounds, temp_file.file_name)
			if self.dry:
				print 'Dry: skipping partial stitch'
				stitcher = None
			else:
				stitcher.run()
		
			print
			print 'Phase 3: loading supertile image'
			if self.dry:
				print 'Dry: skipping loading PTO'
				img = None
			else:
				img = PImage.from_file(temp_file.file_name)
				print 'Supertile width: %d, height: %d' % (img.width(), img.height())
			new = 0
		
			
		
			'''
			A tile is valid if its in a safe location
			There are two ways for the location to be safe:
			-No neighboring tiles as found on canvas edges
			-Sufficiently inside the blend area that artifacts should be minimal
			'''
			gen_tiles = 0
			print
			# TODO: get the old info back if I miss it after yield refactor
			print 'Phase 4: chopping up supertile'
			self.msg('step(x: %d, y: %d)' % (self.tw, self.th), 3)
			#self.msg('x in xrange(%d, %d, %d)' % (xt0, xt1, self.tw), 3)
			#self.msg('y in xrange(%d, %d, %d)' % (yt0, yt1, self.th), 3)
		
			for (y, x) in self.gen_supertile_tiles(x0, x1, y0, y1):	
				# If we made it this far the tile can be constructed with acceptable enblend artifacts
				row = self.y2row(y)
				col = self.x2col(x)
			
				# Did we already do this tile?
				if self.is_done(row, col):
					# No use repeating it although it would be good to diff some of these
					print 'Rejecting tile x%d, y%d / r%d, c%d: already done' % (x, y, row, col)
					continue
			
				# note that x and y are in whole pano coords
				# we need to adjust to our frame
				# row and col on the other hand are used for global naming
				self.make_tile(img, x - x0, y - y0, row, col)
				gen_tiles += 1
			bench.stop()
			print 'Generated %d new tiles for a total of %d / %d in %s' % (gen_tiles, len(self.closed_list), self.net_expected_tiles, str(bench))
			if gen_tiles == 0:
				raise Exception("Didn't generate any tiles")
			# temp_file should be automatically deleted upon exit
		except:
			print 'Supertile failed at %s' % bench
			raise
Пример #17
0
    def run(self):
        '''
        The base Hugin project seems to work if you take out a few things:
        Eb1 Eev0 Er1 Ra0 Rb0 Rc0 Rd0 Re0 Va1 Vb0 Vc0 Vd0 Vx-0 Vy-0
        So say generate a project file with all of those replaced
        
        In particular we will generate new i lines
        To keep our original object intact we will instead do a diff and replace the optimized things on the old project
        
        
        Output is merged into the original file and starts after a line with a single *
        Even Hugin wpon't respect this optimization if loaded in as is
        Gives lines out like this
        
        o f0 r0 p0 y0 v51 a0.000000 b0.000000 c0.000000 g-0.000000 t-0.000000 d-0.000000 e-0.000000 u10 -buf 
        These are the lines we care about
        
        C i0 c0  x3996.61 y607.045 X3996.62 Y607.039  D1.4009 Dx-1.15133 Dy0.798094
        Where D is the magnitutde of the distance and x and y are the x and y differences to fitted solution
        
        There are several other lines that are just the repeats of previous lines
        '''
        bench = Benchmark()

        # The following will assume all of the images have the same size
        self.verify_images()

        # Copy project so we can trash it
        project = self.project.copy()
        prepare_pto(project, self.reoptimize)

        pre_run_text = project.get_text()
        if 0:
            print
            print
            print 'PT optimizer project:'
            print pre_run_text
            print
            print

        # "PToptimizer out.pto"
        args = ["PToptimizer"]
        args.append(project.get_a_file_name())
        #project.save()
        rc = execute.without_output(args)
        if rc != 0:
            fn = '/tmp/pr0nstitch.optimizer_failed.pto'
            print
            print
            print 'Failed rc: %d' % rc
            print 'Failed project save to %s' % (fn, )
            try:
                open(fn, 'w').write(pre_run_text)
            except:
                print 'WARNING: failed to write failure'
            print
            print
            raise Exception('failed position optimization')
        # API assumes that projects don't change under us
        project.reopen()
        '''
        Line looks like this
        # final rms error 24.0394 units
        '''
        rms_error = None
        for l in project.get_comment_lines():
            if l.find('final rms error') >= 00:
                rms_error = float(l.split()[4])
                break
        print 'Optimize: RMS error of %f' % rms_error
        # Filter out gross optimization problems
        if self.rms_error_threshold and rms_error > self.rms_error_threshold:
            raise Exception("Max RMS error threshold %f but got %f" %
                            (self.rms_error_threshold, rms_error))

        if self.debug:
            print 'Parsed: %s' % str(project.parsed)

        if self.debug:
            print
            print
            print
            print 'Optimized project:'
            print project
            #sys.exit(1)
        print 'Optimized project parsed: %d' % project.parsed

        print 'Merging project...'
        merge_pto(project, self.project)
        if self.debug:
            print self.project

        bench.stop()
        print 'Optimized project in %s' % bench

        # These are beyond this scope
        # Move them somewhere else if we want them
        if 0:
            # The following will assume all of the images have the same size
            self.verify_images()

            # Final dimensions are determined by field of view and width
            # Calculate optimial dimensions
            self.calc_dimensions()

            print 'Centering project...'
            self.center_project()
            '''
            WARNING WARNING WARNING
            The panotools model is too advanced for what I'm doing right now
            The image correction has its merits but is mostly getting in the way to distort images
        
            Therefore, I'd like to complete this to understand the intended use but I suspect its not a good idea
            and I could do my own nona style program much better
            The only downside is that if / when I start doing lens model corrections I'll have to rethink this a little
        
            Actually, a lot of these problems go away if I trim to a single tile
            I can use the same FOV as the source image or something similar
            '''
            print 'Calculating optimial field of view to match desired size...'
            self.calc_fov()
Пример #18
0
    def run(self):
        print 'Input images width %d, height %d' % (self.img_width, self.img_height)
        print 'Output to %s' % self.out_dir
        print 'Super tile width %d, height %d from scalar %d' % (self.stw, self.sth, self.st_scalar_heuristic)
        print 'Super tile x step %d, y step %d' % (self.super_t_xstep, self.super_t_ystep)
        print 'Supertile clip width %d, height %d' % (self.clip_width, self.clip_height)
        
        if self.merge and self.force:
            raise Exception('Can not merge and force')
        
        if not self.dry:
            self.dry = True
            print
            print
            print
            print '***BEGIN DRY RUN***'
            self.run()
            print '***END DRY RUN***'
            print
            print
            print
            self.dry = False
            
        if not self.ignore_crop and self.pto.get_panorama_line().getv('S') is None:
            raise Exception('Not cropped.  Set ignore crop to force continue')

        '''
        if we have a width of 256 and 1 pixel we need total size of 256
        If we have a width of 256 and 256 pixels we need total size of 256
        if we have a width of 256 and 257 pixel we need total size of 512
        '''
        print 'Tile width: %d, height: %d' % (self.tw, self.th)
        print 'Net size: %d width (%d:%d) X %d height (%d:%d) = %d MP' % (self.width(), self.left(), self.right(), self.height(), self.top(), self.bottom(), self.width() * self.height() / 1000000)
        print 'Output image extension: %s' % self.out_extension
        
        self.this_tiles_done = 0
        
        bench = Benchmark()
        
        # Scrub old dir if we don't want it
        if os.path.exists(self.out_dir) and not self.merge:
            if not self.force:
                raise Exception("Must set force to override output")
            if not self.dry:
                shutil.rmtree(self.out_dir)
        if not self.dry and not os.path.exists(self.out_dir):
            os.mkdir(self.out_dir)
        if self.st_dir and not self.dry and not os.path.exists(self.st_dir):
            os.mkdir(self.st_dir)
        # in form (row, col)
        self.closed_list = set()
        
        self.n_expected_sts = len(list(self.gen_supertiles()))
        print 'M: Generating %d supertiles' % self.n_expected_sts
        
        x_tiles_ideal = 1.0 * self.width() / self.tw
        x_tiles = math.ceil(x_tiles_ideal)
        y_tiles_ideal = 1.0 * self.height() / self.th
        y_tiles = math.ceil(y_tiles_ideal)
        self.net_expected_tiles = x_tiles * y_tiles
        ideal_tiles = x_tiles_ideal * y_tiles_ideal
        print 'M: Ideal tiles: %0.3f x, %0.3f y tiles => %0.3f net' % (
                x_tiles_ideal, y_tiles_ideal, ideal_tiles)
        print 'M: Expecting to generate x%d, y%d => %d basic tiles' % (
                x_tiles, y_tiles, self.net_expected_tiles)
        if self.merge:
            self.seed_merge()

        if self.is_full:
            print 'M: full => forcing 1 thread '
            self.threads = 1
        print 'M: Initializing %d workers' % self.threads
        self.workers = []
        for ti in xrange(self.threads):
            print 'Bringing up W%02d' % ti
            w = Worker(ti, self, os.path.join(self.log_dir, 'w%02d.log' % ti))
            self.workers.append(w)
            w.start()

        print
        print
        print
        print 'S' * 80
        print 'M: Serial end'
        print 'P' * 80

        try:
            #temp_file = 'partial.tif'
            self.n_supertiles = 0
            st_gen = self.gen_supertiles()
    
            all_allocated = False
            last_progress = time.time()
            pair_submit = 0
            pair_complete = 0
            idle = False
            while not (all_allocated and pair_complete == pair_submit):
                progress = False
                # Check for completed jobs
                for wi, worker in enumerate(self.workers):
                    try:
                        out = worker.qo.get(False)
                    except Queue.Empty:
                        continue
                    pair_complete += 1
                    what = out[0]
                    progress = True
    
                    if what == 'done':
                        (st_bounds, img_fn) = out[1]
                        print 'MW%d: done w/ submit %d, complete %d' % (wi, pair_submit, pair_complete)
                        # Dry run
                        if img_fn is None:
                            pim = None
                        else:
                            pim = PImage.from_file(img_fn)
                        # hack
                        # ugh remove may be an already existing supertile (not a temp file)
                        #os.remove(img_fn)
                        self.process_image(pim, st_bounds)
                    elif what == 'exception':
                        if not self.ignore_errors:
                            for worker in self.workers:
                                worker.running.clear()
                            # let stdout clear up
                            # (only moderately effective)
                            time.sleep(1)
                        
                        #(_task, e) = out[1]
                        print '!' * 80
                        print 'M: ERROR: MW%d failed w/ exception' % wi
                        (_task, _e, estr) = out[1]
                        print 'M: Stack trace:'
                        for l in estr.split('\n'):
                            print l
                        print '!' * 80
                        if not self.ignore_errors:
                            raise Exception('M: shutdown on worker failure')
                        print 'M WARNING: continuing despite worker failure'
                    else:
                        print 'M: %s' % (out,)
                        raise Exception('M: internal error: bad task type %s' % what)
                    
                    self.st_limit -= 1
                    if self.st_limit == 0:
                        print 'Breaking on ST limit reached'
                        break
    
                # Any workers need more work?
                for wi, worker in enumerate(self.workers):
                    if all_allocated:
                        break
                    if worker.qi.empty():
                        while True:
                            try:
                                st_bounds = st_gen.next()
                            except StopIteration:
                                print 'M: all tasks allocated'
                                all_allocated = True
                                break
            
                            progress = True

                            [x0, x1, y0, y1] = st_bounds
                            self.n_supertiles += 1
                            print 'M: checking supertile x(%d:%d) y(%d:%d)' % (x0, x1, y0, y1)
                            if not self.should_try_supertile(st_bounds):
                                print 'M WARNING: skipping supertile %d as it would not generate any new tiles' % self.n_supertiles
                                continue
                
                            print '*' * 80
                            #print 'W%d: submit %s (%d / %d)' % (wi, repr(pair), pair_submit, n_pairs)
                            print "Creating supertile %d / %d with x%d:%d, y%d:%d" % (self.n_supertiles, self.n_expected_sts, x0, x1, y0, y1)
                            print 'W%d: submit' % (wi,)
                
                            worker.qi.put((st_bounds,))
                            pair_submit += 1
                            break
    
                if progress:
                    last_progress = time.time()
                    idle = False
                else:
                    if not idle:
                        print 'M Server thread idle'
                    idle = True
                    # can take some time, but should be using smaller tiles now
                    if time.time() - last_progress > 4 * 60 * 60:
                        print 'M WARNING: server thread stalled'
                        last_progress = time.time()
                        time.sleep(0.1)

    
            bench.stop()
            print 'M Processed %d supertiles to generate %d new (%d total) tiles in %s' % (self.n_expected_sts, self.this_tiles_done, self.tiles_done(), str(bench))
            tiles_s = self.this_tiles_done / bench.delta_s()
            print 'M %f tiles / sec, %f pix / sec' % (tiles_s, tiles_s * self.tw * self.th)
            
            if self.tiles_done() != self.net_expected_tiles:
                print 'M ERROR: expected to do %d basic tiles but did %d' % (self.net_expected_tiles, self.tiles_done())
                self.dump_open_list()
                raise Exception('State mismatch')
            
            # Gather up supertile filenames generated by workers
            # xxx: maybe we should tell slaves the file they should use?
            for worker in self.workers:
                while True:
                    try:
                        st_fn = worker.st_fns.get(False)
                    except Queue.Empty:
                        break
                    self.st_fns.append(st_fn)
            
        finally:
            self.wkill()
            self.workers = None
Пример #19
0
	def run(self):
		'''
		The base Hugin project seems to work if you take out a few things:
		Eb1 Eev0 Er1 Ra0 Rb0 Rc0 Rd0 Re0 Va1 Vb0 Vc0 Vd0 Vx-0 Vy-0
		So say generate a project file with all of those replaced
		
		In particular we will generate new i lines
		To keep our original object intact we will instead do a diff and replace the optimized things on the old project
		
		
		Output is merged into the original file and starts after a line with a single *
		Even Hugin wpon't respect this optimization if loaded in as is
		Gives lines out like this
		
		o f0 r0 p0 y0 v51 a0.000000 b0.000000 c0.000000 g-0.000000 t-0.000000 d-0.000000 e-0.000000 u10 -buf 
		These are the lines we care about
		
		C i0 c0  x3996.61 y607.045 X3996.62 Y607.039  D1.4009 Dx-1.15133 Dy0.798094
		Where D is the magnitutde of the distance and x and y are the x and y differences to fitted solution
		
		There are several other lines that are just the repeats of previous lines
		'''
		bench = Benchmark()
		
		# The following will assume all of the images have the same size
		self.verify_images()
		
		# Copy project so we can trash it
		project = self.project.to_ptoptimizer()
		prepare_pto(project, self.reoptimize)
		
		pre_run_text = project.get_text()
		if 0:
			print
			print
			print 'PT optimizer project:'
			print pre_run_text
			print
			print
				
		
		# "PToptimizer out.pto"
		args = list()
		args.append(project.get_a_file_name())
		#project.save()
		rc = Execute.show_output("PToptimizer", args)
		if not rc == 0:
			print
			print
			print 'Failed rc: %d' % rc
			print 'Failed project:'
			print pre_run_text
			print
			print
			raise Exception('failed position optimization')
		# API assumes that projects don't change under us
		project.reopen()
		
		'''
		Line looks like this
		# final rms error 24.0394 units
		'''
		rms_error = None
		for l in project.get_comment_lines():
			if l.find('final rms error') >= 00:
				rms_error = float(l.split()[4])
				break
		print 'Optimize: RMS error of %f' % rms_error
		# Filter out gross optimization problems
		if self.rms_error_threshold and rms_error > self.rms_error_threshold:
			raise Exception("Max RMS error threshold %f but got %f" % (self.rms_error_threshold, rms_error))
		
		if self.debug:
			print 'Parsed: %s' % str(project.parsed)

		if self.debug:
			print
			print
			print
			print 'Optimized project:'
			print project
		 	#sys.exit(1)
	 	print 'Optimized project parsed: %d' % project.parsed

		print 'Merging project...'
		merge_pto(project, self.project)
		if self.debug:
			print self.project
		
		bench.stop()
		print 'Optimized project in %s' % bench
		
		# These are beyond this scope
		# Move them somewhere else if we want them
		if 0:
			# The following will assume all of the images have the same size
			self.verify_images()
		
			# Final dimensions are determined by field of view and width
			# Calculate optimial dimensions
			self.calc_dimensions()
		
			print 'Centering project...'
			self.center_project()
		
			'''
			WARNING WARNING WARNING
			The panotools model is too advanced for what I'm doing right now
			The image correction has its merits but is mostly getting in the way to distort images
		
			Therefore, I'd like to complete this to understand the intended use but I suspect its not a good idea
			and I could do my own nona style program much better
			The only downside is that if / when I start doing lens model corrections I'll have to rethink this a little
		
			Actually, a lot of these problems go away if I trim to a single tile
			I can use the same FOV as the source image or something similar
			'''
			print 'Calculating optimial field of view to match desired size...'
			self.calc_fov()
Пример #20
0
	def run(self):
		print 'Input images width %d, height %d' % (self.img_width, self.img_height)
		print 'Output to %s' % self.out_dir
		print 'Super tile width %d, height %d from scalar %d' % (self.stw, self.sth, self.st_scalar_heuristic)
		print 'Super tile x step %d, y step %d' % (self.super_t_xstep, self.super_t_ystep)
		print 'Supertile clip width %d, height %d' % (self.clip_width, self.clip_height)
		
		if self.merge and self.force:
			raise Exception('Can not merge and force')
		
		if not self.dry:
			self.dry = True
			print
			print
			print
			print '***BEGIN DRY RUN***'
			self.run()
			print '***END DRY RUN***'
			print
			print
			print
			self.dry = False
	
		'''
		if we have a width of 256 and 1 pixel we need total size of 256
		If we have a width of 256 and 256 pixels we need total size of 256
		if we have a width of 256 and 257 pixel we need total size of 512
		'''
		print 'Tile width: %d, height: %d' % (self.tw, self.th)
		print 'Net size: %d width (%d:%d) X %d height (%d:%d) = %d MP' % (self.width(), self.left(), self.right(), self.height(), self.top(), self.bottom(), self.width() * self.height() / 1000000)
		print 'Output image extension: %s' % self.out_extension
		
		self.this_tiles_done = 0
		
		bench = Benchmark()
		
		# Scrub old dir if we don't want it
		if os.path.exists(self.out_dir) and not self.merge:
			if self.force:
				if not self.dry:
					shutil.rmtree(self.out_dir)
			else:
				raise Exception("Must set force to override output")
		if not self.dry and not os.path.exists(self.out_dir):
			os.mkdir(self.out_dir)
		# in form (row, col)
		self.closed_list = set()
		
		self.n_expected_sts = len(list(self.gen_supertiles()))
		print 'Generating %d supertiles' % self.n_expected_sts
		
		x_tiles_ideal = 1.0 * self.width() / self.tw
		x_tiles = math.ceil(x_tiles_ideal)
		y_tiles_ideal = 1.0 * self.height() / self.th
		y_tiles = math.ceil(y_tiles_ideal)
		self.net_expected_tiles = x_tiles * y_tiles
		ideal_tiles = x_tiles_ideal * y_tiles_ideal
		print 'Ideal tiles: %0.3f x, %0.3f y tiles => %0.3f net' % (
				x_tiles_ideal, y_tiles_ideal, ideal_tiles)
		print 'Expecting to generate x%d, y%d => %d basic tiles' % (
				x_tiles, y_tiles, self.net_expected_tiles)
		if self.merge:
			self.seed_merge()
		
		#temp_file = 'partial.tif'
		self.n_supertiles = 0
		for supertile in self.gen_supertiles():
			self.n_supertiles += 1
			[x0, x1, y0, y1] = supertile
			
			print 'Checking supertile x(%d:%d) y(%d:%d)' % (x0, x1, y0, y1)
			
			if self.should_try_supertile(x0, x1, y0, y1):
				print
				print
				print "Creating supertile %d / %d with x%d:%d, y%d:%d" % (self.n_supertiles, self.n_expected_sts, x0, x1, y0, y1)
				
				try:
					self.try_supertile(x0, x1, y0, y1)
				except CommandFailed as e:
					if self.ignore_errors:
						# We shouldn't be trying commands during dry but just in case should raise?
						print 'WARNING: got exception trying supertile %d' % (self.n_supertiles)
						traceback.print_exc()
					else:
						raise
			else:
				print 'WARNING: skipping supertile %d as it would not generate any new tiles' % self.n_supertiles

		bench.stop()
		print 'Processed %d supertiles to generate %d new (%d total) tiles in %s' % (self.n_expected_sts, self.this_tiles_done, self.tiles_done(), str(bench))
		tiles_s = self.this_tiles_done / bench.delta_s()
		print '%f tiles / sec, %f pix / sec' % (tiles_s, tiles_s * self.tw * self.th)
		
		if self.tiles_done() != self.net_expected_tiles:
			print 'ERROR: expected to do %d basic tiles but did %d' % (self.net_expected_tiles, self.tiles_done())
			self.dump_open_list()
			raise Exception('State mismatch')
Пример #21
0
class CNCGUI(QMainWindow):
    cncProgress = pyqtSignal(int, int, str, int)
    snapshotCaptured = pyqtSignal(int)
        
    def __init__(self):
        QMainWindow.__init__(self)

        self.cnc_raw = get_cnc()
        self.cnc_raw.on()
        self.cnc_ipc = ControllerThread(self.cnc_raw)
        self.initUI()
        
        # Must not be initialized until after layout is set
        self.gstWindowId = None
        if config['imager']['engine'] == 'gstreamer':
            self.source = gst.element_factory_make("v4l2src", "vsource")
            self.source.set_property("device", "/dev/video0")
            self.setupGst()
        elif config['imager']['engine'] == 'gstreamer-testsrc':
            self.source = gst.element_factory_make("videotestsrc", "video-source")
            self.setupGst()    
        
        self.cnc_ipc.start()
        
        # Offload callback to GUI thread so it can do GUI ops
        self.cncProgress.connect(self.processCncProgress)
        
        if self.cnc_raw is None:
            dbg("Disabling all motion controls on no CNC")
            self.setControlsEnabled(False)
        
        if self.gstWindowId:
            dbg("Starting gstreamer pipeline")
            self.player.set_state(gst.STATE_PLAYING)
        
        if config['cnc']['startup_run']:
            self.run()
        
    def x(self, n):
        self.axes['X'].jog(n)
    
    def y(self, n):
        self.axes['Y'].jog(n)
        
    def z(self, n):
        self.axes['Z'].jog(n)
        
    def reload_obj_cb(self):
        '''Re-populate the objective combo box'''
        self.obj_cb.clear()
        self.obj_config = None
        for objective in config['objective']:
            self.obj_cb.addItem(objective['name'])
    
    def update_obj_config(self):
        '''Make resolution display reflect current objective'''
        self.obj_config = config['objective'][self.obj_cb.currentIndex ()]
        print 'Selected objective %s' % self.obj_config['name']
        self.obj_mag.setText('Magnification: %0.2f' % self.obj_config["mag"])
        self.obj_x_view.setText('X view (um): %0.3f' % self.obj_config["x_view"])
        self.obj_y_view.setText('Y view (um): %0.3f' % self.obj_config["y_view"])
    
    def get_config_layout(self):
        cl = QGridLayout()
        
        row = 0
        l = QLabel("Objective")
        cl.addWidget(l, row, 0)
        self.obj_cb = QComboBox()
        cl.addWidget(self.obj_cb, row, 1)
        self.obj_cb.currentIndexChanged.connect(self.update_obj_config)
        row += 1
        self.obj_mag = QLabel("")
        cl.addWidget(self.obj_mag, row, 1)
        self.obj_x_view = QLabel("")
        row += 1
        cl.addWidget(self.obj_x_view, row, 1)
        self.obj_y_view = QLabel("")
        cl.addWidget(self.obj_y_view, row, 2)
        row += 1
        # seed it
        self.reload_obj_cb()
        self.update_obj_config()
        
        return cl
    
    def get_video_layout(self):
        # Overview
        def low_res_layout():
            layout = QVBoxLayout()
            layout.addWidget(QLabel("Overview"))
            
            # Raw X-windows canvas
            self.video_container = QWidget()
            # Allows for convenient keyboard control by clicking on the video
            self.video_container.setFocusPolicy(Qt.ClickFocus)
            # TODO: do something more proper once integrating vodeo feed
            w, h = 800, 600
            w, h = 3264/8, 2448/8
            self.video_container.setMinimumSize(w, h)
            self.video_container.resize(w, h)
            policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            self.video_container.setSizePolicy(policy)
            
            layout.addWidget(self.video_container)
            
            return layout
        
        # Higher res in the center for focusing
        def high_res_layout():
            layout = QVBoxLayout()
            layout.addWidget(QLabel("Focus"))
            
            # Raw X-windows canvas
            self.video_container2 = QWidget()
            # TODO: do something more proper once integrating vodeo feed
            w, h = 800, 600
            w, h = 3264/8, 2448/8
            self.video_container2.setMinimumSize(w, h)
            self.video_container2.resize(w, h)
            policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            self.video_container2.setSizePolicy(policy)
            
            layout.addWidget(self.video_container2)
            
            return layout
            
        layout = QHBoxLayout()
        layout.addLayout(low_res_layout())
        layout.addLayout(high_res_layout())
        return layout
    
    def setupGst(self):
        '''
        gst-launch v4l2src device=/dev/video0 ! tee ! queue ! videoscale ! capsfilter caps=video/x-raw-yuv ! xvimagesink 
            gst-launch v4l2src device=/dev/video0 ! videoscale ! xvimagesink
        gst-launch v4l2src device=/dev/video0 ! ffmpegcolorspace ! ximagesink
            works...hmm
        
        
        gst-launch v4l2src device=/dev/video0 ! ffmpegcolorspace ! videocrop top=100 left=1 right=4 bottom=0 ! ximagesink
        
        
        sysctl kernel.shmmax=67108864
            cranked up to 128M, no change
            er no that was in KB so that was 128GB...
        sysctl kernel.shmall=32768
            didn't try messing with this
            kernel.shmall = 2097152
            2GB, should be plenty


            
        sysctl kernel.shmmax=67108864
            default: 33554432
        sysctl kernel.shmall=32768
            default: 2097152
            
        Default IPC limits
        root@gespenst:/home/mcmaster# ipcs -l

            ------ Shared Memory Limits --------
            max number of segments = 4096
            max seg size (kbytes) = 32768
            max total shared memory (kbytes) = 8388608
            min seg size (bytes) = 1

            ------ Semaphore Limits --------
            max number of arrays = 128
            max semaphores per array = 250
            max semaphores system wide = 32000
            max ops per semop call = 32
            semaphore max value = 32767

            ------ Messages Limits --------
            max queues system wide = 1471
            max size of message (bytes) = 8192
            default max size of queue (by        
        
        Works fine at med res
        mcmaster@gespenst:~/document/external/pr0ntools/cnc_microscope/snapshot$ gst-launch v4l2src device=/dev/video0 ! videoscale ! xvimagesink 
            Setting pipeline to PAUSED ...
            Pipeline is live and does not need PREROLL ...
            Setting pipeline to PLAYING ...
            New clock: GstSystemClock

            (close window)

            ERROR: from element /GstPipeline:pipeline0/GstXvImageSink:xvimagesink0: Output window was closed
            Additional debug info:
            xvimagesink.c(1326): gst_xvimagesink_handle_xevents (): /GstPipeline:pipeline0/GstXvImageSink:xvimagesink0
            Execution ended after 2888164132 ns.
            Setting pipeline to PAUSED ...
            Setting pipeline to READY ...
            Setting pipeline to NULL ...
            Freeing pipeline ...
        Dies at high res
        mcmaster@gespenst:~/document/external/pr0ntools/cnc_microscope/snapshot$ gst-launch v4l2src device=/dev/video0 ! videoscale ! xvimagesink 
            Setting pipeline to PAUSED ...
            Pipeline is live and does not need PREROLL ...
            Setting pipeline to PLAYING ...
            New clock: GstSystemClock
            ERROR: from element /GstPipeline:pipeline0/GstXvImageSink:xvimagesink0: Failed to create output image buffer of 3264x2448 pixels
            Additional debug info:
            xvimagesink.c(2404): gst_xvimagesink_show_frame (): /GstPipeline:pipeline0/GstXvImageSink:xvimagesink0:
            XServer allocated buffer size did not match input buffer
            Execution ended after 1854135991 ns.
            Setting pipeline to PAUSED ...
            Setting pipeline to READY ...
            Setting pipeline to NULL ...
            Freeing pipeline ...
        On Fedora I had to do something like vmalloc=192M, related?
        
        '''
        
        dbg("Setting up gstreamer pipeline")
        self.gstWindowId = self.video_container.winId()
        self.gstWindowId2 = self.video_container2.winId()

        self.player = gst.Pipeline("player")
        #sinkxv = gst.element_factory_make("xvimagesink")
        sinkx = gst.element_factory_make("ximagesink", 'sinkx_overview')
        sinkx_focus = gst.element_factory_make("ximagesink", 'sinkx_focus')
        #fvidscale_cap = gst.element_factory_make("capsfilter")
        #fvidscale = gst.element_factory_make("videoscale")
        fcs = gst.element_factory_make('ffmpegcolorspace')
        caps = gst.caps_from_string('video/x-raw-yuv')
        #fvidscale_cap.set_property('caps', caps)
        self.stream_queue = gst.element_factory_make("queue")

        self.tee = gst.element_factory_make("tee")

        self.capture_enc = gst.element_factory_make("jpegenc")
        self.capture_sink = gst.element_factory_make("capturesink")
        #self.resizer = gst.element_factory_make("myresize")
        self.resizer =  gst.element_factory_make("videoscale")
        self.snapshotCaptured.connect(self.captureSnapshot)
        self.capture_sink_queue = gst.element_factory_make("queue")

        '''
        Per #gstreamer question evidently v4l2src ! ffmpegcolorspace ! ximagesink
            gst-launch v4l2src ! ffmpegcolorspace ! ximagesink
        allocates memory different than v4l2src ! videoscale ! xvimagesink 
            gst-launch v4l2src ! videoscale ! xvimagesink 
        Problem is that the former doesn't resize the window but allows taking full res pictures
        The later resizes the window but doesn't allow taking full res pictures
        However, we don't want full res in the view window
        '''
        # works at lower res and resizes
        #self.player.add(fvidscale, sinkxv)
        # what was this being used for?
        self.player.add(self.source, self.tee, self.stream_queue)
        # works at full res but doesn't resize
        #self.player.add(fcs, sinkx)
        # compromise
        self.player.add(fcs, self.resizer, sinkx, sinkx_focus)
        
        self.player.add(self.capture_sink_queue, self.capture_enc, self.capture_sink)
        # Video render stream
        gst.element_link_many(self.source, self.tee)
        #gst.element_link_many(self.tee, self.stream_queue, fvidscale, fvidscale_cap, sinkxv)

        self.size_tee = gst.element_factory_make("tee")
        self.size_queue_overview = gst.element_factory_make("queue")
        self.size_queue_focus = gst.element_factory_make("queue")
        # First lets make this identical to keep things simpler
        self.videocrop = gst.element_factory_make("videocrop")
        '''
        TODO: make this more automagic
        w, h = 3264/8, 2448/8 => 408, 306
        Want 3264/2, 2448,2 type resolution
        Image is coming in raw at this point which menas we need to end up with
        408*2, 306*2 => 816, 612
        since its centered crop the same amount off the top and bottom:
        (3264 - 816)/2, (2448 - 612)/2 => 1224, 918
        '''
        self.videocrop.set_property("top", 918)
        self.videocrop.set_property("bottom", 918)
        self.videocrop.set_property("left", 1224)
        self.videocrop.set_property("right", 1224)
        self.scale2 = gst.element_factory_make("videoscale")
        self.player.add(self.size_tee, self.size_queue_overview, self.size_queue_focus, self.videocrop, self.scale2)
        
        gst.element_link_many(self.tee, self.stream_queue, fcs, self.size_tee)
        gst.element_link_many(self.size_tee, self.size_queue_overview, self.resizer, sinkx)
        # gah
        # libv4l2: error converting / decoding frame data: v4l-convert: error destination buffer too small (16777216 < 23970816)
        gst.element_link_many(self.size_tee, self.size_queue_focus, self.videocrop, self.scale2, sinkx_focus)
        #self.resizer_temp = gst.element_factory_make("myresize")
        #self.player.add(self.resizer_temp)
        #gst.element_link_many(self.size_tee, self.size_queue_focus, self.scale2, sinkx_focus)
                
        # Frame grabber stream
        gst.element_link_many(self.tee, self.capture_sink_queue, self.capture_enc, self.capture_sink)
        
        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.enable_sync_message_emission()
        bus.connect("message", self.on_message)
        bus.connect("sync-message::element", self.on_sync_message)
    
    def on_message(self, bus, message):
        t = message.type
        if t == gst.MESSAGE_EOS:
            self.player.set_state(gst.STATE_NULL)
            print "End of stream"
        elif t == gst.MESSAGE_ERROR:
            err, debug = message.parse_error()
            print "Error: %s" % err, debug
            self.player.set_state(gst.STATE_NULL)
        else:
            #print 'Other message: %s' % t
            # Deadlocks upon calling this...
            #print 'Cur state %s' % self.player.get_state()
            ''

    def on_sync_message(self, bus, message):
        if message.structure is None:
            return
        message_name = message.structure.get_name()
        if message_name == "prepare-xwindow-id":
            if message.src.get_name() == 'sinkx_overview':
                win_id = self.gstWindowId
            elif message.src.get_name() == 'sinkx_focus':
                win_id = self.gstWindowId2
            else:
                raise Exception('oh noes')
            
            assert win_id
            imagesink = message.src
            imagesink.set_xwindow_id(win_id)
    
    def home(self):
        dbg('home requested')
        self.cnc_ipc.home()
            
    def go_rel(self):
        dbg('Go rel all requested')
        for k in self.axes:
            axis = self.axes[k]
            axis.go_rel()
    
    def go_abs(self):
        dbg('Go abs all requested')
        for k in self.axes:
            axis = self.axes[k]
            axis.go_abs()
    
    def processCncProgress(self, pictures_to_take, pictures_taken, image, first):
        print 'Processing CNC progress'
        if first:
            print 'First CB with %d items' % pictures_to_take
            self.pb.setMinimum(0)
            self.pb.setMaximum(pictures_to_take)
            self.bench = Benchmark(pictures_to_take)
        else:
            print 'took %s at %d / %d' % (image, pictures_taken, pictures_to_take)
            self.bench.set_cur_items(pictures_taken)
            print self.bench
            
        self.pb.setValue(pictures_taken)
            
    def dry(self):
        return self.dry_cb.isChecked()
    
    def run(self):
        if not self.snapshot_pb.isEnabled():
            print "Wait for snapshot to complete before CNC'ing"
            return
        
        dry = self.dry()
        if dry:
            dbg('Dry run checked')
        rconfig = RunConfig()
        imager = None
        if not dry:
            print 'Loading imager...'
            itype = config['imager']['engine']
            if itype == 'mock':
                imager = MockImager()
            elif itype == "VC":
                if VCImager is None:
                    raise Exception('Import failed')
                imager = VCImager()
            elif itype == 'gstreamer' or itype == 'gstreamer-testsrc':
                class GstImager(Imager):
                    def __init__(self, gui):
                        Imager.__init__(self)
                        self.gui = gui
                        self.image_ready = threading.Event()
                        self.image_id = None
                        
                    def take_picture(self, file_name_out = None):
                        print 'gstreamer imager: taking image to %s' % file_name_out
                        def emitSnapshotCaptured(image_id):
                            print 'Image captured reported: %s' % image_id
                            self.image_id = image_id
                            self.image_ready.set()

                        self.image_id = None
                        self.image_ready.clear()
                        self.gui.capture_sink.request_image(emitSnapshotCaptured)
                        print 'Waiting for next image...'
                        self.image_ready.wait()
                        print 'Got image %s' % self.image_id
                        image = PImage.from_image(self.gui.capture_sink.pop_image(self.image_id))
                        factor = float(config['imager']['scalar'])
                        # Use a reasonably high quality filter
                        scaled = image.get_scaled(factor, Image.ANTIALIAS)
                        if not self.gui.dry():
                            scaled.save(file_name_out)

                imager = GstImager(self)
            else:
                raise Exception('Invalid imager type %s' % itype)
        if not config:
            raise Exception("missing uscope config")
        if not self.obj_config:
            raise Exception("missing obj config")
        
        rconfig.dry = dry
        
        def emitCncProgress(pictures_to_take, pictures_taken, image, first):
            print 'Emitting CNC progress'
            if image is None:
                image = ''
            self.cncProgress.emit(pictures_to_take, pictures_taken, image, first)
        rconfig.progress_cb = emitCncProgress
        
        rconfig.obj_config = self.obj_config            
        # Will be offloaded to its own thread
        # Operations must be blocking
        # We enforce that nothing is running and disable all CNC GUI controls
        rconfig.controller = self.cnc_raw
        rconfig.imager = imager
        
        rconfig.job_name = str(self.job_name_le.text())
        if len(rconfig.job_name) == 0:
            rconfig.job_name = "out"
        if not dry and os.path.exists(rconfig.job_name):
            raise Exception("job name dir %s already exists" % rconfig.job_name)
        
        # If user had started some movement before hitting run wait until its done
        dbg("Waiting for previous movement (if any) to cease")
        self.cnc_ipc.wait_idle()
        
        self.pt = PlannerThread(self, rconfig)
        self.pt.plannerDone.connect(self.plannerDone)
        self.setControlsEnabled(False)
        #eeeee not working as well as I hoped
        # tracked it down to python video capture library operating on windows GUI frame buffer
        # now that switching over to Linux should be fine to be multithreaded
        # If need to use the old layer again should use signals to block GUI for minimum time
        if config['multithreaded']:
            dbg("Running multithreaded")
            self.pt.start()
        else:
            dbg("Running single threaded")
            self.pt.run()
    
    def setControlsEnabled(self, yes):
        self.go_pb.setEnabled(yes)
        self.go_abs_pb.setEnabled(yes)
        self.go_rel_pb.setEnabled(yes)
        self.snapshot_pb.setEnabled(yes)
    
    def plannerDone(self):
        print 'RX planner done'
        # Cleanup camera objects
        self.pt = None
        self.setControlsEnabled(True)
        if config['cnc']['startup_run_exit']:
            print 'Planner debug break on completion'
            os._exit(1)
    
    def stop(self):
        '''Stop operations after the next operation'''
        for axis in self.cnc_ipc.axes:
            axis.stop()
        
    def estop(self):
        '''Stop operations immediately.  Position state may become corrupted'''
        for axis in self.cnc_ipc.axes:
            axis.estop()

    def clear_estop(self):
        '''Stop operations immediately.  Position state may become corrupted'''
        for axis in self.cnc_ipc.axes:
            axis.unestop()
            
    def get_axes_layout(self):
        layout = QHBoxLayout()
        gb = QGroupBox('Axes')
        
        def get_general_layout():
            layout = QVBoxLayout()

            def get_go():
                layout = QHBoxLayout()
                
                self.home_pb = QPushButton("Home all")
                self.home_pb.clicked.connect(self.home)
                layout.addWidget(self.home_pb)
        
                self.go_abs_pb = QPushButton("Go abs all")
                self.go_abs_pb.clicked.connect(self.go_abs)
                layout.addWidget(self.go_abs_pb)
            
                self.go_rel_pb = QPushButton("Go rel all")
                self.go_rel_pb.clicked.connect(self.go_rel)
                layout.addWidget(self.go_rel_pb)
                
                return layout
                
            def get_stop():
                layout = QHBoxLayout()
                
                self.stop_pb = QPushButton("Stop")
                self.stop_pb.clicked.connect(self.stop)
                layout.addWidget(self.stop_pb)
        
                self.estop_pb = QPushButton("Emergency stop")
                self.estop_pb.clicked.connect(self.estop)
                layout.addWidget(self.estop_pb)

                self.clear_estop_pb = QPushButton("Clear e-stop")
                self.clear_estop_pb.clicked.connect(self.clear_estop)
                layout.addWidget(self.clear_estop_pb)
                
                return layout
            
            layout.addLayout(get_go())
            layout.addLayout(get_stop())
            return layout
            
        layout.addLayout(get_general_layout())

        self.axes = dict()
        print 'Axes: %u' % len(self.cnc_ipc.axes)
        for axis in self.cnc_ipc.axes:
            if axis.name == 'Z':
                continue
            axisw = Axis(axis)
            print 'Creating axis GUI %s' % axis.name
            self.axes[axis.name] = axisw
            layout.addWidget(axisw)
        
        gb.setLayout(layout)
        return gb

    def get_snapshot_layout(self):
        gb = QGroupBox('Snapshot')
        layout = QGridLayout()

        snapshot_dir = config['imager']['snapshot_dir']
        if not os.path.isdir(snapshot_dir):
            print 'Snapshot dir %s does not exist' % snapshot_dir
            if os.path.exists(snapshot_dir):
                raise Exception("Snapshot directory is not accessible")
            os.mkdir(snapshot_dir)
            print 'Snapshot dir %s created' % snapshot_dir        

        # nah...just have it in the config
        # d = QFileDialog.getExistingDirectory(self, 'Select snapshot directory', snapshot_dir)

        layout.addWidget(QLabel('File name'), 0, 0)
        self.snapshot_serial = -1
        self.snapshot_fn_le = QLineEdit('')
        self.snapshot_next_serial()
        layout.addWidget(self.snapshot_fn_le, 0, 1)
        self.snapshot_pb = QPushButton("Snapshot")
        self.snapshot_pb.clicked.connect(self.take_snapshot)
        layout.addWidget(self.snapshot_pb, 1, 0, 2, 1)
        
        gb.setLayout(layout)
        return gb
    
    def snapshot_next_serial(self):
        while True:
            self.snapshot_serial += 1
            fn_base = 'snapshot00%u.jpg' % self.snapshot_serial
            fn_full = os.path.join(config['imager']['snapshot_dir'], fn_base)
            if os.path.exists(fn_full):
                print 'Snapshot %s already exists, skipping' % fn_full
                continue
            # Omit base to make GUI easier to read
            self.snapshot_fn_le.setText(fn_base)
            break
    
    def take_snapshot(self):
        print 'Requesting snapshot'
        # Disable until snapshot is completed
        self.snapshot_pb.setEnabled(False)
        def emitSnapshotCaptured(image_id):
            print 'Image captured: %s' % image_id
            self.snapshotCaptured.emit(image_id)
        self.capture_sink.request_image(emitSnapshotCaptured)
    
    def captureSnapshot(self, image_id):
        print 'RX image for saving'
        image = PImage.from_image(self.capture_sink.pop_image(image_id))
        fn_full = os.path.join(config['imager']['snapshot_dir'], str(self.snapshot_fn_le.text()))
        factor = float(config['imager']['scalar'])
        # Use a reasonably high quality filter
        image.get_scaled(factor, Image.ANTIALIAS).save(fn_full)
        
        # That image is done, get read for the next
        self.snapshot_next_serial()
        self.snapshot_pb.setEnabled(True)
    
    def get_scan_layout(self):
        gb = QGroupBox('Scan')
        layout = QGridLayout()

        # TODO: add overlap widgets
        
        layout.addWidget(QLabel('Job name'), 0, 0)
        self.job_name_le = QLineEdit('default')
        layout.addWidget(self.job_name_le, 0, 1)
        self.go_pb = QPushButton("Go")
        self.go_pb.clicked.connect(self.run)
        layout.addWidget(self.go_pb, 1, 0)
        self.pb = QProgressBar()
        layout.addWidget(self.pb, 1, 1)
        layout.addWidget(QLabel('Dry?'), 2, 0)
        self.dry_cb = QCheckBox()
        self.dry_cb.setChecked(config['cnc']['dry'])
        layout.addWidget(self.dry_cb, 2, 1)
        
        gb.setLayout(layout)
        return gb

    def get_bottom_layout(self):
        layout = QHBoxLayout()
        layout.addWidget(self.get_axes_layout())
        def get_lr_layout():
            layout = QVBoxLayout()
            layout.addWidget(self.get_snapshot_layout())
            layout.addWidget(self.get_scan_layout())
            return layout
        layout.addLayout(get_lr_layout())
        return layout
        
    def initUI(self):
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('pr0ncnc')    
        
        # top layout
        layout = QVBoxLayout()
        
        layout.addLayout(self.get_config_layout())
        layout.addLayout(self.get_video_layout())
        layout.addLayout(self.get_bottom_layout())
        
        w = QWidget()
        w.setLayout(layout)
        self.setCentralWidget(w)
        self.show()
        
    def keyPressEvent(self, event):
        '''
        Upper left hand coordinate system
        '''
        # Only control explicitly, don't move by typing accident in other element
        if not self.video_container.hasFocus():
            return
        k = event.key()
        # Ignore duplicates, want only real presses
        if event.isAutoRepeat():
            return
        #inc = 5
        if k == Qt.Key_Left:
            dbg('left')
            if self.axes['X'].jogging:
                return
            self.axes['X'].jogging = True
            self.axes['X'].axis.forever_neg()
        elif k == Qt.Key_Right:
            dbg('right')
            if self.axes['X'].jogging:
                return
            self.axes['X'].jogging = True
            self.axes['X'].axis.forever_pos()
        elif k == Qt.Key_Up:
            if self.axes['Y'].jogging:
                return
            self.axes['Y'].jogging = True
            self.axes['Y'].axis.forever_neg()
        elif k == Qt.Key_Down:
            if self.axes['Y'].jogging:
                return
            self.axes['Y'].jogging = True
            self.axes['Y'].axis.forever_pos()
        # Focus is sensitive...should step slower?
        # worry sonce focus gets re-integrated
        elif k == Qt.Key_PageDown:
            if self.axes['Z'].jogging:
                return
            self.axes['Z'].jogging = True
            self.axes['Z'].axis.forever_neg()
        elif k == Qt.Key_PageUp:
            if self.axes['Z'].jogging:
                return
            self.axes['Z'].jogging = True
            self.axes['Z'].axis.forever_pos()
        elif k == Qt.Key_Escape:
            self.stop()

    def keyReleaseEvent(self, event):
        if not self.video_container.hasFocus():
            return
        k = event.key()
        # Ignore duplicates, want only real presses
        if event.isAutoRepeat():
            return
        #inc = 5
        if k == Qt.Key_Left:
            dbg('left release')
            self.axes['X'].axis.stop()
            self.axes['X'].jogging = False
            self.axes['X'].emit_pos()
        elif k == Qt.Key_Right:
            dbg('right release')
            self.axes['X'].axis.stop()
            self.axes['X'].jogging = False
            self.axes['X'].emit_pos()
        elif k == Qt.Key_Up:
            self.axes['Y'].axis.stop()
            self.axes['Y'].jogging = False
            self.axes['Y'].emit_pos()
        elif k == Qt.Key_Down:
            self.axes['Y'].axis.stop()
            self.axes['Y'].jogging = False
            self.axes['Y'].emit_pos()
        elif k == Qt.Key_PageDown:
            self.axes['Z'].axis.stop()
            self.axes['Z'].jogging = False
            self.axes['Z'].emit_pos()
        elif k == Qt.Key_PageUp:
            self.axes['Z'].axis.stop()
            self.axes['Z'].jogging = False
            self.axes['Z'].emit_pos()
Пример #22
0
    def run(self):
        print 'Input images width %d, height %d' % (self.img_width,
                                                    self.img_height)
        print 'Output to %s' % self.out_dir
        print 'Super tile width %d, height %d from scalar %d' % (
            self.stw, self.sth, self.st_scalar_heuristic)
        print 'Super tile x step %d, y step %d' % (self.super_t_xstep,
                                                   self.super_t_ystep)
        print 'Supertile clip width %d, height %d' % (self.clip_width,
                                                      self.clip_height)

        if self.merge and self.force:
            raise Exception('Can not merge and force')

        if not self.dry:
            self.dry = True
            print
            print
            print
            print '***BEGIN DRY RUN***'
            self.run()
            print '***END DRY RUN***'
            print
            print
            print
            self.dry = False

        if not self.ignore_crop and self.pto.get_panorama_line().getv(
                'S') is None:
            raise Exception('Not cropped.  Set ignore crop to force continue')
        '''
        if we have a width of 256 and 1 pixel we need total size of 256
        If we have a width of 256 and 256 pixels we need total size of 256
        if we have a width of 256 and 257 pixel we need total size of 512
        '''
        print 'Tile width: %d, height: %d' % (self.tw, self.th)
        print 'Net size: %d width (%d:%d) X %d height (%d:%d) = %d MP' % (
            self.width(), self.left(), self.right(), self.height(), self.top(),
            self.bottom(), self.width() * self.height() / 1000000)
        print 'Output image extension: %s' % self.out_extension

        self.this_tiles_done = 0

        bench = Benchmark()

        # Scrub old dir if we don't want it
        if os.path.exists(self.out_dir) and not self.merge:
            if not self.force:
                raise Exception("Must set force to override output")
            if not self.dry:
                shutil.rmtree(self.out_dir)
        if not self.dry and not os.path.exists(self.out_dir):
            os.mkdir(self.out_dir)
        if self.st_dir and not self.dry and not os.path.exists(self.st_dir):
            os.mkdir(self.st_dir)
        # in form (row, col)
        self.closed_list = set()

        self.n_expected_sts = len(list(self.gen_supertiles()))
        print 'M: Generating %d supertiles' % self.n_expected_sts

        x_tiles_ideal = 1.0 * self.width() / self.tw
        x_tiles = math.ceil(x_tiles_ideal)
        y_tiles_ideal = 1.0 * self.height() / self.th
        y_tiles = math.ceil(y_tiles_ideal)
        self.net_expected_tiles = x_tiles * y_tiles
        ideal_tiles = x_tiles_ideal * y_tiles_ideal
        print 'M: Ideal tiles: %0.3f x, %0.3f y tiles => %0.3f net' % (
            x_tiles_ideal, y_tiles_ideal, ideal_tiles)
        print 'M: Expecting to generate x%d, y%d => %d basic tiles' % (
            x_tiles, y_tiles, self.net_expected_tiles)
        if self.merge:
            self.seed_merge()

        if self.is_full:
            print 'M: full => forcing 1 thread '
            self.threads = 1
        print 'M: Initializing %d workers' % self.threads
        self.workers = []
        for ti in xrange(self.threads):
            print 'Bringing up W%02d' % ti
            w = Worker(ti, self, os.path.join(self.log_dir, 'w%02d.log' % ti))
            self.workers.append(w)
            w.start()

        print
        print
        print
        print 'S' * 80
        print 'M: Serial end'
        print 'P' * 80

        try:
            #temp_file = 'partial.tif'
            self.n_supertiles = 0
            st_gen = self.gen_supertiles()

            all_allocated = False
            last_progress = time.time()
            pair_submit = 0
            pair_complete = 0
            idle = False
            while not (all_allocated and pair_complete == pair_submit):
                progress = False
                # Check for completed jobs
                for wi, worker in enumerate(self.workers):
                    try:
                        out = worker.qo.get(False)
                    except Queue.Empty:
                        continue
                    pair_complete += 1
                    what = out[0]
                    progress = True

                    if what == 'done':
                        (st_bounds, img_fn) = out[1]
                        print 'MW%d: done w/ submit %d, complete %d' % (
                            wi, pair_submit, pair_complete)
                        # Dry run
                        if img_fn is None:
                            pim = None
                        else:
                            pim = PImage.from_file(img_fn)
                        # hack
                        # ugh remove may be an already existing supertile (not a temp file)
                        #os.remove(img_fn)
                        self.process_image(pim, st_bounds)
                    elif what == 'exception':
                        if not self.ignore_errors:
                            for worker in self.workers:
                                worker.running.clear()
                            # let stdout clear up
                            # (only moderately effective)
                            time.sleep(1)

                        #(_task, e) = out[1]
                        print '!' * 80
                        print 'M: ERROR: MW%d failed w/ exception' % wi
                        (_task, _e, estr) = out[1]
                        print 'M: Stack trace:'
                        for l in estr.split('\n'):
                            print l
                        print '!' * 80
                        if not self.ignore_errors:
                            raise Exception('M: shutdown on worker failure')
                        print 'M WARNING: continuing despite worker failure'
                    else:
                        print 'M: %s' % (out, )
                        raise Exception('M: internal error: bad task type %s' %
                                        what)

                    self.st_limit -= 1
                    if self.st_limit == 0:
                        print 'Breaking on ST limit reached'
                        break

                # Any workers need more work?
                for wi, worker in enumerate(self.workers):
                    if all_allocated:
                        break
                    if worker.qi.empty():
                        while True:
                            try:
                                st_bounds = st_gen.next()
                            except StopIteration:
                                print 'M: all tasks allocated'
                                all_allocated = True
                                break

                            progress = True

                            [x0, x1, y0, y1] = st_bounds
                            self.n_supertiles += 1
                            print 'M: checking supertile x(%d:%d) y(%d:%d)' % (
                                x0, x1, y0, y1)
                            if not self.should_try_supertile(st_bounds):
                                print 'M WARNING: skipping supertile %d as it would not generate any new tiles' % self.n_supertiles
                                continue

                            print '*' * 80
                            #print 'W%d: submit %s (%d / %d)' % (wi, repr(pair), pair_submit, n_pairs)
                            print "Creating supertile %d / %d with x%d:%d, y%d:%d" % (
                                self.n_supertiles, self.n_expected_sts, x0, x1,
                                y0, y1)
                            print 'W%d: submit' % (wi, )

                            worker.qi.put((st_bounds, ))
                            pair_submit += 1
                            break

                if progress:
                    last_progress = time.time()
                    idle = False
                else:
                    if not idle:
                        print 'M Server thread idle'
                    idle = True
                    # can take some time, but should be using smaller tiles now
                    if time.time() - last_progress > 4 * 60 * 60:
                        print 'M WARNING: server thread stalled'
                        last_progress = time.time()
                        time.sleep(0.1)

            bench.stop()
            print 'M Processed %d supertiles to generate %d new (%d total) tiles in %s' % (
                self.n_expected_sts, self.this_tiles_done, self.tiles_done(),
                str(bench))
            tiles_s = self.this_tiles_done / bench.delta_s()
            print 'M %f tiles / sec, %f pix / sec' % (tiles_s, tiles_s *
                                                      self.tw * self.th)

            if self.tiles_done() != self.net_expected_tiles:
                print 'M ERROR: expected to do %d basic tiles but did %d' % (
                    self.net_expected_tiles, self.tiles_done())
                self.dump_open_list()
                raise Exception('State mismatch')

            # Gather up supertile filenames generated by workers
            # xxx: maybe we should tell slaves the file they should use?
            for worker in self.workers:
                while True:
                    try:
                        st_fn = worker.st_fns.get(False)
                    except Queue.Empty:
                        break
                    self.st_fns.append(st_fn)

        finally:
            self.wkill()
            self.workers = None
Пример #23
0
    def run(self):
        if self.dry:
            print 'Dry run abort'
            return

        bench = Benchmark()

        if not self.output_project_file_name:
            raise Exception("need project file")
        #if not self.output_project_file_name:
        #self.project_temp_file = ManagedTempFile.get()
        #self.output_project_file_name = self.project_temp_file.file_name
        print 'Beginning stitch'
        print 'output project file name: %s' % self.output_project_file_name

        #sys.exit(1)
        self.init_failures()

        # Generate control points and merge them into a master project
        self.control_point_gen = get_cp_engine()
        # How many rows and cols to go to each side
        # If you hand took the pictures, this might suit you
        self.project = PTOProject.from_blank()
        if self.output_project_file_name:
            self.project.set_file_name(self.output_project_file_name)
            if os.path.exists(self.output_project_file_name):
                # Otherwise, we merge into it
                print 'WARNING: removing old project file: %s' % self.output_project_file_name
                os.remove(self.output_project_file_name)
        else:
            self.project.get_a_file_name(None, "_master.pto")

        self.project.image_file_names = self.image_file_names

        try:
            '''
            Generate control points
            '''
            self.generate_control_points()
            print 'Soften try: %s' % (self.soften_try, )
            print 'Soften ok: %s' % (self.soften_ok, )

            print 'Post stitch fixup...'
            optimize_xy_only(self.project)
            fixup_i_lines(self.project)
            fixup_p_lines(self.project)

            print
            print '***PTO project baseline final (%s / %s) data length %d***' % (
                self.project.file_name, self.output_project_file_name,
                len(self.project.get_text()))
            print

            self.failure_json_w()
            print

            # Make dead sure its saved up to date
            self.project.save()
            # having issues with this..
            if self.output_project_file_name and not self.project.file_name == self.output_project_file_name:
                raise Exception('project file name changed %s %s',
                                self.project.file_name,
                                self.output_project_file_name)

            # TODO: missing calc opt size/width/height/fov and crop

        except Exception as e:
            sys.stdout.flush()
            sys.stderr.flush()
            print
            print 'WARNING: stitch FAILED'
            traceback.print_exc()
            try:
                fn = self.project.file_name + ".failed"
                print 'Attempting to save intermediate result to %s' % fn
                self.project.save_as(fn)
            except:
                print 'WARNING: failed intermediate save'
            raise e
        finally:
            bench.stop()
            print 'Stitch done in %s' % bench
Пример #24
0
    def try_supertile(self, st_bounds):
        '''x0/1 and y0/1 are global absolute coordinates'''
        # First generate all of the valid tiles across this area to see if we can get any useful work done?
        # every supertile should have at least one solution or the bounds aren't good
        x0, x1, y0, y1 = st_bounds

        bench = Benchmark()
        try:
            if self.st_dir:
                # nah...tiff takes up too much space
                dst = os.path.join(self.st_dir,
                                   'st_%06dx_%06dy.jpg' % (x0, y0))
                if os.path.exists(dst):
                    # normally this is a .tif so slight loss in quality
                    img = PImage.from_file(dst)
                    print 'supertile short circuit on already existing: %s' % (
                        dst, )
                    return img

            # st_081357x_000587y.jpg
            temp_file = ManagedTempFile.get(None,
                                            '.tif',
                                            prefix_mangle='st_%06dx_%06dy_' %
                                            (x0, y0))

            stitcher = PartialStitcher(self.pto,
                                       st_bounds,
                                       temp_file.file_name,
                                       self.i,
                                       self.running,
                                       pprefix=self.pprefix)
            stitcher.enblend_lock = self.enblend_lock
            stitcher.nona_args = self.nona_args
            stitcher.enblend_args = self.enblend_args

            if self.dry:
                print 'dry: skipping partial stitch'
                stitcher = None
            else:
                stitcher.run()

            print
            print 'phase 3: loading supertile image'
            if self.dry:
                print 'dry: skipping loading PTO'
                img_fn = None
            else:
                if self.st_dir:
                    self.st_fns.put(dst)

                    #shutil.copyfile(temp_file.file_name, dst)
                    args = [
                        'convert', '-quality', '90', temp_file.file_name, dst
                    ]
                    print 'going to execute: %s' % (args, )
                    subp = subprocess.Popen(args,
                                            stdout=None,
                                            stderr=None,
                                            shell=False)
                    subp.communicate()
                    if subp.returncode != 0:
                        raise Exception('Failed to copy stitched file')

                    # having some problems that looks like file isn't getting written to disk
                    # monitoring for such errors
                    # remove if I can root cause the source of these glitches
                    for i in xrange(30):
                        if os.path.exists(dst):
                            break
                        if i == 0:
                            print 'WARNING: soften missing strong blur dest file name %s, waiting a bit...' % (
                                dst, )
                        time.sleep(0.1)
                    else:
                        raise Exception(
                            'Missing soften strong blur output file name %s' %
                            dst)

                # FIXME: was passing loaded image object
                # Directory should delete on exit
                # otherwise parent can delete it
                #img = PImage.from_file(temp_file.file_name)
                img_fn = temp_file.file_name
                # prevent deletion
                temp_file.file_name = ''

                #print 'supertile width: %d, height: %d' % (img.width(), img.height())
                print 'Supertile done w/ fn %s' % (img_fn, )
            return img_fn
        except:
            print 'supertile failed at %s' % (bench, )
            raise
Пример #25
0
    def run(self):
        '''
        The base Hugin project seems to work if you take out a few things:
        Eb1 Eev0 Er1 Ra0 Rb0 Rc0 Rd0 Re0 Va1 Vb0 Vc0 Vd0 Vx-0 Vy-0
        So say generate a project file with all of those replaced
        
        In particular we will generate new i lines
        To keep our original object intact we will instead do a diff and replace the optimized things on the old project
        
        
        Output is merged into the original file and starts after a line with a single *
        Even Hugin wpon't respect this optimization if loaded in as is
        Gives lines out like this
        
        o f0 r0 p0 y0 v51 a0.000000 b0.000000 c0.000000 g-0.000000 t-0.000000 d-0.000000 e-0.000000 u10 -buf 
        These are the lines we care about
        
        C i0 c0  x3996.61 y607.045 X3996.62 Y607.039  D1.4009 Dx-1.15133 Dy0.798094
        Where D is the magnitutde of the distance and x and y are the x and y differences to fitted solution
        
        There are several other lines that are just the repeats of previous lines
        '''
        bench = Benchmark()
        
        # The following will assume all of the images have the same size
        self.verify_images()
        
        # Copy project so we can trash it
        project = self.project.copy()
        prepare_pto(project, self.reoptimize)
        
        pre_run_text = project.get_text()
        if 0:
            print
            print
            print 'PT optimizer project:'
            print pre_run_text
            print
            print
                
        
        # "PToptimizer out.pto"
        args = ["PToptimizer"]
        args.append(project.get_a_file_name())
        #project.save()
        rc = execute.without_output(args)
        if rc != 0:
            fn = '/tmp/pr0nstitch.optimizer_failed.pto'
            print
            print
            print 'Failed rc: %d' % rc
            print 'Failed project save to %s' % (fn,)
            try:
                open(fn, 'w').write(pre_run_text)
            except:
                print 'WARNING: failed to write failure'
            print
            print
            raise Exception('failed position optimization')
        # API assumes that projects don't change under us
        project.reopen()
        
        '''
        Line looks like this
        # final rms error 24.0394 units
        '''
        rms_error = None
        for l in project.get_comment_lines():
            if l.find('final rms error') >= 00:
                rms_error = float(l.split()[4])
                break
        print 'Optimize: RMS error of %f' % rms_error
        # Filter out gross optimization problems
        if self.rms_error_threshold and rms_error > self.rms_error_threshold:
            raise Exception("Max RMS error threshold %f but got %f" % (self.rms_error_threshold, rms_error))
        
        if self.debug:
            print 'Parsed: %s' % str(project.parsed)

        if self.debug:
            print
            print
            print
            print 'Optimized project:'
            print project
            #sys.exit(1)
        print 'Optimized project parsed: %d' % project.parsed

        print 'Merging project...'
        merge_pto(project, self.project)
        if self.debug:
            print self.project
        
        bench.stop()
        print 'Optimized project in %s' % bench
Пример #26
0
    def run(self):
        bench = Benchmark()
        
        # The following will assume all of the images have the same size
        self.verify_images()
        
        # Copy project so we can trash it
        self.opt_project = self.project.copy()
        self.prepare_pto(self.opt_project)

        print 'Building image coordinate map'
        i_fns = []
        for il in self.opt_project.image_lines:
            i_fns.append(il.get_name())
        self.icm = ImageCoordinateMap.from_file_names(i_fns)
        print 'Built image coordinate map'
        
        if self.icm.width() <= self.tw:
            raise Exception('Decrease tile width')
        if self.icm.height() <= self.th:
            raise Exception('Decrease tile height')

        order = 2
        
        
        '''
        Phase 1: baseline
        Fully optimize a region in the center of our pano
        '''
        print 'Phase 1: baseline'
        x0 = (self.icm.width() - self.tw) / 2
        if x0 % order != 0:
            x0 += 1
        x1 = x0 + self.tw - 1
        y0 = (self.icm.height() - self.th) / 2
        if y0 % order != 0:
            y0 += 1
        y1 = y0 + self.th - 1
        (center_pto, center_cplis) = self.partial_optimize(x0, x1, y0, y1)
        merge_pto(center_pto, self.opt_project, center_cplis)


        '''
        Phase 2: predict
        Now use base center project to predict optimization positions for rest of project
        Assume that scanning left/right and that backlash will cause rows to alternate ("order 2")
        Note this will also fill in position estimates for unmatched images
        x = c0 * c + c1 * r + c2
        y = c3 * c + c4 * r + c5
        XXX: is there reason to have order 2 y coordinates?
        '''
        print 'Phase 2: predict'
        ((c0s, c1s, c2s), (c3s, c4s, c5s)) = linearize(self.opt_project, center_pto, allow_missing=False, order=order)
        # Exclude filenames directly optimized
        center_is = set()
        for il in center_pto.get_image_lines():
            center_is.add(self.opt_project.i2i(center_pto, il.get_index()))
        for row in xrange(self.icm.width()):
            for col in xrange(self.icm.height()):
                fn = self.icm.get_image(col, row)
                il = self.project.img_fn2l(fn)
                # Skip directly optimized lines
                if il.get_index() in center_is:
                    continue
                # Otherwise predict position
                x = c0s[col%order] * col + c1s[col%order] * row + c2s[col%order]
                il.set_variable('d', x)
                y = c3s[row%order] * col + c4s[row%order] * row + c5s[row%order]
                il.set_variable('e', y)
        
        
        '''
        Phase 3: optimize
        Moving out from center, optimize sub-sections based off of prediction
        Move in a cross pattern
            Left
            Right
            Up
            Down
            Expand scope
        '''
        '''
        x0 = self.icm.width() / 2
        if x0 % order != 0:
            x0 += 1
        x1 = x0 + self.tw - 1
        y0 = self.icm.height() / 2
        if y0 % order != 0:
            y0 += 1
        y1 = y0 + self.th - 1
        (center_pto, center_cplis) = self.partial_optimize(x0, x1, y0, y1)
        merge_pto(center_pto, self.opt_project, center_cplis)
        '''


        if self.debug:
            print self.project
        
        bench.stop()
        print 'Optimized project in %s' % bench