Example #1
0
    def chainfunc(self, pad, buffer):
        try:
            print 'Got resize buffer'
            # Simplest: just propagate the data
            # self.srcpad.push(buffer)
            
            # Import into PIL and downsize it
            # Raw jpeg to pr0n PIL wrapper object
            print 'resize chain', len(buffer.data), len(buffer.data) / 3264.0
            #open('temp.jpg', 'w').write(buffer.data)
            #io = StringIO.StringIO(buffer.data)
            io = StringIO.StringIO(str(buffer))
            try:
                image = PImage.from_image(Image.open(io))
            except:
                print 'failed to create image'
                return gst.FLOW_OK
            # Use a fast filter since this is realtime
            image = image.get_scaled(0.5, Image.NEAREST)

            output = StringIO.StringIO()
            image.save(output, 'jpeg')
            self.srcpad.push(gst.Buffer(output.getvalue()))
        except:
            traceback.print_exc()
            os._exit(1)
        
        return gst.FLOW_OK
Example #2
0
 def __init__(self, image_in, threads=1):
     self.image_in = image_in
     self.pim = PImage.from_file(self.image_in)
     self.im_ext = ".jpg"
     self.threads = threads
     self.tw = 250
     self.th = 250
Example #3
0
	def verify_layer_sizes(self, images):
		width = None
		height = None
		reference_layer = None
		
		print images		

		# Image can't read SVG
		# We could read the width/height attr still though
		for a_image in images:
			if a_image.find('.svg') < 0:
				raise Exception('Require .svg files, got %s' % a_image )
		return
		
		for image_name in images:
			this_image = PImage.from_file(image_name)
			this_width = this_image.width()
			this_height = this_image.width()
			if width == None:
				width = this_width
				height = this_height
				reference_image = this_image
				continue
			if this_width != width or this_height != height:
				print '%s size (width=%u, height=%u) does not match %s size (width=%u, height=%u)' % \
						(reference_image.file_name(), width, height, \
						this_image.file_name(), this_width, this_height)
				raise Exception("Image size mismatch")
Example #4
0
 def __init__(self, image_in, threads=1):
     self.image_in = image_in
     self.pim = PImage.from_file(self.image_in)
     self.im_ext = '.jpg'
     self.threads = threads
     self.tw = 250
     self.th = 250
Example #5
0
	def add_point(self, y, x, image_file_name):
		image = PImage.from_file(image_file_name)
		point = SpatialPoint(image_file_name, y, x, image.height(), image.width())
		if image_file_name in self.points:
			raise Exception("duplicate key")
		self.points[image_file_name] = point
		#print self.x_list
		#print self.y_list
		self.y_list.add(point)
		self.x_list.add(point)
		self.is_sorted = False
Example #6
0
 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_file_names(file_names_in, depth):
     file_names = list()
     first_parts = set()
     second_parts = set()
     for file_name_in in file_names_in:
         if os.path.isfile(file_name_in):
             if PImage.is_image_filename(file_name_in):
                 file_names.append(file_name_in)
         elif os.path.isdir(file_name_in):            
             if depth:
                 for file_name in os.listdir(file_name_in):
                     file_names.append(get_file_names(os.path.join(file_name_in, file_name), depth - 1))
     return file_names
Example #8
0
	def run(self):
		fn = self.fn
		max_level = self.max_level
		min_level = self.min_level
		out_dir_base = self.out_dir_base

		if min_level is None:
			min_level = 0
		i = PImage.from_file(fn)
		if max_level is None:
			max_level = calc_max_level_from_image(i)
	
		t_width = 250
		t_height = 250
		'''
		Expect that will not need images larger than 1 terapixel in the near future
		sqrt(1 T / (256 * 256)) = 3906, in hex = 0xF42
		so three hex digits should last some time
		'''
		if out_dir_base is None:
			out_dir_base = 'tiles_out/'
	
		'''
		Test file is the carved out metal sample of the 6522
		It is 5672 x 4373 pixels
		I might do a smaller one first
		'''
		if os.path.exists(out_dir_base):
			os.system('rm -rf %s' % out_dir_base)
		os.mkdir(out_dir_base)
		for zoom_level in xrange(max_level, min_level - 1, -1):
			print
			print '************'
			print 'Zoom level %d' % zoom_level
			out_dir = '%s/%d' % (out_dir_base, zoom_level)
			if os.path.exists(out_dir):
				os.system('rm -rf %s' % out_dir)
			os.mkdir(out_dir)
		
			tiler = ImageTiler(i)
			tiler.out_dir = out_dir
			tiler.run()
		
			if zoom_level != min_level:
				# Each zoom level is half smaller than previous
				i = i.get_scaled(0.5, filt=Image.ANTIALIAS)
				if 0:
					i.save('test.jpg')
					sys.exit(1)
Example #9
0
 def get_file_names(file_names_in, depth):
     file_names = list()
     first_parts = set()
     second_parts = set()
     for file_name_in in file_names_in:
         if os.path.isfile(file_name_in):
             if PImage.is_image_filename(file_name_in):
                 file_names.append(file_name_in)
         elif os.path.isdir(file_name_in):
             if depth:
                 for file_name in os.listdir(file_name_in):
                     file_names.append(
                         get_file_names(
                             os.path.join(file_name_in, file_name),
                             depth - 1))
     return file_names
