Exemple #1
0
    def __init__( self, parent = None ):
        super(Window, self).__init__( parent )
        self.setWindowTitle( 'Interactive Distortion Evolver' )

        ### Experiment Configuration
        # ATW: TODO: When we start getting reasonable distortions, there
        # needs to be a method to reload an old population. For now we'll
        # always make a new one.

        self.experiment_data_dir  = "../external/HyperNEAT/NE/HyperNEAT/out/data"
        self.date_specifier = datetime.now().strftime("%y%m%d_%H%M%S")
        self.image_storage = []

        # Initialize HyperNEAT.
        neat.initialize()

        # See if there is an output directory.
        if not os.path.exists(os.getcwd() + "/output"):
            os.mkdir(os.getcwd() + "/output")

        # Load the image experiment.
        self.experiment = neat.setupExperiment(
            "%s/ImageExperiment.dat" % self.experiment_data_dir,
            "output/imageExp_out_%s.xml" % self.date_specifier )

        # Grab the global parameters.
        self.globals = neat.getGlobalParameters()
        population_size = int(self.globals.getParameterValue('PopulationSize'))

        ### GUI Configuration

        # Set default window size.
        self.setFixedSize( 670, 700 )

        # Initialize the list view for the distorted images.
        lv = QListView( )
        lv.setViewMode( QListView.IconMode )
        lv.setUniformItemSizes( True )
        lv.setSelectionRectVisible( True )
        lv.setMovement( QListView.Static )
        lv.setSelectionMode( QListView.MultiSelection )
        lv.setEditTriggers( QListView.CurrentChanged )
        lv.setResizeMode( QListView.Adjust )
        lv.setIconSize( QSize(120, 120) )
        lv.setMinimumSize( 500, 385 )
        lv.setSpacing( 5 )
        lv.setEnabled( False )
        self.population_list = lv

        # Context menu.
        lv.setContextMenuPolicy( Qt.CustomContextMenu )
        lv.connect( lv, SIGNAL('customContextMenuRequested (const QPoint&)'), self.handle_context_menu )

        # Create the population model.
        pm = PopulationModel( population_size )
        self.population_model = pm
        lv.setModel( pm )
        for i in xrange(population_size):
            self.population_model.update_item( i, DummyNetwork( i % 4 + 1 ) )

        # Monitor population list selection changes.
        self.connect(
            lv.selectionModel(),
            SIGNAL('selectionChanged(const QItemSelection &, const QItemSelection &)'),
            self.handle_listview_change )

        # Initialize widgets for displaying the graphic and for choosing
        # a new base image.
        btn_select_image = QPushButton( "Load Image" )
        self.connect( btn_select_image, SIGNAL('released()'), self.select_image )
        lbl_image = QLabel( "Nothing loaded" )
        lbl_image.setFixedSize( 120, 120 )
        self.original_image_label = lbl_image
        image_layout = QVBoxLayout()
        image_layout.addWidget( btn_select_image )
        image_layout.addWidget( lbl_image )

        # Initialize a horizontal layout for the parameters.
        gb = QGroupBox( "Evolution Parameters" )
        gb.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )

        tw = QTableWidget( 1, 2 )
        tw.setHorizontalHeaderLabels(QString("Parameter;Value").split(';'))
        tw.setColumnWidth( 0, 350 )
        tw.horizontalHeader().setStretchLastSection( True )
        self.connect( tw, SIGNAL('itemChanged(QTableWidgetItem *)'), self.handle_parameter_change )
        self.parameter_table = tw

        tw_layout = QVBoxLayout()
        tw_layout.addWidget( tw )
        gb.setLayout( tw_layout )

        param_layout = QHBoxLayout()
        param_layout.addLayout( image_layout )
        param_layout.addWidget( gb )

        # Grab the global parameters.
        parameter_count = self.globals.getParameterCount()
        tw.setRowCount( parameter_count )
        for p in xrange(parameter_count):
            parameter_name = self.globals.getParameterName( p )
            tw.model().setData( tw.model().index( p, 0 ), parameter_name )
            tw.model().setData( tw.model().index( p, 1 ), self.globals.getParameterValue( parameter_name ) )
            index = tw.item( p, 0 )
            index.setFlags( index.flags() ^ Qt.ItemIsEditable )

        # Initialize a horizontal layout for the evolve button.
        btn_evolve = QPushButton( "Shuffle" )
        self.connect( btn_evolve, SIGNAL('released()'), self.evolve_image )
        btn_evolve.setEnabled( False )
        self.btn_evolve = btn_evolve
        self.btn_evolve.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred )

        self.spin_evolve_iterations = QSpinBox()
        self.spin_evolve_iterations.setRange( 1, 100 )
        self.spin_evolve_iterations.setValue( 1 )

        self.cb_cross_correlate = QCheckBox( "X-Corr" )
        self.cb_cross_correlate.setChecked( True )

        control_layout = QHBoxLayout()
        control_layout.addWidget( btn_evolve )
        control_layout.addWidget( self.spin_evolve_iterations )
        control_layout.addWidget( self.cb_cross_correlate )

        # Initialize vertical central layout.
        central_layout = QVBoxLayout()
        central_layout.addLayout( param_layout )
        central_layout.addWidget( lv )
        central_layout.addLayout( control_layout )
        central_widget = QFrame()
        central_widget.setLayout( central_layout )

        self.setCentralWidget( central_widget )

        # Create a menu
        self.image_menu = QMenu("Menu", self)
        self.image_menu_save_image = self.image_menu.addAction("Save Selected Images")
        self.image_menu_save_network = self.image_menu.addAction("Save Selected Neural Network")

        ### Initialization

        # Handle command line parameters.
        if len(sys.argv) >= 2:
            self.select_image(sys.argv[1])

        # Create progress dialog.
        self.progress_dialog = QProgressDialog( self );
        self.progress_dialog.setLabelText( "Evolving population..." )
        self.progress_dialog.setWindowModality( Qt.WindowModal );
        self.progress_dialog.setVisible( False )
        self.progress_dialog.setCancelButton( None )

        # Start evolver thread.
        self.evolve_thread = EvolveThread( self )
        self.evolve_thread.finished_job.connect( self.finish_evolution )
        self.evolve_thread.update_progress.connect( self.update_evolution_progress )
        self.evolve_thread.start()

        # Generate first population.
        self.population = self.experiment.pythonEvaluationSet()
        self.evolve_image()
