from ICP import ICP

from PIL import Image
from PIL import ImageDraw
from PIL import ImageTk
from PIL import ImageChops
from PIL import ImageFont
import numpy
import sys,os,os.path,glob,signal
import re
import functools
import math
import random
import copy
if sys.version_info[0] == 3:
    import tkinter as Tkinter
    from tkinter.constants import *
    import tkinter.font as tkFont
else:
    import Tkinter    
    from Tkconstants import *
    import tkFont
import pymsgbox
import time

#___________________________________  Utility functions  ____________________________________

def ctrl_c_handler( signum, frame ):             
    print("Killed by Ctrl C")                       
    os.kill( os.getpid(), signal.SIGKILL )       
signal.signal( signal.SIGINT, ctrl_c_handler )   

def file_index(file_name):
    '''
    This function is needed if you are analyzing an image in the scanning mode.
    In this mode, the module runs a non-overlapping scanning window over the image,
    dumps the image data inside the scanning window at each position of the window
    in a directory.  Each file is given a name that includes a numerical index
    indicating its position in the original images.  This function returns the
    numerical index in the name of a file.
    '''
    m = re.search(r'_(\d+)\.jpg$', file_name)
    return int(m.group(1))

#______________________________  ImageScanner Class Definition  ________________________________

class ICPImageScanner(ICP):
    '''
    This class is useful when you want to apply ICP to two very large images and when there is
    reason to believe that the different sections of the images are not related in exactly the
    same manner with regard to the translational and rotational offsets. This will usually not
    be the case when the images are recorded with the regular frame cameras.  However, you can
    see non-constant offset relationships between the different regions of two images of the
    same scene when the images are put together by recording the pixels with sensors that are
    in motion. One example of this would be the satellites that are used for earth imaging --- 
    the satellites construct large images using what are known as pushbroom cameras.
    '''

    def __init__(self, *args, **kwargs ):
        if args:
            raise ValueError(  
                   '''ICPImageScanner constructor can only be called with keyword arguments for 
                      the following keywords: model_image_file, data_image_file, binary_or_gray_or_color,
                      corners_or_edges, size_for_calculations, scanning_window_width, scanning_window_height, 
                      iterations, subimage_index, and debug''')   
        model_image_file = data_image_file = scanning_window_width = scanning_window_height = subimage_index = min_brightness_level = min_area_threshold = max_area_threshold = iterations = corners_or_edges = debug = None
        if 'model_image_file' in kwargs              :   model_image_file = kwargs.pop('model_image_file')
        if 'data_image_file' in kwargs               :   data_image_file = kwargs.pop('data_image_file')
        if 'corners_or_edges' in kwargs              :   corners_or_edges=kwargs.pop('corners_or_edges')
        if 'subimage_index' in kwargs                :   subimage_index = kwargs.pop('subimage_index')
        if 'iterations' in kwargs                    :   iterations = kwargs.pop('iterations')
        if 'scanning_window_width' in kwargs         :   scanning_window_width = kwargs.pop('scanning_window_width')
        if 'scanning_window_height' in kwargs        :   scanning_window_height = kwargs.pop('scanning_window_height')
        ICP.__init__(self, **kwargs)
        if corners_or_edges == "corners":
            sys.exit("The scanner is not yet set for ICP with corner features. Sorry!")
        elif corners_or_edges == "edges":
            self.corners_or_edges = "edges"
        self.model_im_file = model_image_file
        self.data_im_file = data_image_file
        self.model_im = Image.open(model_image_file)
        self.data_im = Image.open(data_image_file)
        self.iterations = iterations
        self.scanning_window_width, self.scanning_window_height  =  scanning_window_width, scanning_window_height
        self.model_im_width, self.model_im_height = self.model_im.size[0], self.model_im.size[1]
        self.scanner_dump_directory_model = os.path.splitext(model_image_file)[0] + "_scanner_dump"
        self.scanner_dump_directory_data = os.path.splitext(data_image_file)[0] + "_scanner_dump"
        if subimage_index is not None:
            self.subimage_index = subimage_index
            self.model_subimage_file = self.scanner_dump_directory_model + "/subimage_" + str(subimage_index) +".jpg"
            self.data_subimage_file = self.scanner_dump_directory_data + "/subimage_" + str(subimage_index) + ".jpg"
            self.model_subimage = Image.open(self.model_subimage_file)
            self.data_subimage = Image.open(self.data_subimage_file)
        self.model_subimages_with_retained_pixels = None
        self.total_num_window_pos = None
        if debug:                             
            self.debug = debug
        else:
            self.debug = 0

    def apply_icp_to_model_and_data_scanner_dumps_and_show_intermediate_results(self):
        '''
        The purpose of this method is to apply ICP to ALL the subimage pairs in the two scanner dump
        directories, one for the model image and the other for the data image.  This method visually
        displays the results of ICP matching for EACH pair of subimages (one for the model and the
        other for the data) produced by the scanner in the form a movie.  This method also displays 
        the intermediate results obtained for each pair of subimages.
        '''
        if ( (not os.path.exists(self.scanner_dump_directory_model)) or 
             (len(glob.glob(self.scanner_dump_directory_model + "/*")) == 0) or
             (not os.path.exists(self.scanner_dump_directory_data)) or 
             (len(glob.glob(self.scanner_dump_directory_data + "/*")) == 0) ):
            sys.exit("Before you call apply_icp_to_model_and_data_scanner_dumps_and_show_intermediate_results(), you must create a scan dump by running the scanner.  See image scanning scripts in the ExamplesICPImageScanner directory for why.")
        self.displayImage6(self.model_im, "input model image -- close window when done viewing")
        self.displayImage6(self.data_im, "input data image -- close window when done viewing")
        self.model_image_width, self.model_image_height = self.model_im.size
        self.data_image_width, self.data_image_height = self.data_im.size
        print("size of the model image is: %s" % str((self.model_image_width,self.model_image_height)))
        print("size of the data image is: %s" % str((self.data_image_width,self.data_image_height)))
        self.horiz_positions_of_scan_window = self.model_im_width // self.scanning_window_width
        self.vert_positions_of_scan_window = self.model_im_height // self.scanning_window_height
        total_scan_window_positions = self.horiz_positions_of_scan_window * self.vert_positions_of_scan_window
        self.model_subimages_with_retained_pixels = [None] * total_scan_window_positions
        for modelfile,datafile in zip( sorted(glob.glob(self.scanner_dump_directory_model + "/*"), key=lambda x: file_index(x)),
                                       sorted(glob.glob(self.scanner_dump_directory_data + "/*"), key=lambda x: file_index(x)) ):
            try:
                print("\n\nApplying ICP to image blocks in files %s and %s" % (modelfile,datafile))
                self.calculate_icp_for_one_pair_of_subimages_and_display_results(modelfile, datafile, file_index(modelfile))
            except: pass

    def apply_icp_to_model_and_data_scanner_dumps_fast(self):
        '''
        Like the previous method, the purpose of this method is also to apply ICP to ALL the subimage 
        pairs in the two scanner dump directories, one for the model image and the other for the data image. 
        This method, however, does NOT display separately the ICP matching results for each pair of
        subimages.
        '''
        if ( (not os.path.exists(self.scanner_dump_directory_model)) or 
             (len(glob.glob(self.scanner_dump_directory_model + "/*")) == 0) or
             (not os.path.exists(self.scanner_dump_directory_data)) or 
             (len(glob.glob(self.scanner_dump_directory_data + "/*")) == 0) ):
            sys.exit("Before you call apply_icp_to_model_and_data_scanner_dumps_and_show_intermediate_results(), you must create a scan dump by running the scanner.  See image scanning scripts in the ExamplesICPImageScanner directory for why.")
        self.model_image_width, self.model_image_height = self.model_im.size
        self.data_image_width, self.data_image_height = self.data_im.size
        self.horiz_positions_of_scan_window = self.model_im_width // self.scanning_window_width
        self.vert_positions_of_scan_window = self.model_im_height // self.scanning_window_height
        total_scan_window_positions = self.horiz_positions_of_scan_window * self.vert_positions_of_scan_window
        self.model_subimages_with_retained_pixels = [None] * total_scan_window_positions
        for modelfile,datafile in zip( sorted(glob.glob(self.scanner_dump_directory_model + "/*"), key=lambda x: file_index(x)),
                                       sorted(glob.glob(self.scanner_dump_directory_data + "/*"), key=lambda x: file_index(x)) ):
            try:
                print("\n\nApplying ICP to image blocks in files %s and %s" % (modelfile,datafile))
                self.calculate_icp_for_one_pair_of_subimages_fast(modelfile, datafile, file_index(modelfile))
            except: pass

    def calculate_icp_for_one_pair_of_subimages_and_display_results(self, modelfile=None, datafile=None, subimage_index=None):
        '''
        Assuming that you have already run the image scanner on the model and the data images, you invoke
        this method to apply ICP to one corresponding pair of subimages in the two scanner dump directories.
        '''
        if (( not os.path.exists(self.scanner_dump_directory_model)) or 
            (len(glob.glob(self.scanner_dump_directory_model + "/*")) == 0) or 
            (not os.path.exists(self.scanner_dump_directory_data)) or 
            (len(glob.glob(self.scanner_dump_directory_data + "*")) == 0)):
            sys.exit("Before invoking caculate_icp_for_one_pair_of_subimages_and_display_results(), you must first create scan dump of subimages by invoking the image scanner code.  See the relevant example script in the ExamplesScanner directory for why.")
        if (modelfile is None) and (datafile is None):
            model_subimage_file = self.model_subimage_file
            data_subimage_file = self.data_subimage_file
        else:
            model_subimage_file = modelfile
            data_subimage_file = datafile  
            self.model_subimage = Image.open(modelfile)
            self.data_subimage = Image.open(datafile)
            self.subimage_index = subimage_index
        # Make sure we have the info on how many positions of the scanning window horizontally and vertically:
        if self.model_subimages_with_retained_pixels is None:
            self.horiz_positions_of_scan_window = self.model_im_width // self.scanning_window_width
            self.vert_positions_of_scan_window = self.model_im_height // self.scanning_window_height
            total_scan_window_positions = self.horiz_positions_of_scan_window * self.vert_positions_of_scan_window
            self.model_subimages_with_retained_pixels = [None] * total_scan_window_positions
        # Now construct an instance of the ICP class:
        icp = ICP(
               binary_or_color = self.binary_or_color,
               corners_or_edges = self.corners_or_edges,
               calculation_image_size = 200,
               max_num_of_pixels_used_for_icp = 300,
               pixel_correspondence_dist_threshold = 20,
               iterations = self.iterations,
               model_image =  model_subimage_file,
               data_image = data_subimage_file,
               subimage_index = self.subimage_index,
            )
        # Extract low-level information from the two corresponding subimages:
        self._extract_pixels_from_subimage('model')
        self._extract_pixels_from_subimage('data') 
        # Initialize the variables in the ICP instance:
        icp.model_list = self.model_list
        icp.data_list = self.data_list
        icp.model_im = self.model_subim_result
        icp.data_im = self.data_subim_result
        # Store away the pixels retained for ICP calculation.     
        self.model_subimages_with_retained_pixels[self.subimage_index] = self.model_subim_result
        # Now call the ICP algorithm:
        icp.icp()
        self.display_subimage_pair_used_for_edge_based_icp()
        icp.display_results_as_movie()