Example #10
0
                    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)
Example #11
0
	def fix_il(il):
		v = il.get_variable('v') 
		if v == None or v >= 180:
			il.set_variable('v', 51)
		
		# These aren't liked: TrX0 TrY0 TrZ0
		il.remove_variable('TrX')
		il.remove_variable('TrY')
		il.remove_variable('TrZ')

		# panotools seems to set these to -1 on some ocassions
		if il.get_variable('w') == None or il.get_variable('h') == None or int(il.get_variable('w')) <= 0 or int(il.get_variable('h')) <= 0:
			img = PImage.from_file(il.get_name())
			il.set_variable('w', img.width())
			il.set_variable('h', img.height())

		for v in 'd e'.split():
			if il.get_variable(v) == None or reoptimize:
				il.set_variable(v, 0)
Example #12
0
     def fix_il(il):
         v = il.get_variable('v') 
         if v == None or v >= 180:
             il.set_variable('v', 51)
         
         # These aren't liked: TrX0 TrY0 TrZ0
         il.remove_variable('TrX')
         il.remove_variable('TrY')
         il.remove_variable('TrZ')
 
         # panotools seems to set these to -1 on some ocassions
         if il.get_variable('w') == None or il.get_variable('h') == None or int(il.get_variable('w')) <= 0 or int(il.get_variable('h')) <= 0:
             img = PImage.from_file(il.get_name())
             il.set_variable('w', img.width())
             il.set_variable('h', img.height())
             
         # Force reoptimize by zeroing optimization result
         il.set_variable('d', 0)
         il.set_variable('e', 0)
Example #13
0
    def fix_il(il):
        v = il.get_variable('v')
        if v == None or v >= 180:
            il.set_variable('v', 51)

        # These aren't liked: TrX0 TrY0 TrZ0
        il.remove_variable('TrX')
        il.remove_variable('TrY')
        il.remove_variable('TrZ')

        # panotools seems to set these to -1 on some ocassions
        if il.get_variable('w') == None or il.get_variable('h') == None or int(
                il.get_variable('w')) <= 0 or int(il.get_variable('h')) <= 0:
            img = PImage.from_file(il.get_name())
            il.set_variable('w', img.width())
            il.set_variable('h', img.height())

        for v in 'd e'.split():
            if il.get_variable(v) == None or reoptimize:
                il.set_variable(v, 0)
Example #14
0
        def fix_il(il):
            v = il.get_variable('v')
            if v == None or v >= 180:
                il.set_variable('v', 51)

            # These aren't liked: TrX0 TrY0 TrZ0
            il.remove_variable('TrX')
            il.remove_variable('TrY')
            il.remove_variable('TrZ')

            # panotools seems to set these to -1 on some ocassions
            if il.get_variable('w') == None or il.get_variable(
                    'h') == None or int(il.get_variable('w')) <= 0 or int(
                        il.get_variable('h')) <= 0:
                img = PImage.from_file(il.get_name())
                il.set_variable('w', img.width())
                il.set_variable('h', img.height())

            # Force reoptimize by zeroing optimization result
            il.set_variable('d', 0)
            il.set_variable('e', 0)
Example #15
0
    def fix_il(il):
        v = il.get_variable('v') 
        if v == None or v >= 180:
            il.set_variable('v', 51)
        
        # panotools seems to set these to -1 on some ocassions
        if il.get_variable('w') == None or il.get_variable('h') == None or int(il.get_variable('w')) <= 0 or int(il.get_variable('h')) <= 0:
            img = PImage.from_file(il.get_name())
            il.set_variable('w', img.width())
            il.set_variable('h', img.height())

        for v in 'd e'.split():
            if il.get_variable(v) == None or reoptimize:
                il.set_variable(v, 0)
                #print 'setting var'
        
        nv = {}
        for k, v in il.variables.iteritems():
            if k in ['w', 'h', 'f', 'Va', 'Vb', 'Vc', 'Vd', 'Vx', 'Vy', 'd', 'e', 'g', 't', 'v', 'Vm', 'n']:
                nv[k] = v
        il.variables = nv
Example #16
0
 def get_image(self):
     if self.image is None:
         self.image = PImage.from_file(self.get_name())
     return self.image
Example #17
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
Example #18
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())
            return img_fn
        except:
            print 'supertile failed at %s' % (bench,)
            raise
Example #19
0
def calc_il_dim(il):
    name = il.get_name()
    pimage = PImage.from_file(name)
    il.set_width(pimage.width())
    il.set_height(pimage.height())