Exemple #2
0
    def __init__( self, parent = None ):
        super(Window, self).__init__( parent )
        self.setWindowTitle( 'Interactive Distortion Evolver' )

        ### Experiment Configuration
        # ATW: TODO: When we start getting reasonable distortions, there
        # needs to be a method to reload an old population. For now we'll
        # always make a new one.

        self.experiment_data_dir  = "../external/HyperNEAT/NE/HyperNEAT/out/data"
        self.date_specifier = datetime.now().strftime("%y%m%d_%H%M%S")
        self.image_storage = []

        # Initialize HyperNEAT.
        neat.initialize()

        # See if there is an output directory.
        if not os.path.exists(os.getcwd() + "/output"):
            os.mkdir(os.getcwd() + "/output")

        # Load the image experiment.
        self.experiment = neat.setupExperiment(
            "%s/ImageExperiment.dat" % self.experiment_data_dir,
            "output/imageExp_out_%s.xml" % self.date_specifier )

        # Grab the global parameters.
        self.globals = neat.getGlobalParameters()
        population_size = int(self.globals.getParameterValue('PopulationSize'))

        ### GUI Configuration

        # Set default window size.
        self.setFixedSize( 670, 700 )

        # Initialize the list view for the distorted images.
        lv = QListView( )
        lv.setViewMode( QListView.IconMode )
        lv.setUniformItemSizes( True )
        lv.setSelectionRectVisible( True )
        lv.setMovement( QListView.Static )
        lv.setSelectionMode( QListView.MultiSelection )
        lv.setEditTriggers( QListView.CurrentChanged )
        lv.setResizeMode( QListView.Adjust )
        lv.setIconSize( QSize(120, 120) )
        lv.setMinimumSize( 500, 385 )
        lv.setSpacing( 5 )
        lv.setEnabled( False )
        self.population_list = lv

        # Context menu.
        lv.setContextMenuPolicy( Qt.CustomContextMenu )
        lv.customContextMenuRequested.connect(self.handle_context_menu)

        # Create the population model.
        pm = PopulationModel( population_size )
        self.population_model = pm
        lv.setModel( pm )
        for i in xrange(population_size):
            self.population_model.update_item( i, DummyNetwork( i % 4 + 1 ) )

        # Monitor population list selection changes.
        lv.selectionModel().selectionChanged.connect(self.handle_listview_change )

        # Initialize widgets for displaying the graphic and for choosing
        # a new base image.
        btn_select_image = QPushButton( "Load Image" )
        btn_select_image.released.connect(self.select_image)
        lbl_image = QLabel( "Nothing loaded" )
        lbl_image.setFixedSize( 120, 120 )
        self.original_image_label = lbl_image
        image_layout = QVBoxLayout()
        image_layout.addWidget( btn_select_image )
        image_layout.addWidget( lbl_image )

        # Initialize a horizontal layout for the parameters.
        gb = QGroupBox( "Evolution Parameters" )
        gb.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )

        tw = QTableWidget( 1, 2 )
        tw.setHorizontalHeaderLabels("Parameter;Value".split(';'))
        tw.setColumnWidth( 0, 350 )
        tw.horizontalHeader().setStretchLastSection( True )
        tw.itemChanged.connect(self.handle_parameter_change)
        self.parameter_table = tw

        tw_layout = QVBoxLayout()
        tw_layout.addWidget( tw )
        gb.setLayout( tw_layout )

        param_layout = QHBoxLayout()
        param_layout.addLayout( image_layout )
        param_layout.addWidget( gb )

        # Grab the global parameters.
        parameter_count = self.globals.getParameterCount()
        tw.setRowCount( parameter_count )
        for p in xrange(parameter_count):
            parameter_name = self.globals.getParameterName( p )
            tw.model().setData( tw.model().index( p, 0 ), parameter_name )
            tw.model().setData( tw.model().index( p, 1 ), self.globals.getParameterValue( parameter_name ) )
            index = tw.item( p, 0 )
            index.setFlags( index.flags() ^ Qt.ItemIsEditable )

        # Initialize a horizontal layout for the evolve button.
        btn_evolve = QPushButton( "Shuffle" )
        btn_evolve.released.connect(self.evolve_image)
        btn_evolve.setEnabled( False )
        self.btn_evolve = btn_evolve
        self.btn_evolve.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred )

        self.spin_evolve_iterations = QSpinBox()
        self.spin_evolve_iterations.setRange( 1, 100 )
        self.spin_evolve_iterations.setValue( 1 )

        self.cb_cross_correlate = QCheckBox( "X-Corr" )
        self.cb_cross_correlate.setChecked( True )

        control_layout = QHBoxLayout()
        control_layout.addWidget( btn_evolve )
        control_layout.addWidget( self.spin_evolve_iterations )
        control_layout.addWidget( self.cb_cross_correlate )

        # Initialize vertical central layout.
        central_layout = QVBoxLayout()
        central_layout.addLayout( param_layout )
        central_layout.addWidget( lv )
        central_layout.addLayout( control_layout )
        central_widget = QFrame()
        central_widget.setLayout( central_layout )

        self.setCentralWidget( central_widget )

        # Create a menu
        self.image_menu = QMenu("Menu", self)
        self.image_menu_save_image = self.image_menu.addAction("Save Selected Images")
        self.image_menu_save_network = self.image_menu.addAction("Save Selected Neural Network")

        ### Initialization

        # Handle command line parameters.
        if len(sys.argv) >= 2:
            self.select_image(sys.argv[1])

        # Create progress dialog.
        self.progress_dialog = QProgressDialog( self );
        self.progress_dialog.setLabelText( "Evolving population..." )
        self.progress_dialog.setWindowModality( Qt.WindowModal );
        self.progress_dialog.setVisible( False )
        self.progress_dialog.setCancelButton( None )

        # Start evolver thread.
        self.evolve_thread = EvolveThread( self )
        self.evolve_thread.finished_job.connect( self.finish_evolution )
        self.evolve_thread.update_progress.connect( self.update_evolution_progress )
        self.evolve_thread.start()

        # Generate first population.
        self.population = self.experiment.pythonEvaluationSet()
        self.evolve_image()