#        icp.cleanup_directory()

    def calculate_icp_for_one_pair_of_subimages_fast(self, modelfile=None, datafile=None, subimage_index=None):
        '''
        Assuming that you have already run the image scanner on the model and the data images, you invoke
        this method to apply ICP to one corresponding pair of subimages in the two scanner dump directories.
        '''
        if (( not os.path.exists(self.scanner_dump_directory_model)) or 
            (len(glob.glob(self.scanner_dump_directory_model + "/*")) == 0) or 
            (not os.path.exists(self.scanner_dump_directory_data)) or 
            (len(glob.glob(self.scanner_dump_directory_data + "*")) == 0)):
            sys.exit("Before invoking caculate_icp_for_one_pair_of_subimages_and_display_results(), you must first create scan dump of subimages by invoking the image scanner code.  See the relevant example script in the ExamplesScanner directory for why.")
        if (modelfile is None) and (datafile is None):
            model_subimage_file = self.model_subimage_file
            data_subimage_file = self.data_subimage_file
        else:
            model_subimage_file = modelfile
            data_subimage_file = datafile  
            self.model_subimage = Image.open(modelfile)
            self.data_subimage = Image.open(datafile)
            self.subimage_index = subimage_index
        # Make sure we have the info on how many positions of the scanning window horizontally and vertically:
        if self.model_subimages_with_retained_pixels is None:
            self.horiz_positions_of_scan_window = self.model_im_width // self.scanning_window_width
            self.vert_positions_of_scan_window = self.model_im_height // self.scanning_window_height
            total_scan_window_positions = self.horiz_positions_of_scan_window * self.vert_positions_of_scan_window
            self.model_subimages_with_retained_pixels = [None] * total_scan_window_positions
        # Now construct an instance of the ICP class:
        icp = ICP(
               binary_or_color = self.binary_or_color,
               corners_or_edges = self.corners_or_edges,
               calculation_image_size = 200,
               max_num_of_pixels_used_for_icp = 300,
               pixel_correspondence_dist_threshold = 20,
               iterations = self.iterations,
               model_image =  model_subimage_file,
               data_image = data_subimage_file,
               subimage_index = self.subimage_index,
            )
        # Extract low-level information from the two corresponding subimages:
        self._extract_pixels_from_subimage('model')
        self._extract_pixels_from_subimage('data') 
        # Initialize the variables in the ICP instance:
        icp.model_list = self.model_list
        icp.data_list = self.data_list
        icp.model_im = self.model_subim_result
        icp.data_im = self.data_subim_result
        # Store away the pixels retained for ICP calculation.          
        self.model_subimages_with_retained_pixels[self.subimage_index] = self.model_subim_result
        # Now call the ICP algorithm:
        icp.icp()

    def display_subimage_pair_used_for_edge_based_icp(self):
        '''
        For a given a subimage pair, one from the model image and the other from the data image, this
        method displays in the first row the overall model and data images along with a red-outlined
        rectangle in each to indicate what portion of the large images corresponds to the subimages.
        In the second row, this method shows the extracted model subimage, its edge map, and the retained
        edge pixels.  Finally, in the third row, this method shows the same as in the second row but
        for the data image.
        '''
        tk_images = []
        image_labels = []
        rootWindow = Tkinter.Tk()
        screen_width,screen_height =rootWindow.winfo_screenwidth(),rootWindow.winfo_screenheight()
        rootWindow.geometry( str(int(0.8 * screen_width)) + "x" + str(int(0.9 * screen_height)) + "+50+50") 
        canvas = Tkinter.Canvas(rootWindow)
        canvas.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=Tkinter.TRUE)
        scrollbar_x = Tkinter.Scrollbar(rootWindow,orient=Tkinter.HORIZONTAL,command=canvas.xview)
        scrollbar_y = Tkinter.Scrollbar(rootWindow,orient=Tkinter.VERTICAL,command=canvas.yview)
        scrollbar_x.pack(side=Tkinter.BOTTOM, fill=Tkinter.X)
        scrollbar_y.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)
        canvas.configure(xscrollcommand=scrollbar_x.set)
        canvas.configure(yscrollcommand=scrollbar_y.set)
        def set_scrollregion(event):
            canvas.configure(scrollregion=canvas.bbox('all'))
        frame = Tkinter.Frame(canvas)
        canvas.create_window((0,0), window=frame, anchor=Tkinter.NW)
        frame.bind('<Configure>', set_scrollregion)
        cellwidth =  500
        padding = 10
        if cellwidth > 80:
            fontsize = 25
        else:
            fontsize = 15
        font = ImageFont.truetype(self.font_file, fontsize)

        model_image_width, model_image_height = self.model_im_width, self.model_im_height

        original_model_im = self.model_im.copy()
        original_data_im  = self.data_im.copy()

        self.num_horiz_positions_for_subimages = model_image_width // self.scanning_window_width
        self.num_vert_positions_for_subimages = model_image_height // self.scanning_window_height
        vert_pos_index_for_subimage = self.subimage_index // self.num_horiz_positions_for_subimages
        horz_pos_index_for_subimage = self.subimage_index - vert_pos_index_for_subimage * self.num_horiz_positions_for_subimages
        ulcx = upper_left_corner_x = horz_pos_index_for_subimage * self.scanning_window_width
        ulcy = upper_left_corner_y = vert_pos_index_for_subimage * self.scanning_window_height

        draw1 = ImageDraw.Draw(original_model_im)
        draw2 = ImageDraw.Draw(original_data_im)
        outline_width = 10
        for i in range(outline_width):
            draw1.rectangle((ulcx+i, ulcy+i, ulcx+self.scanning_window_width+i, ulcy+self.scanning_window_height+i), fill=None, outline='red')
            draw2.rectangle((ulcx+i, ulcy+i, ulcx+self.scanning_window_width+i, ulcy+self.scanning_window_height+i), fill=None, outline='red')

        original_model_subimage = self.model_subimage.copy()
        original_data_subimage = self.data_subimage.copy()
        displayWidth,displayHeight = None,None
        if model_image_width > model_image_height:
            displayWidth = int(0.9 * cellwidth)
            displayHeight = int(displayWidth * model_image_height * 1.0 / model_image_width)
        else:
            displayHeight = int(0.9 * cellwidth)
            displayWidth = int(displayHeight * model_image_width * 1.0 / model_image_height )
        # These thumbnails are needed for the first row of the display.
        original_model_im.thumbnail((displayWidth,displayHeight), Image.ANTIALIAS)
        original_data_im.thumbnail((displayWidth,displayHeight), Image.ANTIALIAS)
        # make thumbnail of the original model subimage 
        original_model_subimage = original_model_subimage.resize((model_image_width, model_image_height), Image.ANTIALIAS)
        original_model_subimage.thumbnail((displayWidth,displayHeight), Image.ANTIALIAS)
        # make thumbnail of the original data subimage
        original_data_subimage = original_data_subimage.resize((model_image_width, model_image_height), Image.ANTIALIAS)
        original_data_subimage.thumbnail((displayWidth,displayHeight), Image.ANTIALIAS)
        # make thumbnail of the model edge map subimage
        model_edge_map = self.model_subim_edge_map.copy()
        model_edge_map = model_edge_map.resize((model_image_width, model_image_height), Image.ANTIALIAS)
        model_edge_map.thumbnail((displayWidth,displayHeight), Image.ANTIALIAS)
        # make thumbnail of the model edge-pixels-retained subimage
        model_im_res = self.model_subim_result.copy()
        model_im_res = model_im_res.resize((model_image_width,model_image_height), Image.ANTIALIAS)
        model_im_res.thumbnail((displayWidth,displayHeight), Image.ANTIALIAS)
        # make thumbnail of the data edge map subimage
        data_edge_map = self.data_subim_edge_map.copy()
        data_edge_map = data_edge_map.resize((model_image_width, model_image_height), Image.ANTIALIAS)
        data_edge_map.thumbnail((displayWidth,displayHeight), Image.ANTIALIAS)
        # make thumbnail of the data edge-pixels-retained subimage
        data_im_res = self.data_subim_result.copy()
        data_im_res = data_im_res.resize((model_image_width, model_image_height), Image.ANTIALIAS)
        data_im_res.thumbnail((displayWidth,displayHeight), Image.ANTIALIAS)
        # show the original model and the data images side by side:
        image_labels.append("Original Model Image")
        tk_images.append(ImageTk.PhotoImage( original_model_im ))
        image_labels.append("Original Data Image")
        tk_images.append(ImageTk.PhotoImage( original_data_im ))
        # model subimage, followed by its edge map, followed by the edge pixels retained:
        image_labels.append("Model Subimage")
        tk_images.append(ImageTk.PhotoImage( original_model_subimage ))
        image_labels.append("Model Edge Map")
        tk_images.append(ImageTk.PhotoImage( model_edge_map ))
        image_labels.append("Edge Pixels Retained")
        tk_images.append(ImageTk.PhotoImage( model_im_res ))
        # data subimage, followed by its edge map, followed by the edge pixels retained:
        image_labels.append("Data Subimage")
        tk_images.append(ImageTk.PhotoImage( original_data_subimage ))
        image_labels.append("Data Edge Map")
        tk_images.append(ImageTk.PhotoImage( data_edge_map ))
        image_labels.append("Edge Pixels Retained")
        tk_images.append(ImageTk.PhotoImage( data_im_res ))
        # now stuff images into the frame object associated with the canvas:
        ##  NOTE that the arguments to range() are hardcoded to integers because this display is supposed
        ##    to show ONLY two images in the first row, one for the model image and the other for the data image.
        ##    The for loop then creates two more rows of image displays, with the first of these for the model
        ##    subimage and the second for the data subimage.  In each of these two rows, you start with the 
        ##    subimage, followed by its edge map, and followed by the map of the edge pixels retained.
        for i in range(2):
            Tkinter.Label(frame,image=tk_images[i], text=image_labels[i], font=fontsize, compound=Tkinter.BOTTOM, width=cellwidth).grid(row=0,column=i,padx=10,pady=30)
        for i in range(2,8):
            Tkinter.Label(frame,image=tk_images[i], text=image_labels[i], font=fontsize, compound=Tkinter.BOTTOM, width=cellwidth).grid(row=1,column=i-2,padx=10,pady=30)
        '''
        for i in range(2,5):
            Tkinter.Label(frame,image=tk_images[i], text=image_labels[i], font=fontsize, compound=Tkinter.BOTTOM, width=cellwidth).grid(row=1,column=i-2,padx=10,pady=30)
        for i in range(5,8):
            Tkinter.Label(frame,image=tk_images[i], text=image_labels[i], font=fontsize, compound=Tkinter.BOTTOM, width=cellwidth).grid(row=2,column=i-5,padx=10,pady=30)
        '''
        messageFrame = Tkinter.Frame(frame, width=displayWidth, height=displayHeight).grid(row=2,padx=10,pady=50)
        messageLabelText = Tkinter.StringVar()
        Tkinter.Label(messageFrame,
                      textvariable = messageLabelText,
                      font = 2 * fontsize,
                      anchor = 'c',
                      relief = 'groove',
                     ).pack(side='top', padx=10, pady=10)
        messageLabelText.set('''Close this window to see a movie of image registration''')
        Tkinter.mainloop()
        
    def chop_model_and_data_images_into_tiles_interactive(self):
        '''
        This method creates a dump of subimages extracted from large model and data images.  The
        method is interactive in the sense that it shows the user each subimage for his/her 
        examination before storing it in a dump directory.
        '''
        for image_type in ('model','data'):
            scanner_dump_directory = self.scanner_dump_directory_model if image_type == 'model' else self.scanner_dump_directory_data
            self.displayImage6(self.model_im if image_type == 'model' else self.data_im, "input_image -- close window when done viewing")
            M,N = self.scanning_window_width, self.scanning_window_height
            image = self.model_im.copy() if image_type == 'model' else self.data_im.copy()
            self.image_width,self.image_height = self.model_im.size if image_type == 'model' else self.data_im.size
            print("size of the image is: %s" % str((self.image_width,self.image_height)))
            self.array_R = numpy.zeros((N, M), dtype="int")
            self.array_G = numpy.zeros((N, M), dtype="int")
            self.array_B = numpy.zeros((N, M), dtype="int")
            mw = Tkinter.Tk()
            winsize_x,winsize_y = None,None
            screen_width,screen_height = mw.winfo_screenwidth(),mw.winfo_screenheight()
            if screen_width <= screen_height:
                winsize_x = int(0.5 * screen_width)
                winsize_y = int(winsize_x * (self.image_height * 1.0 / self.image_width))            
            else:
                winsize_y = int(0.5 * screen_height)
                winsize_x = int(winsize_y * (self.image_width * 1.0 / self.image_height))
            image = image.resize((winsize_x,winsize_y), Image.ANTIALIAS)
            mw.title( "Image scanner in action" ) 
            mw.configure( height = winsize_y, width = winsize_x )         
            self.canvas = Tkinter.Canvas( mw,                         
                                 height = winsize_y,            
                                 width = winsize_x,             
                                 cursor = "crosshair" )   
            self.canvas.pack(fill=BOTH, expand=True)
            photo = ImageTk.PhotoImage( image )
            self.canvas.create_image(winsize_x//2,winsize_y//2,image=photo)
            self.scale_x = winsize_x / (self.image_width * 1.0)
            self.scale_y = winsize_y / (self.image_height * 1.0) 
            print("\nx_scale: %f" % self.scale_x)
            print("y_scale: %f" % self.scale_y)
            horizontal_positions_of_scan_window = self.image_width // self.scanning_window_width
            vertical_positions_of_scan_window = self.image_height // self.scanning_window_height
            total_scan_window_positions = horizontal_positions_of_scan_window * vertical_positions_of_scan_window
            self.rect = self.canvas.create_rectangle((0, 0, int(M*self.scale_x), 
                                                             int(N*self.scale_y)), width='7', outline='red') 
            self.canvas.update()
            self.horizontal_positions_of_scan_window = horizontal_positions_of_scan_window
            self.vertical_positions_of_scan_window = vertical_positions_of_scan_window
            if os.path.exists(scanner_dump_directory):
                files = glob.glob(scanner_dump_directory + "/*")
                map(lambda x: os.remove(x), files)
            else:
               os.mkdir(scanner_dump_directory)
            self.moves_horizontal = self.image_width // self.scanning_window_width - 1
            self.moves_vertical = self.image_height // self.scanning_window_height - 1
            self.delta_x = int(self.scanning_window_width * self.scale_x)
            self.delta_y = int(self.scanning_window_height * self.scale_y)
            self.x_incr, self.y_incr = 0,0
            self.old_posx, self.old_posy = 0,0
            self.total_num_window_pos = (self.moves_horizontal + 1) * (self.moves_vertical + 1)
            self.num_remaining_pos = self.total_num_window_pos
            self.block_index = 0
            print("horizontal moves max index: %d" % self.moves_horizontal)
            print("vertical moves max index: %d" % self.moves_vertical)
            self._move(image_type)
            mw.mainloop()

    def display_results_for_all_subimage_pairs_together_as_a_movie(self):
        '''
        This method shows in the form of a "movie" the ICP matching for ALL the subimages extracted
        from the large model and data images.  This method is meant to be called when you DO WANT 
        to see the intermediate results for each subimage.  Production of the intermediate results
        also colorizes the pixels of the data subimages for all different iterations.
        '''
        if (self.horiz_positions_of_scan_window is None) or (self.vert_positions_of_scan_window is None):
            self.horiz_positions_of_scan_window = self.model_im_width // self.scanning_window_width
            self.vert_positions_of_scan_window = self.model_im_height // self.scanning_window_height
        total_scan_window_positions = self.horiz_positions_of_scan_window * self.vert_positions_of_scan_window
        if self.scanning_window_width > self.scanning_window_height:
            cell_width = cell_height = self.scanning_window_width + 10
        else:
            cell_width = cell_height = self.scanning_window_height + 10
        def onFrameConfigure(canvas):
            '''Reset the scroll region to encompass the inner frame'''
            canvas.configure(scrollregion=canvas.bbox("all"))
        root = Tkinter.Tk()
        root.title("the movie window")
        canvasroot = Tkinter.Canvas(root, borderwidth=0, background="#ffffff")        
        rootframe = Tkinter.Frame(canvasroot, background="#ffffff")
        vsb = Tkinter.Scrollbar(root, orient="vertical", command=canvasroot.yview)
        hsb = Tkinter.Scrollbar(root, orient="horizontal", command=canvasroot.xview)
        canvasroot.configure(yscrollcommand=vsb.set)
        canvasroot.configure(xscrollcommand=hsb.set)
        vsb.pack(side="right", fill="y")
        hsb.pack(side="top", fill="x")     
        canvasroot.pack(side="left", fill="both", expand=True)
        canvasroot.create_window((30,30), window=rootframe, anchor="nw")
        rootframe.bind("<Configure>", lambda event, canvas=canvasroot: onFrameConfigure(canvasroot))
        imageframe = rootframe
        # declare the array variables to be used later:
#        colors = ('white','blue','red','black')
        colors = ('white','white','white','white')
        frames = [ [None for _ in range(self.vert_positions_of_scan_window)] for _ in range(self.horiz_positions_of_scan_window)]

        model_images = [ [None for _ in range(self.vert_positions_of_scan_window)] 
                                                    for _ in range(self.horiz_positions_of_scan_window)]
        model_color_images = [ [None for _ in range(self.vert_positions_of_scan_window)] 
                                                    for _ in range(self.horiz_positions_of_scan_window)]
        tkim = [ [ [None for _ in range(self.iterations)] for _ in range(self.vert_positions_of_scan_window)] 
                                                    for _ in range(self.horiz_positions_of_scan_window)]
        label_image = [ [ [None for _ in range(self.iterations)] for _ in range(self.vert_positions_of_scan_window)] 
                                                    for _ in range(self.horiz_positions_of_scan_window)]
        out_photo_image = [ [ [None for _ in range(self.iterations)] for _ in range(self.vert_positions_of_scan_window)] 
                                                    for _ in range(self.horiz_positions_of_scan_window)]
        #  create a grid structure for the movie with cell consisting of a Tkinter Frame object.
        for row in range(self.vert_positions_of_scan_window):
            for col in range (self.horiz_positions_of_scan_window):
                frames[row][col] = Tkinter.Frame(imageframe, width=cell_width, height=cell_height, bg=colors[(row*self.horiz_positions_of_scan_window+col) % len(colors)])
                frames[row][col].grid(row=row, column=col, sticky=W+E+N+S)
                model_im_index = row * self.horiz_positions_of_scan_window + col  
                model_images[row][col] = self.model_subimages_with_retained_pixels[model_im_index]
        colspan = self.horiz_positions_of_scan_window
        rownext = self.vert_positions_of_scan_window
        # Now add the notification widgets:
        iterationIndexFrame = Tkinter.Frame(imageframe, height=10).grid(row=rownext+1, column=0, columnspan=colspan, sticky=W+E+N+S)
        iterationLabelText = Tkinter.StringVar()
        Tkinter.Label(iterationIndexFrame,
                      textvariable = iterationLabelText,
                      anchor = 'c',
                      relief = 'groove',
                     ).pack(side='top', padx=10, pady=10)
        separator = Tkinter.Frame(imageframe, height=10, bd=1, relief=Tkinter.SUNKEN).grid(row=rownext+2, column=0, columnspan=colspan, sticky=W+E+N+S)
        buttonframe = Tkinter.Frame(imageframe, height=10).grid(row=rownext+3, column= 0, columnspan=colspan, sticky=W+E+N+S)
        tkFont.nametofont('TkDefaultFont').configure(size=20)    
        helv36 = tkFont.Font(family="Helvetica", size=28, weight='bold')    
        Tkinter.Button(buttonframe, 
                       text = 'Play movie again',                
                       anchor = 'c',
                       relief = 'raised',
                       font = helv36,
                       command = lambda: self.callbak(canvasroot)
                      ).pack(side='top', padx=10, pady=5)
        separator = Tkinter.Frame(imageframe, height=10, bd=1, relief=Tkinter.SUNKEN).grid(row=rownext+4, column=0, columnspan=colspan, sticky=W+E+N+S)
        messageFrame = Tkinter.Frame(imageframe, height=10).grid(row=rownext+5, column=0, columnspan=colspan, sticky=W+E+N+S)
        messageLabelText = Tkinter.StringVar()
        Tkinter.Label(messageFrame,
                      textvariable = messageLabelText,
                      anchor = 'c',
                      relief = 'groove',
                     ).pack(side='top', padx=10, pady=10)
        messageLabelText.set("NOTE: It is best to NOT close this window\nuntil all iterations are completed.")
        # colorize the model subimages:
        for row in range(self.vert_positions_of_scan_window):
            for col in range (self.horiz_positions_of_scan_window):
                imwidth,imheight = model_images[row][col].size
                (mingray,maxgray) = model_images[row][col].getextrema()
                model_color_images[row][col] = Image.new("RGB", (imwidth,imheight), (0,0,0))
                for m in range(imwidth):
                    for n in range(imheight):
                        color_val = model_images[row][col].getpixel((m,n)) * int(255/maxgray)
                        model_color_images[row][col].putpixel((m,n), (color_val, 0, 0))
        # now run the movie:
        self.iteration_control_flag = 1
        while self.iteration_control_flag:
            for i in range(0,self.iterations):
                try:
                    for row in range(self.vert_positions_of_scan_window):
                        for col in range(self.horiz_positions_of_scan_window):        
                            dir_index = row * self.horiz_positions_of_scan_window + col  
                            tkim[row][col][i] = Image.open("__result_" + str(dir_index) + "/__result_color" + str(i) + ".jpg")
                            out_image = ImageChops.add( model_color_images[row][col], tkim[row][col][i] )
#                            out_out_image = out_image.resize((400,400), Image.ANTIALIAS)
                            out_out_image = out_image.resize((self.scanning_window_width,self.scanning_window_height), Image.ANTIALIAS)
                            out_photo_image[row][col][i] = ImageTk.PhotoImage( out_out_image )
                            label_image[row][col][i] = Tkinter.Label(frames[row][col],image=out_photo_image[row][col][i],borderwidth=2,relief="solid")
#                            label_image[row][col][i].place(x=0,y=0,width=400,height=400)
                            label_image[row][col][i].place(relx=0.02,rely=0.02,relwidth=0.98,relheight=0.98)
                    iterationLabelText.set( "Iteration Number: " + str(i+1) )
                    self.iteration_control_flag = 0
                    if i < self.iterations - 1: root.after(1000, root.quit)       
                    root.mainloop(0)
                except IOError: pass

    def display_results_for_all_subimage_pairs_together_as_a_movie_with_colorization(self):
        '''
        This method shows in the form of a "movie" the ICP matching for ALL the subimages extracted
        from the large model and data images.  This method is meant to be called when you do NOT 
        want to see the intermediate results for each subimage.  Note that it is the production of
        the intermediate results that colorizes the pixels needed for the movie display.  Therefore
        when for the sake of speed you opt for not seeing the intermediate results, you need to 
        execute the pixel colorization code separately.  That is the main difference between the
        previous method and this method.
        '''
        if (self.horiz_positions_of_scan_window is None) or (self.vert_positions_of_scan_window is None):
            self.horiz_positions_of_scan_window = self.model_im_width // self.scanning_window_width
            self.vert_positions_of_scan_window = self.model_im_height // self.scanning_window_height
        total_scan_window_positions = self.horiz_positions_of_scan_window * self.vert_positions_of_scan_window
        if self.scanning_window_width > self.scanning_window_height:
            cell_width = cell_height = self.scanning_window_width + 10
        else:
            cell_width = cell_height = self.scanning_window_height + 10
        def onFrameConfigure(canvas):
            '''Reset the scroll region to encompass the inner frame'''
            canvas.configure(scrollregion=canvas.bbox("all"))
        root = Tkinter.Tk()
        root.title("the movie window")
        canvasroot = Tkinter.Canvas(root, borderwidth=0, background="#ffffff")        
        rootframe = Tkinter.Frame(canvasroot, background="#ffffff")
        vsb = Tkinter.Scrollbar(root, orient="vertical", command=canvasroot.yview)
        hsb = Tkinter.Scrollbar(root, orient="horizontal", command=canvasroot.xview)
        canvasroot.configure(yscrollcommand=vsb.set)
        canvasroot.configure(xscrollcommand=hsb.set)
        vsb.pack(side="right", fill="y")
        hsb.pack(side="top", fill="x")     
        canvasroot.pack(side="left", fill="both", expand=True)
        canvasroot.create_window((30,30), window=rootframe, anchor="nw")
        rootframe.bind("<Configure>", lambda event, canvas=canvasroot: onFrameConfigure(canvasroot))
        imageframe = rootframe
        # declare the array variables to be used later:
#        colors = ('white','blue','red','black')
        colors = ('white','white','white','white')
        frames = [ [None for _ in range(self.vert_positions_of_scan_window)] for _ in range(self.horiz_positions_of_scan_window)]

        model_images = [ [None for _ in range(self.vert_positions_of_scan_window)] 
                                                    for _ in range(self.horiz_positions_of_scan_window)]
        model_color_images = [ [None for _ in range(self.vert_positions_of_scan_window)] 
                                                    for _ in range(self.horiz_positions_of_scan_window)]
        tkim = [ [ [None for _ in range(self.iterations)] for _ in range(self.vert_positions_of_scan_window)] 
                                                    for _ in range(self.horiz_positions_of_scan_window)]
        label_image = [ [ [None for _ in range(self.iterations)] for _ in range(self.vert_positions_of_scan_window)] 
                                                    for _ in range(self.horiz_positions_of_scan_window)]
        out_photo_image = [ [ [None for _ in range(self.iterations)] for _ in range(self.vert_positions_of_scan_window)] 
                                                    for _ in range(self.horiz_positions_of_scan_window)]
        #  create a grid structure for the movie with cell consisting of a Tkinter Frame object.
        for row in range(self.vert_positions_of_scan_window):
            for col in range (self.horiz_positions_of_scan_window):
                frames[row][col] = Tkinter.Frame(imageframe, width=cell_width, height=cell_height, bg=colors[(row*self.horiz_positions_of_scan_window+col) % len(colors)])
                frames[row][col].grid(row=row, column=col, sticky=W+E+N+S)
                model_im_index = row * self.horiz_positions_of_scan_window + col  
                model_images[row][col] = self.model_subimages_with_retained_pixels[model_im_index]
        colspan = self.horiz_positions_of_scan_window
        rownext = self.vert_positions_of_scan_window
        # Now add the notification widgets:
        iterationIndexFrame = Tkinter.Frame(imageframe, height=10).grid(row=rownext+1, column=0, columnspan=colspan, sticky=W+E+N+S)
        iterationLabelText = Tkinter.StringVar()
        Tkinter.Label(iterationIndexFrame,
                      textvariable = iterationLabelText,
                      anchor = 'c',
                      relief = 'groove',
                     ).pack(side='top', padx=10, pady=10)
        separator = Tkinter.Frame(imageframe, height=10, bd=1, relief=Tkinter.SUNKEN).grid(row=rownext+2, column=0, columnspan=colspan, sticky=W+E+N+S)
        buttonframe = Tkinter.Frame(imageframe, height=10).grid(row=rownext+3, column= 0, columnspan=colspan, sticky=W+E+N+S)
        tkFont.nametofont('TkDefaultFont').configure(size=20)    
        helv36 = tkFont.Font(family="Helvetica", size=28, weight='bold')    
        Tkinter.Button(buttonframe, 
                       text = 'Play movie again',                
                       anchor = 'c',
                       relief = 'raised',
                       font = helv36,
                       command = lambda: self.callbak(canvasroot)
                      ).pack(side='top', padx=10, pady=5)
        separator = Tkinter.Frame(imageframe, height=10, bd=1, relief=Tkinter.SUNKEN).grid(row=rownext+4, column=0, columnspan=colspan, sticky=W+E+N+S)
        messageFrame = Tkinter.Frame(imageframe, height=10).grid(row=rownext+5, column=0, columnspan=colspan, sticky=W+E+N+S)
        messageLabelText = Tkinter.StringVar()
        Tkinter.Label(messageFrame,
                      textvariable = messageLabelText,
                      anchor = 'c',
                      relief = 'groove',
                     ).pack(side='top', padx=10, pady=10)
        messageLabelText.set("NOTE: It is best to NOT close this window\nuntil all iterations are completed.")
        # colorize the model subimages:
        print("\nColorizing the retained-pixels images as obtained from the model subimages --- could take a while")
        for row in range(self.vert_positions_of_scan_window):
            for col in range (self.horiz_positions_of_scan_window):
                print("colorizing model subimage at (%d,%d)" % (row,col))
                imwidth,imheight = model_images[row][col].size
                (mingray,maxgray) = model_images[row][col].getextrema()
                model_color_images[row][col] = Image.new("RGB", (imwidth,imheight), (0,0,0))
                for m in range(imwidth):
                    for n in range(imheight):
                        color_val = model_images[row][col].getpixel((m,n)) * int(255/maxgray)
                        model_color_images[row][col].putpixel((m,n), (color_val, 0, 0))
                        dir_index = row * self.horiz_positions_of_scan_window + col  
        # Construct color versions of the result images (these are images with the retained pixels) in 
        # the __result_X drectories:
        print("""\nColorizing the retained-pixels images as obtained from the data subimages for each of the iterations"""
              """ of the ICP algorithm.  Depending on the number of iterations, this step could take a while.""")
        self.dir_rootname_for_results = "__result_"
        for row in range(self.vert_positions_of_scan_window):
            for col in range (self.horiz_positions_of_scan_window):
                for i in range(0,self.iterations):
                    dir_index = row * self.horiz_positions_of_scan_window + col  
                    self.dir_name_for_results = self.dir_rootname_for_results + str(dir_index)
                    result_im = Image.open(self.dir_name_for_results + "/__result" + str(i) + ".jpg")
                    (mingray,maxgray) = result_im.getextrema()
                    rwidth,rheight = result_im.size
                    result_color_im = Image.new("RGB", (rwidth,rheight), (0,0,0))
                    for m in range(rwidth):
                        for n in range(rheight):
                            if result_im.getpixel((m,n)) > 0:
                                color_val = result_im.getpixel((m,n)) * int(255/maxgray)
                                result_color_im.putpixel((m,n),(0,color_val,0))
                    result_color_im.save( self.dir_name_for_results + "/__result_color" + str(i) + ".jpg")
        # Now run the movie:
        self.iteration_control_flag = 1
        while self.iteration_control_flag:
            for i in range(0,self.iterations):
                try:
                    for row in range(self.vert_positions_of_scan_window):
                        for col in range(self.horiz_positions_of_scan_window):        
                            dir_index = row * self.horiz_positions_of_scan_window + col  
                            tkim[row][col][i] = Image.open("__result_" + str(dir_index) + "/__result_color" + str(i) + ".jpg")
                            out_image = ImageChops.add( model_color_images[row][col], tkim[row][col][i] )
#                            out_out_image = out_image.resize((400,400), Image.ANTIALIAS)
                            out_out_image = out_image.resize((self.scanning_window_width,self.scanning_window_height), Image.ANTIALIAS)
                            out_photo_image[row][col][i] = ImageTk.PhotoImage( out_out_image )
                            label_image[row][col][i] = Tkinter.Label(frames[row][col],image=out_photo_image[row][col][i],borderwidth=2,relief="solid")
#                            label_image[row][col][i].place(x=0,y=0,width=400,height=400)
                            label_image[row][col][i].place(relx=0.02,rely=0.02,relwidth=0.98,relheight=0.98)
                    iterationLabelText.set( "Iteration Number: " + str(i+1) )
                    self.iteration_control_flag = 0
                    if i < self.iterations - 1: root.after(1000, root.quit)       
                    root.mainloop(0)
                except IOError: pass

    def cleanup_scanner_examples_directory(self):
        for filename in glob.glob( '__result*/*' ):
            os.unlink(filename)
        for filename in glob.glob( '__model/*' ):
            os.unlink(filename)
        for directory_name in glob.glob( '__result*' ):
            os.rmdir(directory_name)
        os.rmdir('__model')

    #______________________  Private Methods of the ICPImageScanner Class  ____________________

    def _extract_pixels_from_subimage(self, model_or_data):
        if model_or_data == "model":
            im = self.model_subimage
        else:
            im = self.data_subimage
        im = im.convert('L')        ## convert to gray level
        im.thumbnail( (self.calculation_image_size, self.calculation_image_size), Image.ANTIALIAS )
        if self.debug: im.show()
        width,height = im.size
        if self.debug: print("width: %d    height: %d" % (width, height))
        dx = numpy.zeros((height, width), dtype="float")
        dy = numpy.zeros((height, width), dtype="float")
        rval = numpy.zeros((height, width), dtype="float")  # rval at a pixel = determinant / trace^2
        result_im = Image.new("1", (width,height), 0)
        edge_im = Image.new("L", (width,height), 0)
        edge_pixel_list = []    
        corner_pixels = []
        # Note that array indexing is 'opposite' of the image indexing with the first index along what 
        # is y for the image and the second index along what is x for the image.  For the image, x is 
        # the horizontal axis to the right, y is the vertical axis pointing downwards.  In what follows, 
        # we treat i and j as the image coordinates.  That is, i increments horizontally to the right
        # and j increments vertically downwards.
        for i in range(3,width-3):
            for j in range(3,height-3):
                ip1,im1,jp1,jm1 = i+1,i-1,j+1,j-1
                dx[(j,i)] = (im.getpixel((ip1,jm1)) + 2*im.getpixel((ip1,j)) + \
                             im.getpixel((ip1,jp1))) -  (im.getpixel((im1,jm1)) + \
                             2*im.getpixel((im1,j)) + im.getpixel((im1,jp1))) 
                dy[(j,i)] = (im.getpixel((im1,jp1)) + 2*im.getpixel((i,jp1)) + \
                             im.getpixel((ip1,jp1))) -  (im.getpixel((im1,jm1)) + \
                             2*im.getpixel((i,jm1)) + im.getpixel((ip1,jm1))) 
        edge_pixel_dict = {}
        for i in range(3,width-3):                 # i is for horizontal axis to the right
            for j in range(3,height-3):            # j is for vertical axis to the bottom
                edge_strength = math.sqrt(dx[(j,i)]**2 + dy[(j,i)]**2)
                edge_im.putpixel((i,j), int(edge_strength))   
                if edge_strength > self.edge_detection_threshold:            
                    edge_pixel_dict["e_" + str(i) + "_" + str(j)] = edge_strength
        sorted_edge_pixels = sorted(edge_pixel_dict.keys(), \
                                      key=lambda x: edge_pixel_dict[x], reverse=True)
        if len(sorted_edge_pixels) > self.max_num_of_pixels_used_for_icp:
            sorted_edge_pixels = sorted_edge_pixels[0:self.max_num_of_pixels_used_for_icp]
        for pixel_label in sorted_edge_pixels: 
            parts = re.split(r'_', pixel_label)
            i_index,j_index = int(parts[-2]), int(parts[-1])
            edge_pixel_list.append((i_index,j_index))
            result_im.putpixel((i_index,j_index), 255)
        if self.debug: result_im.show()
        if model_or_data == "model":
            if os.path.exists("__model"):
                files = glob.glob("__model/*")
                map(lambda x: os.remove(x), files)
            else:
               os.mkdir("__model")
            result_im.save("__model/__model_subimage" + str(self.subimage_index) + ".jpg")
            self.model_subim_result = result_im
            self.model_list = edge_pixel_list
            self.model_subim_edge_map = edge_im
            if self.debug: edge_im.save("model_edge_image.jpg")
        else:
            if self.debug: result_im.save("data_image_pixels_retained.jpg")
            self.data_subim_result = result_im
            self.data_list = edge_pixel_list
            self.data_subim_edge_map = edge_im
            if self.debug: edge_im.save("data_edge_image.jpg")

    def _move(self, image_type):
        self.num_remaining_pos -= 1
        print("Creating pixel values array for local window at block index: %d" % self.block_index)
        original_im = self.model_im if image_type == 'model' else self.data_im
        scanner_dump_directory = self.scanner_dump_directory_model if image_type == 'model' else self.scanner_dump_directory_data
        for x in range(self.x_incr * self.scanning_window_width, (self.x_incr + 1) * self.scanning_window_width):        
            for y in range(self.y_incr * self.scanning_window_height, (self.y_incr + 1) * self.scanning_window_height):
                r,g,b = original_im.getpixel((x,y))
                self.array_R[y % self.scanning_window_height, x % self.scanning_window_width] = r
                self.array_G[y % self.scanning_window_height, x % self.scanning_window_width] = g
                self.array_B[y % self.scanning_window_height, x % self.scanning_window_width] = b
        height,width = self.array_R.shape
        newimage = Image.new("RGB", (width,height), (0,0,0))
        for i in range(0, height):
            for j in range(0, width):
                r,g,b = self.array_R[i,j], self.array_G[i,j], self.array_B[i,j]
                newimage.putpixel((j,i), (r,g,b))
        newimage.save(scanner_dump_directory +  "/subimage_" + str(self.block_index) + ".jpg")
        width,height = newimage.size
        tk2 = Tkinter.Toplevel(takefocus = True)
        winsize_x,winsize_y = None,None
        screen_width,screen_height = tk2.winfo_screenwidth(),tk2.winfo_screenheight()
        if screen_width <= screen_height:
            winsize_x = int(0.5 * screen_width)
            winsize_y = int(winsize_x * (height * 1.0 / width))            
        else:
            winsize_y = int(0.5 * screen_height)
            winsize_x = int(winsize_y * (width * 1.0 / height))
        display_image = newimage.resize((winsize_x,winsize_y), Image.ANTIALIAS)
        tk2.title("scanned window")   
        frame = Tkinter.Frame(tk2, relief=RIDGE, borderwidth=2)
        frame.pack(fill=BOTH,expand=1)
        photo_image = ImageTk.PhotoImage( display_image )
        label = Tkinter.Label(frame, image=photo_image)
        label.pack(fill=X, expand=1)
        tk2.update()
        print("========= done with scan window display =========")
        response = pymsgbox.confirm("Done with viewing scan window?")
        if response == "OK": 
            tk2.after(10, self._callback, tk2)
        new_posx = self.old_posx + self.delta_x
        if new_posx + self.delta_x < int(self.image_width * self.scale_x):
            self.canvas.move( self.rect, self.delta_x, 0)
            self.old_posx = new_posx
            self.x_incr += 1
        elif self.old_posy + 2 * self.delta_y < int(self.image_height * self.scale_y):
            self.canvas.move( self.rect, -1 * self.moves_horizontal * self.delta_x, self.delta_y ) 
            self.old_posx = 0
            self.x_incr = 0
            self.old_posy += self.delta_y
            self.y_incr += 1    
        self.canvas.update()
        self.block_index += 1
        if self.num_remaining_pos > 0:
            self._move(image_type)

    def _move_noninteractive(self):
        if self.block_index == 0:
            time.sleep(1)             # one second
        self.num_remaining_pos -= 1
        print("Creating pixel values array for local window at block index: %d" % self.block_index)
        for x in range(self.x_incr * self.scanning_window_width, (self.x_incr + 1) * self.scanning_window_width):        
            for y in range(self.y_incr * self.scanning_window_height, (self.y_incr + 1) * self.scanning_window_height):
                r,g,b = self.original_im.getpixel((x,y))
                self.array_R[y % self.scanning_window_height, x % self.scanning_window_width] = r
                self.array_G[y % self.scanning_window_height, x % self.scanning_window_width] = g
                self.array_B[y % self.scanning_window_height, x % self.scanning_window_width] = b
        height,width = self.array_R.shape
        newimage = Image.new("RGB", (width,height), (0,0,0))
        for i in range(0, height):
            for j in range(0, width):
                r,g,b = self.array_R[i,j], self.array_G[i,j], self.array_B[i,j]
                newimage.putpixel((j,i), (r,g,b))
        newimage.save(self.scanner_dump_directory + "/subimage_" + str(self.block_index) + ".jpg")
        new_posx = self.old_posx + self.delta_x
        if new_posx + self.delta_x < int(self.image_width * self.scale_x):
            self.canvas.move( self.rect, self.delta_x, 0)
            self.old_posx = new_posx
            self.x_incr += 1
        elif self.old_posy + 2 * self.delta_y < int(self.image_height * self.scale_y):
            # we need to bring the window back from the last col to the first col in the next row:
            self.canvas.move( self.rect, -1 * self.moves_horizontal * self.delta_x, self.delta_y ) 
            self.old_posx = 0
            self.x_incr = 0
            self.old_posy += self.delta_y
            self.y_incr += 1
        self.canvas.update()
        self.block_index += 1
        if self.num_remaining_pos > 0:
            self._move_noninteractive()

    def _callback(self,arg):
        arg.destroy()

#_________________________  End of ICPImageScanner Class Definition ___________________________