Example #20
0
def rotate_tiles(src_dir, dst_dir, degrees, force=False, rc=False):
    self = Object()

    if src_dir[-1] == '/':
        src_dir = src_dir[0:-1]
    if dst_dir is None:
        dst_dir = src_dir + "-rotated"

    if os.path.exists(dst_dir):
        if force:
            shutil.rmtree(dst_dir)
        else:
            raise Exception('Output alrady exists, must set force')
    if not os.path.exists(dst_dir):
        os.mkdir(dst_dir)

    if degrees == 0:
        print 'WARNING: rotate got 0 degrees, aborting'
        return

    # And that only if the tiles are the same width and height
    # which is not required but the usual
    if not degrees in (90, 180, 270):
        #if not degrees in [180]:
        raise Exception('Only right angle degrees currently supported')

    print 'Rotating dir %s to dir %s %d degrees' % (src_dir, dst_dir, degrees)
    icm = ImageCoordinateMap.from_dir_tagged_file_names(src_dir)

    # Verify uniform size
    print "Verifying tile size...."
    self.tw = None
    self.th = None
    # For the first level we copy things over
    n = 0
    for (src, row, col) in icm.images():
        n += 1
        pi = PImage.from_file(src)
        # I could actually set with / height here but right now this is
        # coming up fomr me accidentially using 256 x 256 tiles when the
        # standard is 250 x 250
        if self.tw is None:
            self.tw = pi.width()
        if self.th is None:
            self.th = pi.height()
        if pi.width() != self.tw or pi.height() != self.th:
            raise Exception('Source image incorrect size')

    this_n = 0
    for (src, src_row, src_col) in icm.images():
        this_n += 1
        extension = '.jpg'
        extension = '.' + src.split('.')[-1]

        if degrees == 180:
            dst_row = icm.height() - src_row - 1
            dst_col = icm.width() - src_col - 1
        elif degrees == 90:
            # r0-c0 => r0-cn
            # r0-cn => rn-cm
            dst_row = src_col
            dst_col = icm.height() - src_row - 1
        elif degrees == 270:
            dst_row = icm.height() - src_col - 1
            dst_col = src_row
        else:
            dst_row = src_row
            dst_col = src_col

        if rc:
            dst = os.path.join(dst_dir,
                               'c%04d_r%04d%s' % (dst_col, dst_row, extension))
        else:
            dst = os.path.join(dst_dir,
                               'y%03d_x%03d%s' % (dst_row, dst_col, extension))
        pi = PImage.from_file(src)
        # rotates CCW...w/e
        pip = pi.rotate(-degrees)
        print '%d / %d: %s => %s' % (this_n, n, src, dst)
        pip.save(dst)
Example #21
0
def calc_il_dim(il):
	name = il.get_name()
	pimage = PImage.from_file(name)
	il.set_width(pimage.width())
	il.set_height(pimage.height())
Example #22
0
			arg_value_bool = True
			if arg.find("=") > 0:
				arg_key = arg.split("=")[0][2:]
				arg_value = arg.split("=")[1]
				if arg_value == "false" or arg_value == "0" or arg_value == "no":
					arg_value_bool = False
			else:
				arg_key = arg[2:]

			if arg_key == "help":
				help()
				sys.exit(0)
			elif arg_key == "result" or arg_key == "out":
				if arg_value.find('.pto') > 0:
					output_project_file_name = arg_value
				elif PImage.is_image_filename(arg_value):
					output_image_file_name = arg_value
				else:
					arg_fatal('unknown file type %s, use explicit version' % arg)
			elif arg_key == "grid-only":
				grid_only = arg_value_bool
			elif arg_key == "algorithm":
				algorithm = arg_value
			elif arg_key == "n-rows":
				n_rows = int(arg_value)
			elif arg_key == "n-cols":
				n_cols = int(arg_value)
			elif arg_key == "alt-rows":
				alt_rows = arg_value_bool
			elif arg_key == "alt-cols":
				alt_cols = arg_value_bool
Example #23
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
Example #24
0
	def __init__(self, image_in):
		self.image_in = image_in
		self.image = PImage.from_file(self.image_in)
		self.set_out_extension('.jpg')
