__version__ = '2.2.1'
__author__ = "Avinash Kak (kak@purdue.edu)"
__date__ = '2018-September-10'
__url__ = 'https://engineering.purdue.edu/kak/distWatershed/Watershed-2.2.1.html'
__copyright__ = "(C) 2018 Avinash Kak. Python Software Foundation."
from Watershed import Watershed
from PIL import Image
from PIL import ImageDraw
from PIL import ImageTk
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 *
else:
import Tkinter
from Tkconstants import *
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 ImageScanner(Watershed):
'''
This class is useful when dealing with large images that contain small objects of
interest. Consider the fact that large digital images (images of size 5472x3648
or larger) can now be routinely recorded with inexpensive digital cameras. If
you are interested in segmenting out small objects (objects that may occupy only
a couple of hundred pixels), the algorithm development for detections is best
carried out on a subimage basis. That is, you first divide the large image into
overlapping or non-overlapping subimages and then focus on reliable object
detection in the subimages. This is where you'll find the ImageScanner class
useful. This class comes with methods that allow you to see the results of the
operations carried out in the subimages individually in the original large image.
'''
def __init__(self, *args, **kwargs ):
if args:
raise ValueError(
'''ImageScanner constructor can only be called with keyword arguments for
the following keywords: data_image, binary_or_gray_or_color,
gradient_threshold_as_fraction, level_decimation_factor, padding,
size_for_calculations, max_gradient_to_be_reached_as_fraction,
color_filter, sigma, scanner_dump_directory, scanning_window_width,
scanning_window_height, subimage_filename, and debug''')
scanning_window_width = scanning_window_height = scanner_dump_directory = subimage_filename = dump_directory = debug = min_brightness_level = min_area_threshold = max_area_threshold = max_number_of_blobs = object_shape = None
if 'scanner_dump_directory' in kwargs : scanner_dump_directory = kwargs.pop('scanner_dump_directory')
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')
if 'subimage_filename' in kwargs : subimage_filename = kwargs.pop('subimage_filename')
if 'min_brightness_level' in kwargs : min_brightness_level = kwargs.pop('min_brightness_level')
if 'min_area_threshold' in kwargs : min_area_threshold = kwargs.pop('min_area_threshold')
if 'max_area_threshold' in kwargs : max_area_threshold = kwargs.pop('max_area_threshold')
if 'max_number_of_blobs' in kwargs : max_number_of_blobs = kwargs.pop('max_number_of_blobs')
if 'object_shape' in kwargs : object_shape = kwargs.pop('object_shape')
Watershed.__init__(self, **kwargs)
self.mw = None
self.canvas = None
self.image_w, self.image_h = None, None
self.scanning_window_width, self.scanning_window_height = scanning_window_width, scanning_window_height
self.subimage_filename = subimage_filename
self.min_area_threshold = min_area_threshold
self.max_area_threshold = max_area_threshold
self.max_number_of_blobs = max_number_of_blobs
self.min_brightness_level = min_brightness_level
self.scanner_dump_directory = scanner_dump_directory
self.object_shape = object_shape
self.scale_x, self.scale_y = None, None
self.moves_horizontal, self.moves_vertical = None, None
self.delta_x, self.delta_y = None, None
self.x_incr, self.y_incr = 0,0
self.old_posx, self.old_posy = 0,0
self.iteration_index = 0
self.rect = None
self.total_num_window_pos = None
self.num_remaining_pos = None
self.block_index = 0
if debug:
self.debug = debug
else:
self.debug = 0
self.wshed = Watershed(**kwargs)
def analyze_scanner_dump(self):
'''
The purpose of this method is to analyze ALL subimages in the scanner dump directory,
to generate the object detection results from each subimage, and, finally, to display the
locations of the detections collected from all the subimages in the original image.
'''
if (not os.path.exists(self.scanner_dump_directory)) or (len(glob.glob(self.scanner_dump_directory + "/*")) == 0):
sys.exit("Before you call analyze_scanner_dump(), you must create a scan dump by invoking scan_image_for_detections_interactive() or scan_image_for_detections() on an instance of the ImageScanner class). See the relevant example script in the ExamplesScanner directory for why.")
self.displayImage6(self.original_im, "input_image -- close window when done viewing")
self.image_width, self.image_height = self.original_im.size
print("size of the image is: %s" % str((self.image_width, self.image_height)))
print("\n\nAnalyzing contents of the subimage in file: %s" % self.subimage_filename)
M,N = self.scanning_window_width, self.scanning_window_height
image_name = self.data_im_name
hpos = self.image_width // self.scanning_window_width
vpos = self.image_height // self.scanning_window_height
positions_of_detected_objects = []
blocks_examined = 0
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))
scaled_image = self.original_im.copy().resize((winsize_x,winsize_y), Image.ANTIALIAS)
mw.title( image_name + ": Displaying detections" )
mw.configure( height = winsize_y, width = winsize_x )
canvas = Tkinter.Canvas( mw,
height = winsize_y,
width = winsize_x,
cursor = "crosshair" )
canvas.pack(fill=BOTH, expand=True)
frame = Tkinter.Frame(mw)
frame.pack( side = 'bottom' )
Tkinter.Button( frame,
text = 'Save',
command = lambda: canvas.postscript(file = image_name + "_detections.jpg")
).pack( side = 'left' )
Tkinter.Button( frame,
text = 'Exit',
command = lambda: mw.destroy(),
).pack( side = 'right' )
photo = ImageTk.PhotoImage( scaled_image )
canvas.create_image(winsize_x//2,winsize_y//2,image=photo)
scale_x = winsize_x / (self.image_width * 1.0)
scale_y = winsize_y / (self.image_height * 1.0)
print("\nx_scale: %f" % scale_x)
print("y_scale: %f" % scale_y)
rectscan = canvas.create_rectangle((0, 0, int(M*scale_x), int(N*scale_y)), width='7', outline='red')
old_posx, old_posy = 0,0
delta_x_mov_rect, delta_y_mov_rect = int(M * scale_x), int(N * scale_y)
canvas.update()
mw.update()
for filename in sorted(glob.glob("scanner_dump/*"), key=lambda x: file_index(x)):
print("\n\nAnalyzing contents of image block in file: %s" % filename)
if self.debug:
if blocks_examined in [0,1,2,3,4]:
blocks_examined += 1
continue
image_file_index = file_index(filename)
image_item = Image.open(filename)
width,height = image_item.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 = image_item.resize((winsize_x,winsize_y), Image.ANTIALIAS)
tk2.title("wait until results calculated for this subimage")
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()
# The second arg in what follows is for suppressing the showing of intermediate results
filtered_im = self.apply_color_filter_hsv_to_named_image_file(filename, False)
pixel_coords = self.connected_components_of_filtered_output(filtered_im, self.min_brightness_level, self.min_area_threshold, self.max_area_threshold, self.max_number_of_blobs, self.object_shape, False)
print("Number of objects detected: %d" % len(pixel_coords))
upper_left_corner = ((image_file_index % hpos) * M, (image_file_index//hpos) * N)
real_pixel_coords = map(lambda x: (upper_left_corner[0] + x[0], upper_left_corner[1] + x[1]), pixel_coords)
positions_of_detected_objects += real_pixel_coords
print("Pixel coordinates for detections: %s" % str(pixel_coords))
print("Real coordinates for detections: %s" % str(real_pixel_coords))
print("All coordinates for detections: %s" % str(positions_of_detected_objects))
original_image = self.original_im.copy()
width,height = original_image.size
for pixel in positions_of_detected_objects:
if all(x > 20 for x in pixel) and (pixel[0] < width-20) and (pixel[1] < height-20):
rect = canvas.create_rectangle((pixel[0]-20)*scale_x, (pixel[1]-20)*scale_y,
(pixel[0]+20)*scale_x, (pixel[1]+20)*scale_y, width='2', outline='red', fill='red')
canvas.update()
tk2.destroy()
new_posx = old_posx + delta_x_mov_rect
if new_posx + delta_x_mov_rect < int(self.image_width * scale_x):
canvas.move( rectscan, delta_x_mov_rect, 0)
old_posx = new_posx
elif old_posy + 2 * delta_y_mov_rect < int(self.image_height * scale_y):
# now we need to move rect all the way back to the first column in the next row:
canvas.move( rectscan, -1 * (hpos-1) * delta_x_mov_rect, delta_y_mov_rect )
old_posx = 0
old_posy += delta_y_mov_rect
canvas.update()
blocks_examined += 1
canvas.delete(rectscan)
canvas.update()
mw.mainloop()
return positions_of_detected_objects
def analyze_scanner_dump_and_show_intermediate_results(self):
'''
Like the previous method, the purpose of this method also is to analyze ALL subimages
in the scanner dump directory, to generate the object detection results from each subimage,
finally, to display the locations of the detections collected from all the subimages in
the original image. This method goes beyond the previous method by also displaying the
intermediate results obtained as the subimages are processed for object detections. The
intermediate results correspond to color filtering, binarizing, component labeling, etc.
'''
if (not os.path.exists(self.scanner_dump_directory)) or (len(glob.glob(self.scanner_dump_directory + "/*")) == 0):
sys.exit("Before you call analyze_scanner_dump_and_show_intermediate_results(), you must create a scan dump by invoking scan_image_for_detections_interactive() or scan_image_for_detections() on an instance of the ImageScanner class). See the relevant example script in the ExamplesScanner directory for why.")
self.displayImage6(self.original_im, "input_image -- close window when done viewing")
self.image_width, self.image_height = self.original_im.size
print("size of the image is: %s" % str((self.image_width,self.image_height)))
print("\n\nAnalyzing contents of the subimage in file: %s" % self.subimage_filename)
M,N = self.scanning_window_width, self.scanning_window_height
image_name = self.data_im_name
hpos = self.image_width // self.scanning_window_width
vpos = self.image_height // self.scanning_window_height
positions_of_detected_objects = []
blocks_examined = 0
for filename in sorted(glob.glob(self.scanner_dump_directory + "/*"), key=lambda x: file_index(x)):
print("\n\nAnalyzing contents of image block in file: %s" % filename)
if self.debug:
if blocks_examined in [0,1,2,3,4]:
blocks_examined += 1
continue
image_file_index = file_index(filename)
image_item = Image.open(filename)
self.displayImage3(image_item, "image: %s -- close window when done viewing" % filename)
filtered_im = self.apply_color_filter_hsv_to_named_image_file(filename)
pixel_coords = self.connected_components_of_filtered_output(filtered_im, self.min_brightness_level, self.min_area_threshold, self.max_area_threshold, self.max_number_of_blobs, self.object_shape)
print("Number of objects detected: %d" % len(pixel_coords))
upper_left_corner = ((image_file_index % hpos) * M, (image_file_index//hpos) * N)
real_pixel_coords = map(lambda x: (upper_left_corner[0] + x[0], upper_left_corner[1] + x[1]), pixel_coords)
positions_of_detected_objects += real_pixel_coords
print("Pixel coordinates for detections: %s" % str(pixel_coords))
print("Real coordinates for detections: %s" % str(real_pixel_coords))
print("All coordinates for detections: %s" % str(positions_of_detected_objects))
original_image = self.original_im.copy()
width,height = original_image.size
for pixel in positions_of_detected_objects:
if all(x > 20 for x in pixel) and (pixel[0] < width-20) and (pixel[1] < height-20):
for i in range(-20,20):
for j in range(-20,20):
original_image.putpixel((pixel[0]+i,pixel[1]+j), (255,0,0))
self.displayImage6(original_image, "image with detections -- close window when done viewing")
blocks_examined += 1
return positions_of_detected_objects
def analyze_single_subimage_from_image_scan(self):
'''
The purpose of this method is to examine the results of object detection for a single subimage
chosen from all the subimages in the scanner dump directory. It is assumed that the subimage
file is in a directory named by the 'dump_directory' instance variable.
'''
if (not os.path.exists(self.scanner_dump_directory)) or (len(glob.glob(self.scanner_dump_directory + "/*")) == 0):
sys.exit("Before you call analyze_single_subimage_from_image_scan(), you must create a scan dump by invoking scan_image_for_detections_interactive() or scan_image_for_detections() on an instance of the ImageScanner class). See the relevant example script in the ExamplesScanner directory for why.")
self.displayImage6(self.original_im, "input_image -- close window when done viewing")
self.image_width, self.image_height = self.original_im.size
print("size of the image is: %s" % str((self.image_width,self.image_height)))
print("\n\nAnalyzing contents of the subimage in file: %s" % self.subimage_filename)
M,N = self.scanning_window_width, self.scanning_window_height
subimage_file_index = file_index(self.subimage_filename)
image_name = self.data_im_name
hpos = self.image_width // self.scanning_window_width
vpos = self.image_height // self.scanning_window_height
positions_of_detected_objects = []
subimage = Image.open(self.subimage_filename)
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))
scaled_image = self.original_im.resize((winsize_x,winsize_y), Image.ANTIALIAS)
mw.title( image_name + ": Displaying detections" )
mw.configure( height = winsize_y, width = winsize_x )
canvas = Tkinter.Canvas( mw,
height = winsize_y,
width = winsize_x,
cursor = "crosshair" )
canvas.pack(fill=BOTH, expand=True)
frame = Tkinter.Frame(mw)
frame.pack( side = 'bottom' )
Tkinter.Button( frame,
text = 'Save',
command = lambda: canvas.postscript(file = image_name + "_detections.jpg")
).pack( side = 'left' )
Tkinter.Button( frame,
text = 'Exit',
command = lambda: mw.destroy(),
).pack( side = 'right' )
photo = ImageTk.PhotoImage( scaled_image )
canvas.create_image(winsize_x//2,winsize_y//2,image=photo)
scale_x = winsize_x / (self.image_width * 1.0)
scale_y = winsize_y / (self.image_height * 1.0)
print("\nx_scale: %f" % scale_x)
print("y_scale: %f" % scale_y)
rectscan = canvas.create_rectangle((0, 0, int(M*scale_x), int(N*scale_y)), width='7', outline='red')
horiz_move_to_pos = (subimage_file_index % hpos) * int(M * scale_x)
vert_move_to_pos = (subimage_file_index // hpos) * int(N * scale_y)
canvas.move(rectscan, horiz_move_to_pos, vert_move_to_pos)
canvas.update()
mw.update()
image_item = Image.open(self.subimage_filename)
width,height = image_item.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 * (self.scanning_window_height * 1.0 / self.scanning_window_width))
else:
winsize_y = int(0.5 * screen_height)
winsize_x = int(winsize_y * (self.scanning_window_width * 1.0 / self.scanning_window_height))
display_image = image_item.resize((winsize_x,winsize_y), Image.ANTIALIAS)
tk2.title("wait for the results to appear in the other 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()
filtered_im = self.apply_color_filter_hsv_to_named_image_file(self.subimage_filename, False)
pixel_coords = self.connected_components_of_filtered_output(filtered_im, self.min_brightness_level, self.min_area_threshold, self.max_area_threshold, self.max_number_of_blobs, self.object_shape, False)
print("Number of objects detected: %d" % len(pixel_coords))
upper_left_corner = ((subimage_file_index % hpos) * M, (subimage_file_index//hpos) * N)
real_pixel_coords = map(lambda x: (upper_left_corner[0] + x[0], upper_left_corner[1] + x[1]), pixel_coords)
positions_of_detected_objects += real_pixel_coords
print("Pixel coordinates for detections: %s" % str(pixel_coords))
print("Real coordinates for detections: %s" % str(real_pixel_coords))
print("All coordinates for detections: %s" % str(positions_of_detected_objects))
original_image = self.original_im.copy()
width,height = original_image.size
for pixel in positions_of_detected_objects:
if all(x > 20 for x in pixel) and (pixel[0] < width-20) and (pixel[1] < height-20):
rect = canvas.create_rectangle((pixel[0]-20)*scale_x, (pixel[1]-20)*scale_y,
(pixel[0]+20)*scale_x, (pixel[1]+20)*scale_y, width='2', outline='red', fill='red')
canvas.update()
mw.mainloop()
return positions_of_detected_objects
def analyze_single_subimage_from_image_scan_and_show_intermediate_results(self):
'''
As for the previous method, the purpose of this method is to examine the results of object detection
for a single subimage chosen from all the subimages that are stored in the scanner dump directory.
It is assumed that the subimage file is in a directory that is named by the 'dump_directory' instance
variable.
'''
if (not os.path.exists(self.scanner_dump_directory)) or (len(glob.glob(self.scanner_dump_directory + "/*")) == 0):
sys.exit("Before invoking analyze_single_subimage_from_image_scan_and_show_intermediate_results(), you must first create scan dump of subimages by invoking scan_image_for_detections_interactive() or scan_image_for_detections() on an instance of the ImageScanner class. See the relevant example script in the ExamplesScanner directory for why.")
self.displayImage6(self.original_im, "input_image -- close window when done viewing")
self.image_width, self.image_height = self.original_im.size
print("size of the image is: %s" % str((self.image_width,self.image_height)))
print("\n\nAnalyzing contents of the subimage in file: %s" % self.subimage_filename)
M,N = self.scanning_window_width, self.scanning_window_height
subimage_file_index = file_index(self.subimage_filename)
image_name = self.data_im_name
hpos = self.image_width // self.scanning_window_width
vpos = self.image_height // self.scanning_window_height
positions_of_detected_objects = []
subimage = Image.open(self.subimage_filename)
tk2 = Tkinter.Tk()
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 * (self.scanning_window_height * 1.0 / self.scanning_window_width))
else:
winsize_y = int(0.5 * screen_height)
winsize_x = int(winsize_y * (self.scanning_window_width * 1.0 / self.scanning_window_height))
display_image = subimage.resize((winsize_x,winsize_y), Image.ANTIALIAS)
tk2.title("subimage -- close when done viewing")
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.mainloop()
filtered_im = self.apply_color_filter_hsv_to_named_image_file(self.subimage_filename)
pixel_coords = self.connected_components_of_filtered_output(filtered_im, self.min_brightness_level, self.min_area_threshold, self.max_area_threshold, self.max_number_of_blobs, self.object_shape)
print("Number of objects detected: %d" % len(pixel_coords))
upper_left_corner = ((subimage_file_index % hpos) * M, (subimage_file_index//hpos) * N)
real_pixel_coords = map(lambda x: (upper_left_corner[0] + x[0], upper_left_corner[1] + x[1]), pixel_coords)
positions_of_detected_objects += real_pixel_coords
print("Pixel coordinates for detections: %s" % str(pixel_coords))
print("Real coordinates for detections: %s" % str(real_pixel_coords))
print("All coordinates for detections: %s" % str(positions_of_detected_objects))
import pymsgbox
response = pymsgbox.confirm("Do you want to see the object coordinates in the main image?")
if response == "OK":
orig_image = self.original_im.copy()
orig_image_w,orig_image_h = self.original_im.size
print("size of the image is: %s" % str((orig_image_w,orig_image_h)))
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 * (orig_image_h * 1.0 / orig_image_w))
else:
winsize_y = int(0.5 * screen_height)
winsize_x = int(winsize_y * (orig_image_w * 1.0 / orig_image_h))
scaled_image = orig_image.resize((winsize_x,winsize_y), Image.ANTIALIAS)
mw.title( image_name + ": Displaying detections" )
mw.resizable(True,True)
mw.configure( height = winsize_y, width = winsize_x )
canvas = Tkinter.Canvas( mw,
height = winsize_y,
width = winsize_x,
cursor = "crosshair" )
canvas.pack(fill=BOTH, expand=True)
frame = Tkinter.Frame(mw)
frame.pack( side = 'bottom' )
Tkinter.Button( frame,
text = 'Save',
command = lambda: canvas.postscript(file = image_name + "_detections.jpg")
).pack( side = 'left' )
Tkinter.Button( frame,
text = 'Exit',
command = lambda: mw.destroy(),
).pack( side = 'right' )
photo = ImageTk.PhotoImage( scaled_image )
canvas.create_image(winsize_x//2,winsize_y//2,image=photo)
scale_x = winsize_x / (orig_image_w * 1.0)
scale_y = winsize_y / (orig_image_h * 1.0)
print("\nx_scale: %f" % scale_x)
print("y_scale: %f" % scale_y)
rectscan = canvas.create_rectangle((0, 0, int(M*scale_x), int(N*scale_y)), width='7', outline='red')
horiz_move_to_pos = (subimage_file_index % hpos) * int(M * scale_x)
vert_move_to_pos = (subimage_file_index // hpos) * int(N * scale_y)
canvas.move(rectscan, horiz_move_to_pos, vert_move_to_pos)
for pixel in positions_of_detected_objects:
if all(x > 20 for x in pixel) and (pixel[0] < orig_image_w-20) and (pixel[1] < orig_image_h-20):
rect = canvas.create_rectangle((pixel[0]-20)*scale_x, (pixel[1]-20)*scale_y,
(pixel[0]+20)*scale_x, (pixel[1]+20)*scale_y, width='2', outline='red', fill='red')
canvas.update()
mw.update()
mw.mainloop()
return positions_of_detected_objects
def scan_image_for_detections_interactive(self):
'''
This method creates a dump of subimages extracted from a large image. The method is
interactive in the sense that it does shows the user each subimage for his/her examination
before dumping it in the dump directory.
'''
self.displayImage6(self.original_im, "input_image -- close window when done viewing")
M,N = self.scanning_window_width, self.scanning_window_height
image = self.original_im.copy()
self.image_width,self.image_height = self.original_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"):
files = glob.glob("scanner_dump/*")
map(lambda x: os.remove(x), files)
else:
os.mkdir("scanner_dump")
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.iteration_index = 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()
mw.mainloop()
def scan_image_for_detections_noninteractive(self):
'''
This method creates a dump of subimages extracted from a large image. The method is
noninteractive in the sense that it does not show the user each subimage for his/her
examination before dumping it in the dump directory.
'''
self.displayImage6(self.original_im, "input_image -- close window when done viewing")
M,N = self.scanning_window_width, self.scanning_window_height
image = self.original_im.copy()
self.image_width,self.image_height = self.original_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"):
files = glob.glob("scanner_dump/*")
map(lambda x: os.remove(x), files)
else:
os.mkdir("scanner_dump")
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.iteration_index = 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_noninteractive()
mw.mainloop()
#______________________ Private Methods of the ImageScanner Class ________________
def _move(self):
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")
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()
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 ImageScanner Class Definition ___________________________