def wfc_execute(WFC_VISUALIZE=False, WFC_PROFILE=False, WFC_LOGGING=False): solver_to_use = "default" #"minizinc" wfc_stats_tracking = { "observations": 0, "propagations": 0, "time_start": None, "time_end": None, "choices_before_success": 0, "choices_per_run": [], "success": False } wfc_stats_data = [] stats_file_name = f"output/stats_{time.time()}.tsv" with open(stats_file_name, "a+") as stats_file: stats_file.write( "id\tname\tsuccess?\tattempts\tobservations\tpropagations\tchoices_to_solution\ttotal_observations_before_solution_in_last_restart\ttotal_choices_before_success_across_restarts\tbacktracking_total\ttime_passed\ttime_start\ttime_end\tfinal_time_end\tgenerated_size\tpattern_count\tseed\tbacktracking?\tallowed_restarts\tforce_the_use_of_all_patterns?\toutput_filename\n" ) default_backtracking = False default_allowed_attempts = 10 default_force_use_all_patterns = False xdoc = ET.ElementTree(file="samples_original.xml") counter = 0 choices_before_success = 0 for xnode in xdoc.getroot(): counter += 1 choices_before_success = 0 if ("#comment" == xnode.tag): continue name = xnode.get('name', "NAME") global hackstring hackstring = name print("< {0} ".format(name), end='') if "backtracking_on" == xnode.tag: default_backtracking = True if "backtracking_off" == xnode.tag: default_backtracking = False if "one_allowed_attempts" == xnode.tag: default_allowed_attempts = 1 if "ten_allowed_attempts" == xnode.tag: default_allowed_attempts = 10 if "force_use_all_patterns" == xnode.tag: default_force_use_all_patterns = True if "overlapping" == xnode.tag: choices_before_success = 0 print("beginning...") print(xnode.attrib) current_output_file_number = 97000 + (counter * 10) wfc_ns = types.SimpleNamespace( output_path="output/", img_filename="samples/" + xnode.get('name', "NAME") + ".png", # name of the input file output_file_number=current_output_file_number, operation_name=xnode.get('name', "NAME"), output_filename="output/" + xnode.get('name', "NAME") + "_" + str(current_output_file_number) + "_" + str(time.time()) + ".png", # name of the output file debug_log_filename="output/" + xnode.get('name', "NAME") + "_" + str(current_output_file_number) + "_" + str(time.time()) + ".log", seed=11975, # seed for random generation, can be any number tile_size=int(xnode.get('tile_size', 1)), # size of tile, in pixels pattern_width=int( xnode.get('N', 2) ), # Size of the patterns we want. 2x2 is the minimum, larger scales get slower fast. channels=3, # Color channels in the image (usually 3 for RGB) symmetry=int(xnode.get('symmetry', 8)), ground=int(xnode.get('ground', 0)), adjacency_directions=dict( enumerate([ CoordXY(x=0, y=-1), CoordXY(x=1, y=0), CoordXY(x=0, y=1), CoordXY(x=-1, y=0) ]) ), # The list of adjacencies that we care about - these will be turned into the edges of the graph periodic_input=string2bool(xnode.get( 'periodicInput', True)), # Does the input wrap? periodic_output=string2bool( xnode.get('periodicOutput', False)), # Do we want the output to wrap? generated_size=(int(xnode.get('width', 48)), int(xnode.get('height', 48))), #Size of the final image screenshots=int( xnode.get('screenshots', 3) ), # Number of times to run the algorithm, will produce this many distinct outputs iteration_limit=int( xnode.get('iteration_limit', 0) ), # After this many iterations, time out. 0 = never time out. allowed_attempts=int( xnode.get('allowed_attempts', default_allowed_attempts) ), # Give up after this many contradictions stats_tracking=wfc_stats_tracking.copy(), backtracking=string2bool( xnode.get('backtracking', default_backtracking)), force_use_all_patterns=default_force_use_all_patterns, force_fail_first_solution=False) wfc_ns.stats_tracking[ "choices_before_success"] += choices_before_success wfc_ns.stats_tracking["time_start"] = time.time() pr = cProfile.Profile() pr.enable() wfc_ns = find_pattern_center(wfc_ns) wfc_ns = wfc.wfc_utilities.load_visualizer(wfc_ns) ## ## Load image and make tile data structures ## wfc_ns.img = load_source_image(wfc_ns.img_filename) wfc_ns.channels = wfc_ns.img.shape[ -1] # detect if it uses channels other than RGB... wfc_ns.tiles = image_to_tiles(wfc_ns.img, wfc_ns.tile_size) wfc_ns.tile_catalog, wfc_ns.tile_grid, wfc_ns.code_list, wfc_ns.unique_tiles = make_tile_catalog( wfc_ns) wfc_ns.tile_ids = { v: k for k, v in dict(enumerate(wfc_ns.unique_tiles[0])).items() } wfc_ns.tile_weights = { a: b for a, b in zip(wfc_ns.unique_tiles[0], wfc_ns.unique_tiles[1]) } if WFC_VISUALIZE: show_input_to_output(wfc_ns) show_extracted_tiles(wfc_ns) show_false_color_tile_grid(wfc_ns) wfc_ns.pattern_catalog, wfc_ns.pattern_weights, wfc_ns.patterns, wfc_ns.pattern_grid = make_pattern_catalog_with_symmetry( wfc_ns.tile_grid, wfc_ns.pattern_width, wfc_ns.symmetry, wfc_ns.periodic_input) if WFC_VISUALIZE: show_pattern_catalog(wfc_ns) adjacency_relations = adjacency_extraction_consistent( wfc_ns, wfc_ns.patterns) if WFC_VISUALIZE: show_adjacencies(wfc_ns, adjacency_relations[:256]) wfc_ns = wfc.wfc_patterns.detect_ground(wfc_ns) pr.disable() screenshots_collected = 0 while screenshots_collected < wfc_ns.screenshots: wfc_logger.info(f"Starting solver #{screenshots_collected}") screenshots_collected += 1 wfc_ns.seed += 100 choice_before_success = 0 #wfc_ns.stats_tracking["choices_before_success"] = 0# += choices_before_success wfc_ns.stats_tracking["time_start"] = time.time() wfc_ns.stats_tracking["final_time_end"] = None # update output name so each iteration has a unique filename output_filename = "output/" + xnode.get( 'name', "NAME" ) + "_" + str(current_output_file_number) + "_" + str( time.time()) + "_" + str( wfc_ns.seed) + ".png", # name of the output file profile_filename = "" + str( wfc_ns.output_path) + "setup_" + str( wfc_ns.output_file_number) + "_" + str( wfc_ns.seed) + "_" + str(time.time()) + "_" + str( wfc_ns.seed) + ".profile" if WFC_PROFILE: with open(profile_filename, 'w') as profile_file: ps = pstats.Stats(pr, stream=profile_file) ps.sort_stats('cumtime', 'ncalls') ps.print_stats(20) solution = None if "minizinc" == solver_to_use: attempt_count = 0 #while attempt_count < wfc_ns.allowed_attempts: # attempt_count += 1 # solution = mz_run(wfc_ns) # solution.wfc_ns.stats_tracking["attempt_count"] = attempt_count # solution.wfc_ns.stats_tracking["choices_before_success"] += solution.wfc_ns.stats_tracking["observations"] else: if True: attempt_count = 0 #print("allowed attempts: " + str(wfc_ns.allowed_attempts)) attempt_wfc_ns = copy.deepcopy(wfc_ns) attempt_wfc_ns.stats_tracking[ "time_start"] = time.time() attempt_wfc_ns.stats_tracking[ "choices_before_success"] = 0 attempt_wfc_ns.stats_tracking[ "total_observations_before_success"] = 0 wfc.wfc_solver.reset_backtracking_count( ) # reset the count of how many times we've backtracked, because multiple attempts are handled here instead of there while attempt_count < wfc_ns.allowed_attempts: attempt_count += 1 print(attempt_count, end=' ') attempt_wfc_ns.seed += 7 # change seed for each attempt... solution = wfc_run(attempt_wfc_ns, visualize=WFC_VISUALIZE, logging=WFC_LOGGING) solution.wfc_ns.stats_tracking[ "attempt_count"] = attempt_count solution.wfc_ns.stats_tracking[ "choices_before_success"] += solution.wfc_ns.stats_tracking[ "observations"] attempt_wfc_ns.stats_tracking[ "total_observations_before_success"] += solution.wfc_ns.stats_tracking[ 'total_observations'] wfc_logger.info("result: {} is {}".format( attempt_count, solution.result)) if solution.result == -2: attempt_count = wfc_ns.allowed_attempts solution.wfc_ns.stats_tracking[ "time_end"] = time.time() wfc_stats_data.append( solution.wfc_ns.stats_tracking.copy()) solution.wfc_ns.stats_tracking[ "final_time_end"] = time.time() print("tracking choices before success...") choices_before_success = solution.wfc_ns.stats_tracking[ "choices_before_success"] time_passed = None if None != solution.wfc_ns.stats_tracking["time_end"]: time_passed = solution.wfc_ns.stats_tracking[ "time_end"] - solution.wfc_ns.stats_tracking[ "time_start"] else: if None != solution.wfc_ns.stats_tracking[ "final_time_end"]: time_passed = solution.wfc_ns.stats_tracking[ "final_time_end"] - solution.wfc_ns.stats_tracking[ "time_start"] print("...finished calculating time passed") #print(wfc_stats_data) print("writing stats...", end='') with open(stats_file_name, "a+") as stats_file: stats_file.write( f"{solution.wfc_ns.output_file_number}\t{solution.wfc_ns.operation_name}\t{solution.wfc_ns.stats_tracking['success']}\t{solution.wfc_ns.stats_tracking['attempt_count']}\t{solution.wfc_ns.stats_tracking['observations']}\t{solution.wfc_ns.stats_tracking['propagations']}\t{solution.wfc_ns.stats_tracking['choices_before_success']}\t{solution.wfc_ns.stats_tracking['total_observations']}\t{attempt_wfc_ns.stats_tracking['total_observations_before_success']}\t{solution.backtracking_total}\t{time_passed}\t{solution.wfc_ns.stats_tracking['time_start']}\t{solution.wfc_ns.stats_tracking['time_end']}\t{solution.wfc_ns.stats_tracking['final_time_end']}\t{solution.wfc_ns.generated_size}\t{len(solution.wfc_ns.pattern_weights.keys())}\t{solution.wfc_ns.seed}\t{solution.wfc_ns.backtracking}\t{solution.wfc_ns.allowed_attempts}\t{solution.wfc_ns.force_use_all_patterns}\t{solution.wfc_ns.output_filename}\n" ) print("done") if WFC_VISUALIZE: print("visualize") if None == solution: print("n u l l") #print(solution) print(1) solution_vis = wfc.wfc_solver.render_recorded_visualization( solution.recorded_vis) #print(solution) print(2) video_fn = f"{solution.wfc_ns.output_path}/crystal_example_{solution.wfc_ns.output_file_number}_{time.time()}.mp4" wfc_logger.info("*****************************") wfc_logger.warning(video_fn) print( f"solver recording stack len - {len(solution_vis.solver_recording_stack)}" ) print(solution_vis.solver_recording_stack[0].shape) if len(solution_vis.solver_recording_stack) > 0: wfc_logger.info( solution_vis.solver_recording_stack[0].shape) writer = FFMPEG_VideoWriter(video_fn, [ solution_vis.solver_recording_stack[0].shape[0], solution_vis.solver_recording_stack[0].shape[1] ], 12.0) for img_data in solution_vis.solver_recording_stack: writer.write_frame(img_data) print('!', end='') writer.close() mpy.ipython_display(video_fn, height=700) print("recording done") if WFC_VISUALIZE: solution = wfc_partial_output(solution) show_rendered_patterns(solution, True) print("render to output") render_patterns_to_output(solution, True, False) print("completed") print("\n{0} >".format(name)) elif "simpletiled" == xnode.tag: print("> ", end="\n") continue else: continue
##print(adjacency_grid) ##print(reverse_adjacency_grid) #print(adjacency_index(wfc_ns_chess.generated_size, 2)) #print(reverse_direction_index(wfc_ns_chess.adjacency_directions)) #print(reverse_direction_index(wfc_ns_chess.adjacency_directions)[get_direction_from_offset(wfc_ns_chess.adjacency_directions, (0,-1))]) if __name__ == "__main__": import types test_ns = types.SimpleNamespace(img_filename="red_maze.png", seed=87386, tile_size=1, pattern_width=2, channels=3, adjacency_directions=dict( enumerate([ CoordXY(x=0, y=-1), CoordXY(x=1, y=0), CoordXY(x=0, y=1), CoordXY(x=-1, y=0) ])), periodic_input=True, periodic_output=True, generated_size=(3, 3), screenshots=1, iteration_limit=0, allowed_attempts=1) test_ns = wfc_utilities.find_pattern_center(test_ns) test_ns = wfc_utilities.load_visualizer(test_ns) test_ns.img = load_source_image(test_ns.img_filename) test_ns.tile_catalog, test_ns.tile_grid, test_ns.code_list, test_ns.unique_tiles = make_tile_catalog( test_ns)
def show_adjacencies(wfc_ns, adjacency_relations_list): try: figadj = figure(figsize=(12, 1 + len(adjacency_relations_list)), edgecolor='b') title('Adjacencies') max_offset = max([ abs(x) for x in list( itertools.chain.from_iterable( wfc_ns.adjacency_directions.values())) ]) for i, adj_rel in enumerate(adjacency_relations_list): preview_size = (wfc_ns.pattern_width + max_offset * 2) preview_adj = np.full((preview_size, preview_size), -1, dtype=np.int64) upper_left_of_center = CoordXY( x=max_offset, y=max_offset) #(ns.pattern_width, ns.pattern_width) #print(f"adj_rel: {adj_rel}") blit(preview_adj, wfc_ns.patterns[adj_rel[1]], upper_left_of_center, check=True) blit(preview_adj, wfc_ns.patterns[adj_rel[2]], (upper_left_of_center.y + wfc_ns.adjacency_directions[adj_rel[0]].y, upper_left_of_center.x + wfc_ns.adjacency_directions[adj_rel[0]].x), check=True) ptr = tiles_to_images(wfc_ns, preview_adj, wfc_ns.tile_catalog, wfc_ns.tile_size, visualize=True).astype(np.uint8) subp = subplot(math.ceil(len(adjacency_relations_list) / 4), 4, i + 1) spi = subp.imshow(ptr) spi.axes.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False) title( f'{i}: ({adj_rel[1]} + {adj_rel[2]}) by\n{wfc_ns.adjacency_directions[adj_rel[0]]}', fontsize=10) indicator_rect = matplotlib.patches.Rectangle( (upper_left_of_center.y - 0.51, upper_left_of_center.x - 0.51), wfc_ns.pattern_width, wfc_ns.pattern_width, Fill=False, edgecolor='b', linewidth=3.0, linestyle=':') spi.axes.add_artist(indicator_rect) spi.axes.grid(False) plt.savefig(wfc_ns.output_filename + "_adjacency.pdf", bbox_inches="tight") plt.close() except ValueError as e: print(e)
sp.axes.grid(False) plt.close() # A nice little diagram of our palette of tiles. # # And, just to check that our internal `tile_grid` representation has reasonable values, let's look at it directly. This will be useful if we have to debug the inner workings of our propagator. # In[11]: def show_false_color_tile_grid(img_ns): pl = matshow(img_ns.tile_grid,cmap='gist_ncar',extent=(0,img_ns.tile_grid.shape[1],img_ns.tile_grid.shape[0],0)) title('False Color Map of Tiles in Input Image'); pl.axes.grid(None) #edgecolor('black') if __name__ == "__main__": import types test_ns = types.SimpleNamespace(img_filename = "red_maze.png", seed = 87386, tile_size = 1, pattern_width = 2, channels = 3, adjacency_directions = dict(enumerate([CoordXY(x=0,y=-1),CoordXY(x=1,y=0),CoordXY(x=0,y=1),CoordXY(x=-1,y=0)])), periodic_input = True, periodic_output = True, generated_size = (3,3), screenshots = 1, iteration_limit = 0, allowed_attempts = 1) test_ns = wfc_utilities.find_pattern_center(test_ns) test_ns = wfc_utilities.load_visualizer(test_ns) test_ns.img = load_source_image(test_ns.img_filename) test_ns.tile_catalog, test_ns.tile_grid, test_ns.code_list, test_ns.unique_tiles = make_tile_catalog(test_ns) test_ns.tile_ids = {v:k for k,v in dict(enumerate(test_ns.unique_tiles[0])).items()} test_ns.tile_weights = {a:b for a,b in zip(test_ns.unique_tiles[0], test_ns.unique_tiles[1])} import doctest doctest.testmod()