Example #25
0
    def control_points_by_subimage(self,
                                   pair,
                                   image_fn_pair,
                                   subimage_factor=None):
        '''Stitch two images together by cropping to restrict overlap'''

        # subimage_factor: (y, x) overlap percent tuple or none for default
        # pair: pair of row/col or coordinate positions (used to determine relative positions)
        # (0, 0) at upper left
        # image_fn_pair: pair of image file names

        print 'Preparing subimage stitch on %s:%s' % (image_fn_pair[0],
                                                      image_fn_pair[1])
        '''
        Just work on the overlap section, maybe even less
        '''

        images = [
            PImage.from_file(image_file_name)
            for image_file_name in image_fn_pair
        ]
        '''
        image_0 used as reference
        4 basic situations: left, right, up right
        8 extended: 4 basic + corners
        Pairs should be sorted, which simplifies the logic
        '''
        sub_image_0_x_delta = 0
        sub_image_0_y_delta = 0
        sub_image_1_x_end = images[1].width()
        sub_image_1_y_end = images[1].height()

        if subimage_factor:
            y_overlap = subimage_factor[0]
            x_overlap = subimage_factor[1]
        else:
            x_overlap = self.x_overlap
            y_overlap = self.y_overlap

        # image 0 left of image 1?
        if pair.first.col < pair.second.col:
            # Keep image 0 right, image 1 left
            sub_image_0_x_delta = int(images[0].width() * (1.0 - x_overlap))
            sub_image_1_x_end = int(images[1].width() * x_overlap)

        # image 0 above image 1?
        if pair.first.row < pair.second.row:
            # Keep image 0 top, image 1 bottom
            sub_image_0_y_delta = int(images[0].height() * (1.0 - y_overlap))
            sub_image_1_y_end = int(images[1].height() * y_overlap)
        '''
        print 'image 0 x delta: %d, y delta: %d' % (sub_image_0_x_delta, sub_image_0_y_delta)
        Note y starts at top in PIL
        '''
        sub_image_0 = images[0].subimage(sub_image_0_x_delta, None,
                                         sub_image_0_y_delta, None)
        sub_image_1 = images[1].subimage(None, sub_image_1_x_end, None,
                                         sub_image_1_y_end)
        sub_image_0_file = ManagedTempFile.get(None, '.jpg')
        sub_image_1_file = ManagedTempFile.get(None, '.jpg')
        print 'sub image 0: width=%d, height=%d, name=%s' % (sub_image_0.width(
        ), sub_image_0.height(), sub_image_0_file.file_name)
        print 'sub image 1: width=%d, height=%d, name=%s' % (sub_image_1.width(
        ), sub_image_1.height(), sub_image_0_file.file_name)
        #sys.exit(1)
        sub_image_0.image.save(sub_image_0_file.file_name)
        sub_image_1.image.save(sub_image_1_file.file_name)

        sub_image_fn_pair = (sub_image_0_file.file_name,
                             sub_image_1_file.file_name)
        # subimage file name symbolic link to subimage file name
        # this should be taken care of inside of control point actually
        #sub_link_to_sub = dict()
        # subimage to the image it came from
        sub_to_real = dict()
        sub_to_real[sub_image_0_file.file_name] = image_fn_pair[0]
        sub_to_real[sub_image_1_file.file_name] = image_fn_pair[1]

        # Returns a pto project object
        pair_project = self.control_point_gen.generate_core(sub_image_fn_pair)
        if pair_project is None:
            print 'WARNING: failed to gen control points @ %s' % repr(pair)
            return None

        # all we need to do is adjust xy positions
        # afaik above is way overcomplicated
        final_pair_project = pto_unsub(
            pair_project, (sub_image_0_file, sub_image_1_file),
            (sub_image_0_x_delta, sub_image_0_y_delta), sub_to_real)

        # Filenames become absolute
        #sys.exit(1)
        return final_pair_project