Exemple #3
0
class Window(QMainWindow):
    def __init__( self, parent = None ):
        super(Window, self).__init__( parent )
        self.setWindowTitle( 'Interactive Distortion Evolver' )

        ### Experiment Configuration
        # ATW: TODO: When we start getting reasonable distortions, there
        # needs to be a method to reload an old population. For now we'll
        # always make a new one.

        self.experiment_data_dir  = "../external/HyperNEAT/NE/HyperNEAT/out/data"
        self.date_specifier = datetime.now().strftime("%y%m%d_%H%M%S")
        self.image_storage = []

        # Initialize HyperNEAT.
        neat.initialize()

        # See if there is an output directory.
        if not os.path.exists(os.getcwd() + "/output"):
            os.mkdir(os.getcwd() + "/output")

        # Load the image experiment.
        self.experiment = neat.setupExperiment(
            "%s/ImageExperiment.dat" % self.experiment_data_dir,
            "output/imageExp_out_%s.xml" % self.date_specifier )

        # Grab the global parameters.
        self.globals = neat.getGlobalParameters()
        population_size = int(self.globals.getParameterValue('PopulationSize'))

        ### GUI Configuration

        # Set default window size.
        self.setFixedSize( 670, 700 )

        # Initialize the list view for the distorted images.
        lv = QListView( )
        lv.setViewMode( QListView.IconMode )
        lv.setUniformItemSizes( True )
        lv.setSelectionRectVisible( True )
        lv.setMovement( QListView.Static )
        lv.setSelectionMode( QListView.MultiSelection )
        lv.setEditTriggers( QListView.CurrentChanged )
        lv.setResizeMode( QListView.Adjust )
        lv.setIconSize( QSize(120, 120) )
        lv.setMinimumSize( 500, 385 )
        lv.setSpacing( 5 )
        lv.setEnabled( False )
        self.population_list = lv

        # Context menu.
        lv.setContextMenuPolicy( Qt.CustomContextMenu )
        lv.connect( lv, SIGNAL('customContextMenuRequested (const QPoint&)'), self.handle_context_menu )

        # Create the population model.
        pm = PopulationModel( population_size )
        self.population_model = pm
        lv.setModel( pm )
        for i in xrange(population_size):
            self.population_model.update_item( i, DummyNetwork( i % 4 + 1 ) )

        # Monitor population list selection changes.
        self.connect(
            lv.selectionModel(),
            SIGNAL('selectionChanged(const QItemSelection &, const QItemSelection &)'),
            self.handle_listview_change )

        # Initialize widgets for displaying the graphic and for choosing
        # a new base image.
        btn_select_image = QPushButton( "Load Image" )
        self.connect( btn_select_image, SIGNAL('released()'), self.select_image )
        lbl_image = QLabel( "Nothing loaded" )
        lbl_image.setFixedSize( 120, 120 )
        self.original_image_label = lbl_image
        image_layout = QVBoxLayout()
        image_layout.addWidget( btn_select_image )
        image_layout.addWidget( lbl_image )

        # Initialize a horizontal layout for the parameters.
        gb = QGroupBox( "Evolution Parameters" )
        gb.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )

        tw = QTableWidget( 1, 2 )
        tw.setHorizontalHeaderLabels(QString("Parameter;Value").split(';'))
        tw.setColumnWidth( 0, 350 )
        tw.horizontalHeader().setStretchLastSection( True )
        self.connect( tw, SIGNAL('itemChanged(QTableWidgetItem *)'), self.handle_parameter_change )
        self.parameter_table = tw

        tw_layout = QVBoxLayout()
        tw_layout.addWidget( tw )
        gb.setLayout( tw_layout )

        param_layout = QHBoxLayout()
        param_layout.addLayout( image_layout )
        param_layout.addWidget( gb )

        # Grab the global parameters.
        parameter_count = self.globals.getParameterCount()
        tw.setRowCount( parameter_count )
        for p in xrange(parameter_count):
            parameter_name = self.globals.getParameterName( p )
            tw.model().setData( tw.model().index( p, 0 ), parameter_name )
            tw.model().setData( tw.model().index( p, 1 ), self.globals.getParameterValue( parameter_name ) )
            index = tw.item( p, 0 )
            index.setFlags( index.flags() ^ Qt.ItemIsEditable )

        # Initialize a horizontal layout for the evolve button.
        btn_evolve = QPushButton( "Shuffle" )
        self.connect( btn_evolve, SIGNAL('released()'), self.evolve_image )
        btn_evolve.setEnabled( False )
        self.btn_evolve = btn_evolve
        self.btn_evolve.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred )

        self.spin_evolve_iterations = QSpinBox()
        self.spin_evolve_iterations.setRange( 1, 100 )
        self.spin_evolve_iterations.setValue( 1 )

        self.cb_cross_correlate = QCheckBox( "X-Corr" )
        self.cb_cross_correlate.setChecked( True )

        control_layout = QHBoxLayout()
        control_layout.addWidget( btn_evolve )
        control_layout.addWidget( self.spin_evolve_iterations )
        control_layout.addWidget( self.cb_cross_correlate )

        # Initialize vertical central layout.
        central_layout = QVBoxLayout()
        central_layout.addLayout( param_layout )
        central_layout.addWidget( lv )
        central_layout.addLayout( control_layout )
        central_widget = QFrame()
        central_widget.setLayout( central_layout )

        self.setCentralWidget( central_widget )

        # Create a menu
        self.image_menu = QMenu("Menu", self)
        self.image_menu_save_image = self.image_menu.addAction("Save Selected Images")
        self.image_menu_save_network = self.image_menu.addAction("Save Selected Neural Network")

        ### Initialization

        # Handle command line parameters.
        if len(sys.argv) >= 2:
            self.select_image(sys.argv[1])

        # Create progress dialog.
        self.progress_dialog = QProgressDialog( self );
        self.progress_dialog.setLabelText( "Evolving population..." )
        self.progress_dialog.setWindowModality( Qt.WindowModal );
        self.progress_dialog.setVisible( False )
        self.progress_dialog.setCancelButton( None )

        # Start evolver thread.
        self.evolve_thread = EvolveThread( self )
        self.evolve_thread.finished_job.connect( self.finish_evolution )
        self.evolve_thread.update_progress.connect( self.update_evolution_progress )
        self.evolve_thread.start()

        # Generate first population.
        self.population = self.experiment.pythonEvaluationSet()
        self.evolve_image()

    # Destructor.
    def __del__( self ):
        # Save best population.
        self.experiment.saveBest()

        # Cleanup HyperNEAT.
        neat.cleanup()

        # Exit evolve thread.
        try:
            self.evolve_thread.terminate()
            self.evolve_thread.wait( 5000 )
        except NameError:
            print "Evolve thread not created yet, thus not destroyed."

    # Update a parameter value.
    def handle_parameter_change( self, parameter ):
        column = parameter.column()
        if column == 1:
            row = parameter.row()
            parameter_name = self.globals.getParameterName( row )
            current_value = self.globals.getParameterValue( parameter_name )
            (new_value, is_a_float) = parameter.data(Qt.EditRole).toFloat()
            if is_a_float:
                self.globals.setParameterValue( parameter_name, new_value )
            else:
                parameter.setText( "%.2f" % current_value )

    # Choose a new image to work with.
    def select_image( self, file_name = None ):
        if file_name == None:
            file_name = QFileDialog.getOpenFileName(
                self,
                "Select Image", "",
                "Image Files (*.png *.jpg *.bmp)" );

        if os.path.isfile(file_name):
            # Disable evolve button.
            self.btn_evolve.setEnabled( False )

            # Load image.
            print "Loading image: %s..." % file_name
            self.population_list.setEnabled( True )
            self.original_image = QImage( file_name )
            scaled_image = self.original_image.scaled(120, 120, Qt.KeepAspectRatio, Qt.SmoothTransformation)
            self.population_model.set_original_image( scaled_image )
            self.original_image_label.setPixmap( QPixmap(scaled_image) )

            # Enable evolve button.
            self.btn_evolve.setEnabled( True )

    # Handles listview changes. We only care if elements are selected.
    def handle_listview_change( self, selected, deselected ):
        selection = self.population_list.selectionModel().hasSelection()
        if selection:
            self.spin_evolve_iterations.setEnabled( False )
            self.btn_evolve.setText('Evolve')
        else:
            self.spin_evolve_iterations.setEnabled( True )
            self.btn_evolve.setText('Shuffle')

    # Evolve the image with the selected individuals.
    def evolve_image( self ):
        # Disable evolve button.
        self.btn_evolve.setEnabled( False )
        self.spin_evolve_iterations.setEnabled( False )
        self.cb_cross_correlate.setEnabled( False )

        # Configure progress dialog.
        self.progress_dialog.setRange( 0, self.spin_evolve_iterations.value()*self.population.getIndividualCount() )
        self.progress_dialog.setValue( 0 )
        self.progress_dialog.setVisible( True )

        # Set job.
        indices = self.population_list.selectionModel().selectedRows()
        self.evolve_thread.add_job(
            self.spin_evolve_iterations.value(), indices,
            self.cb_cross_correlate.isChecked() )

    # Update evolution progress.
    def update_evolution_progress( self, completed, max ):
        if self.progress_dialog.maximum() != max:
            self.progress_dialog.setMaximum( max )
        self.progress_dialog.setValue( completed )

    # Finish evolution process.
    def finish_evolution( self ):
        # Update icons.
        for i in xrange(self.population_model.rowCount()):
            self.population_model.update_icon(i)
            index = self.population_list.model().index(i, 0)
            self.population_list.selectionModel().select(index, QItemSelectionModel.Select)
            self.population_list.selectionModel().select(index, QItemSelectionModel.Deselect)

        # Close dialog.
        self.progress_dialog.setVisible( False )

        # Reenable evolve button.
        self.cb_cross_correlate.setEnabled( True )
        self.spin_evolve_iterations.setEnabled( True )
        self.btn_evolve.setEnabled( True )

    def handle_context_menu( self, point ):
        # Show the context menu if items are selected.
        indices = self.population_list.selectionModel().selectedRows()
        if len(indices) > 0:
            action = self.image_menu.exec_( self.population_list.mapToGlobal(point) )

            # Save the selected images.
            if action == self.image_menu_save_image:
                file_name = QFileDialog.getSaveFileName(
                    self,
                    "Save Image(s) as...", "",
                    "PNG Image (*.png)" );
                if file_name:
                    if file_name.length() - file_name.lastIndexOf('.png', -1, Qt.CaseInsensitive) == 4:
                        file_name.chop( 4 )
                    print "Save image(s) to: %s" % file_name
                    for index in indices:
                        index_file_name = "%s_%d.png" % (file_name, index.row())
                        print " - Saving image: %s..." % (index_file_name),
                        sys.stdout.flush()
                        distorted_image_map = self.population_model.distort(
                            index.row(), self.original_image )
                        distorted_image = QImage( distorted_image_map )
                        distorted_image.save( index_file_name )
                        print "Done."
                else:
                    print "Save image(s): Canceled"

            # Save the selected networks.
            elif action ==  self.image_menu_save_network:
                file_name = QFileDialog.getSaveFileName(
                    self,
                    "Save Network(s) as...", "",
                    "XML File (*.xml)" );
                if file_name:
                    if file_name.length() - file_name.lastIndexOf('.xml', -1, Qt.CaseInsensitive) == 4:
                        file_name.chop( 4 )
                    print "Save network(s) to: %s" % file_name
                    for index in indices:
                        index_file_name = "%s_%d.xml" % (file_name, index.row())
                        print " - Saving network: %s..." % (index_file_name),
                        sys.stdout.flush()
                        self.population.getIndividual(index.row()).saveToFile(
                            str(index_file_name), False )
                        print "Done."
                else:
                    print "Save network(s): Canceled"