Example #26
0
	def control_points_by_subimage(self, pair, pair_images):
		'''
		Just work on the overlap section, maybe even less
		'''
		overlap = 1.0 / 3.0
		
		images = [PImage.from_file(image_file_name) for image_file_name in pair_images]
		
		'''
		image_0 used as reference
		4 basic situations: left, right, up right
		8 extended: 4 basic + corners
		Pairs should be sorted, which simplifies the logic
		'''
		sub_image_0_x_delta = 0
		sub_image_0_y_delta = 0
		sub_image_1_x_end = images[1].width()
		sub_image_1_y_end = images[1].height()

		# image 0 left of image 1?
		if pair.first.col < pair.second.col:
			# Keep image 0 right, image 1 left
			sub_image_0_x_delta = int(images[0].width() * (1.0 - overlap))
			sub_image_1_x_end = int(images[1].width() * overlap)
		
		# image 0 above image 1?
		if pair.first.row < pair.second.row:
			# Keep image 0 top, image 1 bottom
			sub_image_0_y_delta = int(images[0].height() * (1.0 - overlap))
			sub_image_1_y_end = int(images[1].height() * overlap)
		
		'''
		print 'image 0 x delta: %d, y delta: %d' % (sub_image_0_x_delta, sub_image_0_y_delta)
		Note y starts at top in PIL
		'''
		sub_image_0 = images[0].subimage(sub_image_0_x_delta, None, sub_image_0_y_delta, None)
		sub_image_1 = images[1].subimage(None, sub_image_1_x_end, None, sub_image_1_y_end)
		sub_image_0_file = ManagedTempFile.get(None, '.jpg')
		sub_image_1_file = ManagedTempFile.get(None, '.jpg')
		print 'sub image 0: width=%d, height=%d, name=%s' % (sub_image_0.width(), sub_image_0.height(), sub_image_0_file.file_name)
		print 'sub image 1: width=%d, height=%d, name=%s' % (sub_image_1.width(), sub_image_1.height(), sub_image_0_file.file_name)
		#sys.exit(1)
		sub_image_0.image.save(sub_image_0_file.file_name)
		sub_image_1.image.save(sub_image_1_file.file_name)
		
		sub_pair_images = (sub_image_0_file.file_name, sub_image_1_file.file_name)
		# image index to subimage file name link (not symbolic link)
		index_to_sub_file_name = dict()
		imgfile_index = 0
		# subimage file name symbolic link to subimage file name
		# this should be taken care of inside of control point actually
		#sub_link_to_sub = dict()
		# subimage to the image it came from
		sub_to_real = dict()
		sub_to_real[sub_image_0_file.file_name] = pair_images[0]
		sub_to_real[sub_image_1_file.file_name] = pair_images[1]

		'''
		# Hugin project file
		# generated by Autopano

		# Panorama settings:
		p w8000 h1200 f2 v250 n"PSD_mask"

		# input images:
		#-imgfile 2816 704 "/tmp/pr0ntools_C21F246F52E9D691/AA9627DC60B39FC8.jpg"
		o f0 y+0.000000 r+0.000000 p+0.000000 u20 d0.000000 e0.000000 v70.000000 a0.000000 b0.000000 c0.000000
		#-imgfile 2816 704 "/tmp/pr0ntools_C21F246F52E9D691/EDE10C14171B2078.jpg"
		o f0 y+0.000000 r+0.000000 p+0.000000 u20 d0.000000 e0.000000 v70.000000 a0.000000 b0.000000 c0.000000

		# Control points:
		c n0 N1 x1024 y176 X555 Y119
		# Control Point No 0: 1.00000
		c n0 N1 x1047 y160 X578 Y105
		...




		autopano-sift-c style file
		
		# Hugin project file generated by APSCpp

		p f2 w3000 h1500 v360  n"JPEG q90"
		m g1 i0

		i w2816 h704 f0 a0 b-0.01 c0 d0 e0 p0 r0 v180 y0  u10 n"/tmp/pr0ntools_6691335AD228382E.jpg"
		i w2816 h938 f0 a0 b-0.01 c0 d0 e0 p0 r0 v180 y0  u10 n"/tmp/pr0ntools_64D97FF4621BC36E.jpg"

		v p1 r1 y1

		# automatically generated control points
		c n0 N1 x1142.261719 y245.074757 X699.189408 Y426.042661 t0
		c n0 N1 x887.417450 y164.602097 X1952.346197 Y921.975829 t0
		...
		c n0 N1 x823.803714 y130.802771 X674.596763 Y335.994699 t0
		c n0 N1 x1097.192159 y121.170416 X937.394996 Y329.998934 t0

		# :-)
		'''
		fast_pair_project = self.control_point_gen.generate_core(sub_pair_images)
		if fast_pair_project is None:
			print 'WARNING: failed to gen control points @ %s' % repr(pair)
			return None
		out = ''
		part_pair_index = 0
		for line in fast_pair_project.__repr__().split('\n'):
			if len(line) == 0:
				new_line = ''
			# This type of line is gen by autopano-sift-c
			elif line[0] == 'c':
				# c n0 N1 x1142.261719 y245.074757 X699.189408 Y426.042661 t0
				
				'''
				Okay def alphabetical issues
				# Not strictly related to this code, but close enough
				if not index_to_sub_file_name[0] == sub_image_0_file:
					print '0 index indicated file: %s, pair gen order expected %s' % (index_to_sub_file_name[0], sub_image_0_file)
					raise Exception('mismatch')
				if not index_to_sub_file_name[1] == sub_image_1_file:
					print '1 index indicated file: %s, pair gen order expected %s' % (index_to_sub_file_name[1], sub_image_1_file)
					raise Exception('mismatch')
				'''
				
				# Parse
				parts = line.split()
				if not parts[1] == 'n0':
					print parts[1]
					raise Exception('mismatch')
				if not parts[2] == 'N1':
					print parts[2]
					raise Exception('mismatch')
					
				x = float(parts[3][1:])								
				y = float(parts[4][1:])
				X = float(parts[5][1:])
				Y = float(parts[6][1:])
		
				#sub_image_1_x_end = image_1.width()
				#sub_image_1_y_end = image_1.height()

				# Adjust the image towards the upper left hand corner
				if index_to_sub_file_name[0] == sub_image_0_file.file_name:
					# normal adjustment
					x += sub_image_0_x_delta
					y += sub_image_0_y_delta
				elif index_to_sub_file_name[1] == sub_image_0_file.file_name:
					# they got flipped
					X += sub_image_0_x_delta
					Y += sub_image_0_y_delta
				else:
					print index_to_sub_file_name
					print 'index_to_sub_file_name[0]: %s' % repr(index_to_sub_file_name[0])
					print 'index_to_sub_file_name[1]: %s' % repr(index_to_sub_file_name[1])
					print 'sub_image_0_file: %s' % repr(sub_image_0_file)
					print 'sub_image_1_file: %s' % repr(sub_image_1_file)
					raise Exception("confused")
		
				# Write
				new_line = "c n0 N1 x%f y%f X%f Y%f t0" % (x, y, X, Y)
				out += new_line + '\n'
			# This type of line is generated by pto_merge
			elif line[0] == 'i':
				# i w2816 h704 f0 a0 b-0.01 c0 d0 e0 p0 r0 v180 y0  u10 n"/tmp/pr0ntools_6691335AD228382E.jpg"
				new_line = ''
				for part in line.split():
					t = part[0]
					if t == 'i':
						new_line += 'i'
					elif t == 'w':
						new_line += ' w%d' % images[0].width()
					elif t == 'h':
						new_line += ' w%d' % images[0].height()
					elif t == 'n':
						new_line += ' n%s' % pair_images[part_pair_index]
						part_pair_index += 1
					else:
						new_line += ' %s' % part
				print 'new line: %s' % new_line
			# These lines are generated by autopanoaj
			# The comment line is literally part of the file format, some sort of bizarre encoding
			# #-imgfile 2816 704 "/tmp/pr0ntools_2D24DE9F6CC513E0/pr0ntools_6575AA69EA66B3C3.jpg"
			# o f0 y+0.000000 r+0.000000 p+0.000000 u20 d0.000000 e0.000000 v70.000000 a0.000000 b0.000000 c0.000000
			elif line.find('#-imgfile') == 0:
				# Replace pseudo file names with real ones
				new_line = line
				index_to_sub_file_name[imgfile_index] = line.split('"')[1]
				imgfile_index += 1
			else:
				new_line = line
			out += new_line + '\n'
		else:
			out += line + '\n'

		
		for k in sub_to_real:
			v = sub_to_real[k]
			print 'Replacing %s => %s' % (k, v)
			out = out.replace(k, v)

		final_pair_project = PTOProject.from_text(out)
		return final_pair_project
Example #27
0
 def get_image(self):
     if self.image is None:
         self.image = PImage.from_file(self.get_name())
     return self.image
Example #28
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
Example #29
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
Example #30
0
    def control_points_by_subimage(self, pair, image_fn_pair):
        '''Stitch two images together by cropping to restrict overlap'''

        # subimage_factor: (y, x) overlap percent tuple or none for default
        # pair: pair of row/col or coordinate positions (used to determine relative positions)
        # (0, 0) at upper left
        # image_fn_pair: pair of image file names

        print 'Preparing subimage stitch on %s:%s' % (image_fn_pair[0], image_fn_pair[1])
        '''
        Just work on the overlap section, maybe even less
        '''

        images = [PImage.from_file(image_file_name) for image_file_name in image_fn_pair]

        '''
        image_0 used as reference
        4 basic situations: left, right, up right
        8 extended: 4 basic + corners
        Pairs should be sorted, which simplifies the logic
        '''
        sub_image_0_x_delta = 0
        sub_image_0_y_delta = 0
        sub_image_1_x_end = images[1].width()
        sub_image_1_y_end = images[1].height()

        # Add some backlash margin
        # "more overlap" means will try a slightly larger area
        #margin = 0.05
        x_overlap = self.x_overlap
        y_overlap = self.y_overlap

        # image 0 left of image 1?
        if pair.first.col < pair.second.col:
            # Keep image 0 right, image 1 left
            sub_image_0_x_delta = int(images[0].width() * x_overlap)
            sub_image_1_x_end = int(round(images[1].width() * (1.0 - x_overlap)))

        # image 0 above image 1?
        if pair.first.row < pair.second.row:
            # Keep image 0 top, image 1 bottom
            sub_image_0_y_delta = int(images[0].height() * y_overlap)
            sub_image_1_y_end = int(round(images[1].height() * (1.0 - y_overlap)))

        '''
        print 'image 0 x delta: %d, y delta: %d' % (sub_image_0_x_delta, sub_image_0_y_delta)
        Note y starts at top in PIL
        '''
        sub_image_0 = images[0].subimage(sub_image_0_x_delta, None, sub_image_0_y_delta, None)
        sub_image_1 = images[1].subimage(None, sub_image_1_x_end, None, sub_image_1_y_end)
        sub_image_0_file = ManagedTempFile.get(None, '.jpg')
        sub_image_1_file = ManagedTempFile.get(None, '.jpg')
        print 'sub image 0: width=%d, height=%d, name=%s' % (sub_image_0.width(), sub_image_0.height(), sub_image_0_file.file_name)
        print 'sub image 1: width=%d, height=%d, name=%s' % (sub_image_1.width(), sub_image_1.height(), sub_image_1_file.file_name)
        #sys.exit(1)
        sub_image_0.image.save(sub_image_0_file.file_name)
        sub_image_1.image.save(sub_image_1_file.file_name)

        sub_image_fn_pair = (sub_image_0_file.file_name, sub_image_1_file.file_name)
        # subimage file name symbolic link to subimage file name
        # this should be taken care of inside of control point actually
        #sub_link_to_sub = dict()
        # subimage to the image it came from
        sub_to_real = dict()
        sub_to_real[sub_image_0_file.file_name] = image_fn_pair[0]
        sub_to_real[sub_image_1_file.file_name] = image_fn_pair[1]

        # Returns a pto project object
        pair_project = self.control_point_gen.generate_core(sub_image_fn_pair)
        if pair_project is None:
            print 'WARNING: failed to gen control points @ %s' % repr(pair)
            return None

        # all we need to do is adjust xy positions
        # afaik above is way overcomplicated
        final_pair_project = pto_unsub(pair_project, (sub_image_0_file, sub_image_1_file), (sub_image_0_x_delta, sub_image_0_y_delta), sub_to_real)

        # Filenames become absolute
        #sys.exit(1)
        return final_pair_project