Exemple #4
0
class Window(QMainWindow):
    def __init__( self, parent = None ):
        super(Window, self).__init__( parent )
        self.setWindowTitle( 'Interactive Distortion Evolver' )

        ### Experiment Configuration
        # ATW: TODO: When we start getting reasonable distortions, there
        # needs to be a method to reload an old population. For now we'll
        # always make a new one.

        self.experiment_data_dir  = "../external/HyperNEAT/NE/HyperNEAT/out/data"
        self.date_specifier = datetime.now().strftime("%y%m%d_%H%M%S")
        self.image_storage = []

        # Initialize HyperNEAT.
        neat.initialize()

        # See if there is an output directory.
        if not os.path.exists(os.getcwd() + "/output"):
            os.mkdir(os.getcwd() + "/output")

        # Load the image experiment.
        self.experiment = neat.setupExperiment(
            "%s/ImageExperiment.dat" % self.experiment_data_dir,
            "output/imageExp_out_%s.xml" % self.date_specifier )

        # Grab the global parameters.
        self.globals = neat.getGlobalParameters()
        population_size = int(self.globals.getParameterValue('PopulationSize'))

        ### GUI Configuration

        # Set default window size.
        self.setFixedSize( 670, 700 )

        # Initialize the list view for the distorted images.
        lv = QListView( )
        lv.setViewMode( QListView.IconMode )
        lv.setUniformItemSizes( True )
        lv.setSelectionRectVisible( True )
        lv.setMovement( QListView.Static )
        lv.setSelectionMode( QListView.MultiSelection )
        lv.setEditTriggers( QListView.CurrentChanged )
        lv.setResizeMode( QListView.Adjust )
        lv.setIconSize( QSize(120, 120) )
        lv.setMinimumSize( 500, 385 )
        lv.setSpacing( 5 )
        lv.setEnabled( False )
        self.population_list = lv

        # Context menu.
        lv.setContextMenuPolicy( Qt.CustomContextMenu )
        lv.customContextMenuRequested.connect(self.handle_context_menu)

        # Create the population model.
        pm = PopulationModel( population_size )
        self.population_model = pm
        lv.setModel( pm )
        for i in xrange(population_size):
            self.population_model.update_item( i, DummyNetwork( i % 4 + 1 ) )

        # Monitor population list selection changes.
        lv.selectionModel().selectionChanged.connect(self.handle_listview_change )

        # Initialize widgets for displaying the graphic and for choosing
        # a new base image.
        btn_select_image = QPushButton( "Load Image" )
        btn_select_image.released.connect(self.select_image)
        lbl_image = QLabel( "Nothing loaded" )
        lbl_image.setFixedSize( 120, 120 )
        self.original_image_label = lbl_image
        image_layout = QVBoxLayout()
        image_layout.addWidget( btn_select_image )
        image_layout.addWidget( lbl_image )

        # Initialize a horizontal layout for the parameters.
        gb = QGroupBox( "Evolution Parameters" )
        gb.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )

        tw = QTableWidget( 1, 2 )
        tw.setHorizontalHeaderLabels("Parameter;Value".split(';'))
        tw.setColumnWidth( 0, 350 )
        tw.horizontalHeader().setStretchLastSection( True )
        tw.itemChanged.connect(self.handle_parameter_change)
        self.parameter_table = tw

        tw_layout = QVBoxLayout()
        tw_layout.addWidget( tw )
        gb.setLayout( tw_layout )

        param_layout = QHBoxLayout()
        param_layout.addLayout( image_layout )
        param_layout.addWidget( gb )

        # Grab the global parameters.
        parameter_count = self.globals.getParameterCount()
        tw.setRowCount( parameter_count )
        for p in xrange(parameter_count):
            parameter_name = self.globals.getParameterName( p )
            tw.model().setData( tw.model().index( p, 0 ), parameter_name )
            tw.model().setData( tw.model().index( p, 1 ), self.globals.getParameterValue( parameter_name ) )
            index = tw.item( p, 0 )
            index.setFlags( index.flags() ^ Qt.ItemIsEditable )

        # Initialize a horizontal layout for the evolve button.
        btn_evolve = QPushButton( "Shuffle" )
        btn_evolve.released.connect(self.evolve_image)
        btn_evolve.setEnabled( False )
        self.btn_evolve = btn_evolve
        self.btn_evolve.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred )

        self.spin_evolve_iterations = QSpinBox()
        self.spin_evolve_iterations.setRange( 1, 100 )
        self.spin_evolve_iterations.setValue( 1 )

        self.cb_cross_correlate = QCheckBox( "X-Corr" )
        self.cb_cross_correlate.setChecked( True )

        control_layout = QHBoxLayout()
        control_layout.addWidget( btn_evolve )
        control_layout.addWidget( self.spin_evolve_iterations )
        control_layout.addWidget( self.cb_cross_correlate )

        # Initialize vertical central layout.
        central_layout = QVBoxLayout()
        central_layout.addLayout( param_layout )
        central_layout.addWidget( lv )
        central_layout.addLayout( control_layout )
        central_widget = QFrame()
        central_widget.setLayout( central_layout )

        self.setCentralWidget( central_widget )

        # Create a menu
        self.image_menu = QMenu("Menu", self)
        self.image_menu_save_image = self.image_menu.addAction("Save Selected Images")
        self.image_menu_save_network = self.image_menu.addAction("Save Selected Neural Network")

        ### Initialization

        # Handle command line parameters.
        if len(sys.argv) >= 2:
            self.select_image(sys.argv[1])

        # Create progress dialog.
        self.progress_dialog = QProgressDialog( self );
        self.progress_dialog.setLabelText( "Evolving population..." )
        self.progress_dialog.setWindowModality( Qt.WindowModal );
        self.progress_dialog.setVisible( False )
        self.progress_dialog.setCancelButton( None )

        # Start evolver thread.
        self.evolve_thread = EvolveThread( self )
        self.evolve_thread.finished_job.connect( self.finish_evolution )
        self.evolve_thread.update_progress.connect( self.update_evolution_progress )
        self.evolve_thread.start()

        # Generate first population.
        self.population = self.experiment.pythonEvaluationSet()
        self.evolve_image()

    # Destructor.
    def __del__( self ):
        # Save best population.
        self.experiment.saveBest()

        # Cleanup HyperNEAT.
        neat.cleanup()

        # Exit evolve thread.
        try:
            self.evolve_thread.terminate()
            self.evolve_thread.wait( 5000 )
        except NameError:
            print "Evolve thread not created yet, thus not destroyed."

    # Update a parameter value.
    def handle_parameter_change( self, parameter ):
        column = parameter.column()
        if column == 1:
            row = parameter.row()
            parameter_name = self.globals.getParameterName( row )
            current_value = self.globals.getParameterValue( parameter_name )
            v = parameter.data(Qt.EditRole)
            if v.canConvert(QVariant.Double):
                v.convert(QVariant.Double)
                self.globals.setParameterValue(parameter_name, v.value())
            else:
                parameter.setText("%.2f" % current_value)

    # Choose a new image to work with.
    def select_image( self, file_name = None ):
        if file_name == None:
            file_name, _ = QFileDialog.getOpenFileName(
                self,
                "Select Image", "",
                "Image Files (*.png *.jpg *.bmp)" );

        if os.path.isfile(file_name):
            # Disable evolve button.
            self.btn_evolve.setEnabled( False )

            # Load image.
            print "Loading image: %s..." % file_name
            self.population_list.setEnabled( True )
            self.original_image = QImage( file_name )
            scaled_image = self.original_image.scaled(120, 120, Qt.KeepAspectRatio, Qt.SmoothTransformation)
            self.population_model.set_original_image( scaled_image )
            self.original_image_label.setPixmap( QPixmap(scaled_image) )

            # Enable evolve button.
            self.btn_evolve.setEnabled( True )

    # Handles listview changes. We only care if elements are selected.
    def handle_listview_change( self, selected, deselected ):
        selection = self.population_list.selectionModel().hasSelection()
        if selection:
            self.spin_evolve_iterations.setEnabled( False )
            self.btn_evolve.setText('Evolve')
        else:
            self.spin_evolve_iterations.setEnabled( True )
            self.btn_evolve.setText('Shuffle')

    # Evolve the image with the selected individuals.
    def evolve_image( self ):
        # Disable evolve button.
        self.btn_evolve.setEnabled( False )
        self.spin_evolve_iterations.setEnabled( False )
        self.cb_cross_correlate.setEnabled( False )

        # Configure progress dialog.
        self.progress_dialog.setRange( 0, self.spin_evolve_iterations.value()*self.population.getIndividualCount() )
        self.progress_dialog.setValue( 0 )
        self.progress_dialog.setVisible( True )

        # Set job.
        indices = self.population_list.selectionModel().selectedRows()
        self.evolve_thread.add_job(
            self.spin_evolve_iterations.value(), indices,
            self.cb_cross_correlate.isChecked() )

    # Update evolution progress.
    def update_evolution_progress( self, completed, max ):
        if self.progress_dialog.maximum() != max:
            self.progress_dialog.setMaximum( max )
        self.progress_dialog.setValue( completed )

    # Finish evolution process.
    def finish_evolution( self ):
        # Update icons.
        for i in xrange(self.population_model.rowCount()):
            self.population_model.update_icon(i)
            index = self.population_list.model().index(i, 0)
            self.population_list.selectionModel().select(index, QItemSelectionModel.Select)
            self.population_list.selectionModel().select(index, QItemSelectionModel.Deselect)

        # Close dialog.
        self.progress_dialog.setVisible( False )

        # Reenable evolve button.
        self.cb_cross_correlate.setEnabled( True )
        self.spin_evolve_iterations.setEnabled( True )
        self.btn_evolve.setEnabled( True )

    def handle_context_menu( self, point ):
        # Show the context menu if items are selected.
        indices = self.population_list.selectionModel().selectedRows()
        if len(indices) > 0:
            action = self.image_menu.exec_( self.population_list.mapToGlobal(point) )

            # Save the selected images.
            if action == self.image_menu_save_image:
                file_name, _ = QFileDialog.getSaveFileName(
                    self,
                    "Save Image(s) as...", "",
                    "PNG Image (*.png)" );
                if file_name:
                    if file_name.length() - file_name.lastIndexOf('.png', -1, Qt.CaseInsensitive) == 4:
                        file_name.chop( 4 )
                    print "Save image(s) to: %s" % file_name
                    for index in indices:
                        index_file_name = "%s_%d.png" % (file_name, index.row())
                        print " - Saving image: %s..." % (index_file_name),
                        sys.stdout.flush()
                        distorted_image_map = self.population_model.distort(
                            index.row(), self.original_image )
                        distorted_image = QImage( distorted_image_map )
                        distorted_image.save( index_file_name )
                        print "Done."
                else:
                    print "Save image(s): Canceled"

            # Save the selected networks.
            elif action ==  self.image_menu_save_network:
                file_name, _ = QFileDialog.getSaveFileName(
                    self,
                    "Save Network(s) as...", "",
                    "XML File (*.xml)" );
                if file_name:
                    print "Save network(s) to: %s" % file_name
                    for index in indices:
                        index_file_name = "%s_%d.xml" % (file_name, index.row())
                        print " - Saving network: %s..." % (index_file_name),
                        sys.stdout.flush()
                        self.population.getIndividual(index.row()).saveToFile(
                            str(index_file_name), False )
                        print "Done."
                else:
                    print "Save network(s): Canceled"