Example #31
0
def rotate_tiles(src_dir, dst_dir, degrees, force = False, rc = False):
	self = Object()

	if src_dir[-1] == '/':
		src_dir = src_dir[0:-1]
	if dst_dir is None:
		dst_dir = src_dir + "-rotated"

	if os.path.exists(dst_dir):
		if force:
			shutil.rmtree(dst_dir)
		else:
			raise Exception('Output alrady exists, must set force')
	if not os.path.exists(dst_dir):
		os.mkdir(dst_dir)

	if degrees == 0:
		print 'WARNING: rotate got 0 degrees, aborting'
		return
	
	# And that only if the tiles are the same width and height	
	# which is not required but the usual
	if not degrees in (90, 180, 270):
	#if not degrees in [180]:
		raise Exception('Only right angle degrees currently supported')
	
	print 'Rotating dir %s to dir %s %d degrees' % (src_dir, dst_dir, degrees)
	icm = ImageCoordinateMap.from_dir_tagged_file_names(src_dir)
	
	# Verify uniform size
	print "Verifying tile size...."
	self.tw = None
	self.th = None
	# For the first level we copy things over
	n = 0
	for (src, row, col) in icm.images():
		n += 1
		pi = PImage.from_file(src)
		# I could actually set with / height here but right now this is
		# coming up fomr me accidentially using 256 x 256 tiles when the 
		# standard is 250 x 250
		if self.tw is None:
			self.tw = pi.width()
		if self.th is None:
			self.th = pi.height()
		if pi.width() != self.tw or pi.height() != self.th:
			raise Exception('Source image incorrect size')
		
	this_n = 0
	for (src, src_row, src_col) in icm.images():
		this_n += 1
		extension = '.jpg'
		extension = '.' + src.split('.')[-1]
		
		if degrees == 180:
			dst_row = icm.height() - src_row - 1
			dst_col = icm.width() - src_col - 1
		elif degrees == 90:
			# r0-c0 => r0-cn
			# r0-cn => rn-cm
			dst_row = src_col
			dst_col = icm.height() - src_row - 1
		elif degrees == 270:
			dst_row = icm.height() - src_col - 1
			dst_col = src_row
		else:
			dst_row = src_row
			dst_col = src_col
		
		if rc:
			dst = os.path.join(dst_dir, 'c%04d_r%04d%s' % (dst_col, dst_row, extension))
		else:
			dst = os.path.join(dst_dir, 'y%03d_x%03d%s' % (dst_row, dst_col, extension))
		pi = PImage.from_file(src)
		# rotates CCW...w/e
		pip = pi.rotate(-degrees)
		print '%d / %d: %s => %s' % (this_n, n, src, dst)
		pip.save(dst)
Example #32
0
	def run(self):
		self.prep_out_dir_base()
		
		for self.zoom_level in xrange(self.max_level, self.min_level - 1, -1):
			print
			print '************'
			print 'Zoom level %d' % self.zoom_level
			out_dir = '%s/%d' % (self.out_dir_base, self.zoom_level)
			if os.path.exists(out_dir):
				os.system('rm -rf %s' % out_dir)
			os.mkdir(out_dir)
			
			# For the first level we copy things over
			if self.zoom_level == self.max_level:
				for (img_fn, row, col) in self.map.images():
					dst = self.get_fn(row, col)
					if 0:
						print 'Direct copying %s => %s' % (img_fn, dst)
						shutil.copy(img_fn, dst)
					# This allows to do type conversions if needed
					# Presumably the conversion process for jps should be lossless although I haven't verified
					else:
						print 'Basic conversion %s => %s w/ quality %u' % (img_fn, dst, self.quality)
						pi = PImage.from_file(img_fn)
						# I could actually set with / height here but right now this is
						# coming up fomr me accidentially using 256 x 256 tiles when the 
						# standard is 250 x 250
						if self.t_width is None:
							self.t_width = pi.width()
						if self.t_height is None:
							self.t_height = pi.height()
						if pi.width() != self.t_width or pi.height() != self.t_height:
							raise Exception('Source image incorrect size')
						pi.save(dst, quality=self.quality)
					
			# Additional levels we take the image coordinate map and shrink
			else:
				# Prepare a new image coordinate map so we can form the next tile set
				new_cols = int(math.ceil(1.0 * self.map.width() / self.zoom_factor))
				new_rows = int(math.ceil(1.0 * self.map.height() / self.zoom_factor))
				#print 'Shrink by %s: cols %s => %s, rows %s => %s' % (str(self.zoom_factor), self.map.width(), new_cols, self.map.height(), new_rows)
				if 0:
					print
					self.map.debug_print()
					print
				new_map = ImageCoordinateMap(new_cols, new_rows)
				todo = new_rows * new_cols
				this = 0
				for new_row in xrange(new_rows):
					old_row = new_row * self.zoom_factor
					for new_col in xrange(new_cols):
						this += 1
						old_col = new_col * self.zoom_factor
						#print
						print 'z%d %d/%d: transforming row %d => %d, col %d => %d w/ quality %u' % (self.zoom_level, this, todo, old_row, new_row, old_col, new_col, self.quality)
						# Paste the old (4) images together
						imgp = PImage.from_filename_array([[self.get_old(old_row + 0, old_col + 0), self.get_old(old_row + 0, old_col + 1)],
								[self.get_old(old_row + 1, old_col + 0), self.get_old(old_row + 1, old_col + 1)]])
						if imgp.width() != self.t_width * self.zoom_factor or imgp.height() != self.t_height * self.zoom_factor:
							print 'New image width %d, height: %d from tile width %d, height %d' % (imgp.width(), imgp.height(), self.t_width, self.t_height)
							raise Exception('Combined image incorrect size')
						scaled = imgp.get_scaled(0.5, filt=Image.ANTIALIAS)
						if scaled.width() != self.t_width or scaled.height() != self.t_height:
							raise Exception('Scaled image incorrect size')
						new_fn = self.get_fn(new_row, new_col)
						scaled.save(new_fn, quality=self.quality)
						#sys.exit(1)
						new_map.set_image(new_col, new_row, new_fn)
				# Next shrink will be on the previous tile set, not the original
				print 'Rotating image map'
				self.map = new_map
Example #33
0
	def control_points_by_subimage(self, pair, image_fn_pair, subimage_factor = None):
		'''Stitch two images together by cropping to restrict overlap'''
		
		# subimage_factor: (y, x) overlap percent tuple or none for default
		# pair: pair of row/col or coordinate positions (used to determine relative positions)
		# (0, 0) at upper left
		# image_fn_pair: pair of image file names
		
		print 'Preparing subimage stitch on %s:%s' % (image_fn_pair[0], image_fn_pair[1])
		'''
		Just work on the overlap section, maybe even less
		'''
		
		images = [PImage.from_file(image_file_name) for image_file_name in image_fn_pair]
		
		'''
		image_0 used as reference
		4 basic situations: left, right, up right
		8 extended: 4 basic + corners
		Pairs should be sorted, which simplifies the logic
		'''
		sub_image_0_x_delta = 0
		sub_image_0_y_delta = 0
		sub_image_1_x_end = images[1].width()
		sub_image_1_y_end = images[1].height()

		if subimage_factor:
			y_overlap = subimage_factor[0]
			x_overlap = subimage_factor[1]
		else:
			x_overlap = self.x_overlap
			y_overlap = self.y_overlap

		# image 0 left of image 1?
		if pair.first.col < pair.second.col:
			# Keep image 0 right, image 1 left
			sub_image_0_x_delta = int(images[0].width() * (1.0 - x_overlap))
			sub_image_1_x_end = int(images[1].width() * x_overlap)
		
		# image 0 above image 1?
		if pair.first.row < pair.second.row:
			# Keep image 0 top, image 1 bottom
			sub_image_0_y_delta = int(images[0].height() * (1.0 - y_overlap))
			sub_image_1_y_end = int(images[1].height() * y_overlap)
		
		'''
		print 'image 0 x delta: %d, y delta: %d' % (sub_image_0_x_delta, sub_image_0_y_delta)
		Note y starts at top in PIL
		'''
		sub_image_0 = images[0].subimage(sub_image_0_x_delta, None, sub_image_0_y_delta, None)
		sub_image_1 = images[1].subimage(None, sub_image_1_x_end, None, sub_image_1_y_end)
		sub_image_0_file = ManagedTempFile.get(None, '.jpg')
		sub_image_1_file = ManagedTempFile.get(None, '.jpg')
		print 'sub image 0: width=%d, height=%d, name=%s' % (sub_image_0.width(), sub_image_0.height(), sub_image_0_file.file_name)
		print 'sub image 1: width=%d, height=%d, name=%s' % (sub_image_1.width(), sub_image_1.height(), sub_image_0_file.file_name)
		#sys.exit(1)
		sub_image_0.image.save(sub_image_0_file.file_name)
		sub_image_1.image.save(sub_image_1_file.file_name)
		
		sub_image_fn_pair = (sub_image_0_file.file_name, sub_image_1_file.file_name)
		# subimage file name symbolic link to subimage file name
		# this should be taken care of inside of control point actually
		#sub_link_to_sub = dict()
		# subimage to the image it came from
		sub_to_real = dict()
		sub_to_real[sub_image_0_file.file_name] = image_fn_pair[0]
		sub_to_real[sub_image_1_file.file_name] = image_fn_pair[1]

		# Returns a pto project object
		fast_pair_project = self.control_point_gen.generate_core(sub_image_fn_pair)
		if fast_pair_project is None:
			print 'WARNING: failed to gen control points @ %s' % repr(pair)
			return None
		oto_text = str(fast_pair_project)
		if 0:
			print oto_text
		# are we actually doing anything useful here?
		# The original intention was to make dead sure we had the right file order
		# but I'm pretty sure its consistent and we don't need to parse the comments
		final_pair_project = ajpto2pto_text(oto_text, sub_image_0_file, sub_image_1_file, sub_image_0_x_delta, sub_image_0_y_delta, sub_to_real)
		
		# Filenames become absolute
		#sys.exit(1)
		return final_pair_project