1. Image Analysis of SEM Images
Principal Adviser
Professor P A Deshpande
(IIT Kharagpur, Chemical Engineering Department)
Submitted by-
Vartika Sharma
(Summer Intern 2014, LNMIIT)
2. Introduction to SEM Images
A scanning electron microscope (SEM) is a type of electron microscope that produces images of a
sample by scanning it with a focused beam of electrons.
The SEM image a 2D intensity map. Each image pixel on the display corresponds to a point on the
sample, which is proportional to the signal intensity captured by the detector at each specific point.
Fig1: Each image pixel on the display corresponds to a point on the sample
So basically, no true image exists in the SEM. It is not possible to place a film anywhere in the SEM
and record an image. It does not exist. The image is generated and displayed electronically.
Digital Image
A digital image is a digital array or a matrix, where the row and column indices identify a point in the
image and corresponding matrix element value identifies the gray level at that point. The element of
such a digital array are called image elements or pixels.
To get the pixel value at the co-ordinates of the Digital Image:
from PIL import Image
image = Image.open(“image.png”).convert('L')
[width, height] = image.size # For getting width and height of the image
for x in range(width):
for y in range(height):
p = image.getPixel([x, y])
3. Need for Image Analysis
The SEM images contain a wealth of objects and patterns, which may convey a lot of information like
how many cells are there in the field of view of a SEM image, what is the average size of each cell, etc.
Image processing and analysis provides a means to extract and quantify objects and patterns in
image data and obtain answers to such meaningful questions.
Microscopy images in biology are often complex, noisy, artifact-laden and consequently require
multiple image processing steps for the extraction of meaningful quantitative information.
After the pre-processing steps like contrast adjustment and spatial filtering, we can apply various
computational techniques to extract features and patterns from the images.
Fig2: Outline of the steps involved in Image Processing
In my work, I will describe various tools of morphological image processing and image segmentation
that can be used for this purpose. And then focus on Image segmentation using Monte Carlo method.
Converting RGB (true color) Image into Grayscale Image
A grayscale image is an image in which the value of each pixel is a single sample, that is, it carries only
intensity information. Grayscale images are often the result of measuring the intensity of light at each
4. pixel in a single band of the electromagnetic spectrum.
To map each color pixel, described by a triple (R, G, B) of intensities for red, green, and blue, into a
single number giving a 'grayscale' value, we take weighted averages of these three values.
A simple python program for this conversion is:
import cv2
from PIL import Image
import numpy
x = Image.open("red1.jpg")
x.show()
rgb = cv2.imread("red1.jpg")
rgb = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)
cv2.imwrite("gray_image2.jpg", rgb)
gray = Image.open("gray_image2.jpg")
gray.show()
Fig3: RGB (True Color) Image Fig4: Grayscale Image
Converting Gray scale Image into binary Image
• Image Thresholding
One simple way of converting a grayscale image into binary image is thresholding. In thresholding, we
chose an arbitrary pixel value (usually somewhere in the middle or depending upon the lighting
conditions of the image). If pixel value is greater than that value, it is assigned one value (white or
255), else it is assigned another value (black or 0).
Thresholding is also used to extract an object from its background by assigning an intensity value
T(threshold) for each pixel such that each pixel is either classified as an object point or a background
point.
Python program for image thresholding is -
import cv2
from PIL import Image
5. import numpy
gray = Image.open("image.jpg").convert('L') #Converts the RGB image into grayscale
gray.show()
bw = numpy.array(gray)
bw[bw<128] = 0
bw[bw>=128] = 255
imfile = Image.fromarray(bw)
imfile.save("new_bw.jpg")
newb = Image.open("new_bw.jpg")
newb.show()
Fig5: Grayscale Image Fig6: Binary Image
Note - Otsu's Binarization technique is used for automatically calculating a threshold value
from image histogram for an image.
• Adaptive Image Thresholding
Thresholding by taking a single arbitrary value may not be good in all the conditions where image has
different lighting conditions in different areas. Here, we go for adaptive thresholding. The algorithm
calculate the threshold for 'small regions' of the image.
So we get different thresholds for different regions of the same image and it gives us better results for
images with varying illumination.
Gaussian threshold value is the weighted sum of neighborhood values where weights are a Gaussian
window.
A simple program in python to compare global thresholding and adaptive thresholding methods is -
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('image.png',0)
img = cv2.medianBlur(img,5) # Pre-processing step: spatial filtering
6. ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,11,2)
titles = ['Original Image', 'Binary Image(threshold = 127)', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2]
for i in xrange(3):
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
Fig7: Global Thresholding Fig8: Adaptive Thresholding
7. Clustering
Image clustering is a means for high-level description of image content. The goal is to find a mapping
of the archive images into classes (clusters) such that the set of classes provide essentially the same
information about the image archive as the entire image-set collection.
In other words, Cluster analysis is the task of grouping a set of objects in such a way that objects in the
same group (cluster) are more similar to each other than to those in other groups. It is a common
technique for image analysis.
• k-means Clustering
The k-means algorithm takes an iterative approach to generating clusters. The parameter k specifies the
desired number of clusters to generate. The algorithm begins with an initial set of cluster centers. Each
pixel in the image is then assigned to the nearest cluster center and each cluster center is then
recomputed as the centroid of all pixels assigned to the cluster. This process repeats until a desired
stopping criterion is reached.
Each step of the k-means algorithm refines the choices of centroids to reduce distortion. The change in
distortion is used as a stopping criterion: when the change is lower than a threshold, the k-means
algorithm is not making sufficient progress and terminates.
Below is a simple implementation of Lloyd’s algorithm for performing k-means clustering in python:
import numpy as np
def cluster_points(X, mu):
clusters = {}
for x in X:
bestmukey = min([(i[0], np.linalg.norm(x-mu[i[0]]))
for i in enumerate(mu)], key=lambda t:t[1])[0]
try:
clusters[bestmukey].append(x)
except KeyError:
clusters[bestmukey] = [x]
return clusters
def reevaluate_centers(mu, clusters):
newmu = []
keys = sorted(clusters.keys())
for k in keys:
newmu.append(np.mean(clusters[k], axis = 0))
return newmu
def has_converged(mu, oldmu):
return (set([tuple(a) for a in mu]) == set([tuple(a) for a in oldmu])
def find_centers(X, K):
8. # Initialize to K random centers
oldmu = random.sample(X, K)
mu = random.sample(X, K)
while not has_converged(mu, oldmu):
oldmu = mu
# Assign all points in X to clusters
clusters = cluster_points(X, mu)
# Reevaluate centers
mu = reevaluate_centers(oldmu, clusters)
return(mu, clusters)
(Source: http://datasciencelab.wordpress.com/2013/12/12/clustering-with-k-means-in-python/)
Fig9: Original Image Fig10: Clustering used to separate the circles
9. Image Segmentation
Segmentation is often considered to be the first step in image analysis. Segmentation means
subdividing an image into meaningful non-overlapping regions, which would be used for further
analysis. The result of image segmentation is a set of segments that collectively cover the entire image,
or a set of contours extracted from the image.
Each of the pixels in a region are similar with respect to some characteristic or computed property, such
as color, intensity, or texture. Adjacent regions are significantly different with respect to the same
characteristics.
Difference between Clustering and Segmentation
Clustering is the process of organizing objects into groups whose members are similar in some way.
While, Segmentation is dividing something into pieces according to some criteria.
For example, Segmentation is always possible, even in an extremely homogeneous collection of items.
You just decide where you will cut between the groups. However, finding clusters in this extremely
homogeneous collection is impossible, since by definition there are no density differences, and hence
no clusters to find.
• Watershed Segmentation
Watershed algorithm is useful for segmenting objects that are touching one another. Any grayscale
image can be viewed as a topographic surface where high intensity denotes peaks and hills while low
intensity denotes valleys.
The algorithm works as follows:
Suppose a hole is punched at each regional local minimum and the entire topography is flooded from
below by letting the water rise through the holes at a uniform rate.
Pixels below the water level at a given time are marked as flooded. When we raise the water
level incrementally, the flooded regions will grow in size. Eventually, the water will rise to a level
where two flooded regions from separate catchment basins will merge. When this occurs, the algorithm
constructs a one-pixel thick dam that separates the two regions. The flooding continues until the entire
image is segmented into separate catchment basins divided by watershed ridge lines.
Python Program for Watershed Segmentation:
Here, we want to separate the two objects in image . Generate the markers as local maxima of the
distance to the background .
image = cv2.imread(“image_seg.png”)
distance = ndimage.distance_transform_edt(image)
local_maxi = peak_local_max(distance, indices=False, footprint=np.ones((3, 3)),
labels=image)
markers = ndimage.label(local_maxi)[0]
labels = watershed(-distance, markers, mask=image)
10. fig, axes = plt.subplots(ncols=3, figsize=(8, 2.7))
ax0, ax1, ax2 = axes
ax0.imshow(image, cmap=plt.cm.gray, interpolation='nearest')
ax0.set_title('Overlapping objects')
ax1.imshow(-distance, cmap=plt.cm.jet, interpolation='nearest')
ax1.set_title('Distances')
ax2.imshow(labels, cmap=plt.cm.spectral, interpolation='nearest')
ax2.set_title('Separated objects')
for ax in axes:
ax.axis('off')
fig.subplots_adjust(hspace=0.01, wspace=0.01, top=1, bottom=0, left=0,
right=1)
plt.show()
Fig11: (a) Original Image (Overlapping Object), (b) Watershed Algorithm applied, (c) Segmented
Image (Separated Objects)
• Quick Shift Image Segmentation
The algorithm segments an RGB image (or any image with more than one channel) by identifying
clusters of pixels in the joint spatial and color dimensions. Segments are local (superpixels) and can be
used as a basis for further processing. 'Sigma' controls the scale of the local density approximation
'max_dist' selects a level in the hierarchical segmentation that is produced. There is also a trade-off
between distance in color-space and distance in image-space, given by 'ratio'.
import matplotlib.pyplot as plt
import numpy as np
import cv2
from skimage.segmentation import quickshift
from skimage.segmentation import mark_boundaries
from skimage.util import img_as_float
11. new = cv2.imread("seg1.jpg")
x = img_as_float(new[::2, ::2])
quick = quickshift(x, kernel_size=3, max_dist=6, ratio=0.5)
print("Quickshift number of segments: %d" % len(np.unique(quick)))
plt.imshow(mark_boundaries(x, quick))
plt.show()
Fig11: Original SEM Image Fig12: Quick Shift Segmented Image
Quickshift number of segments: 263
• K-Means based image segmentation
(Simple Linear Iterative Clustering Method)
Each pixel is associated to a feature vector and then k-means clustering is run on those.
k-means clustering aims to partition n observations into k clusters in which each observation belongs to
the cluster with the nearest mean, serving as a prototype of the cluster.
'n_segments' chooses the number of centers for kmeans.
(Source: http://www.vlfeat.org/api/slic.html)
import matplotlib.pyplot as plt
import numpy as np
import cv2
from skimage.segmentation import slic
from skimage.segmentation import mark_boundaries
from skimage.util import img_as_float
new = cv2.imread("seg4.jpg")
12. y = img_as_float(new[::2, ::2])
slic = slic(y, n_segments=250, compactness=10, sigma=1)
print("Slic number of segments: %d" % len(np.unique(slic)))
plt.imshow(mark_boundaries(y, slic))
plt.show()
Fig12: Original SEM Image Fig12: K-means based Segmented Image
Slic number of segments: 252
Introduction to graphs
A graph can be represented by G where G=(V,E). For the graph G, V is a set of vertices and E is a set of
edges. Each edge is a tuple (v,w) where w,v V. We can add a third component to the edge tuple to∈
represent a weight.
Vertex
A vertex (also called a “node”) is a fundamental part of a graph. It can have a name, which we will
call the “key.” A vertex may also have additional information. We will call this additional information
the “payload.”
Edge
An edge (also called an “arc”) is another fundamental part of a graph. An edge connects two vertices
to show that there is a relationship between them. Edges may be one-way or two-way. If the edges in a
graph are all one-way, we say that the graph is a directed graph, or a digraph. The class prerequisites
graph shown above is clearly a digraph since you must take some classes before others.
Weight
Edges may be weighted to show that there is a cost to go from one vertex to another. For example in
a graph of roads that connect one city to another, the weight on the edge might represent the distance
between the two cities.
13. Introduction to MCMC Methods and Swendsen Wang
Method
• Random Variable
In probability and statistics, a random variable is a variable whose value is subject to variations due to
chance.
• Markov Chains
A Markov Chain is a random process that has the property that the future depends only on the current
state of the process and not the past i.e. it is memoryless.
An example of a Markov Chain is the "drunkard's walk". Imagine somebody who is drunk and can
move only left or right by one pace. The drunk moves left or right with equal probability. This is a
Markov Chain where the drunk's future/next position depends only upon where he is at present.
• Monte Carlo Methods
Monte Carlo methods are computational algorithms of estimating something which is too difficult or
time consuming to find deterministically, randomly. By increasing the sample size, the law of large
numbers tells us we can increase the accuracy of our approximation by covering more and more of the
function.
• Markov Chain Monte Carlo Algorithm
These two concepts can be put together to solve some difficult problems in areas such as Bayesian
inference, computational biology, etc where multi-dimensional integrals need to be calculated to solve
common problems. The idea is to construct a Markov Chain which converges to the desired probability
distribution after a number of steps. The state of the chain after a large number of steps is then used as a
sample from the desired distribution and the process is repeated. There are many different MCMC
algorithms which use different techniques for generating the Markov Chain. Common ones include the
Metropolis-Hastings and the Gibbs Sampler.
The goal of MCMC is to draw samples from some probability distribution without having to know its
exact height at any point. The way MCMC achieves this is to "wander around" on that distribution in
such a way that the amount of time spent in each location is proportional to the height of the
distribution. If the "wandering around" process is set up correctly, you can make sure that this
proportionality (between time spent and height of the distribution) is achieved.
Intuitively, what we want to do is to to walk around on some (lumpy) surface in such a way that the
amount of time we spend in each location is proportional to the height of the surface at that location.
For example, we'd like to spend twice as much time on a hilltop that's at an altitude of 100m as we do
on a nearby hill that's at an altitude of 50m. The nice thing is that we can do this even if we don't know
the absolute heights of points on the surface: all we have to know are the relative heights. For example,
if one hilltop A is twice as high as hilltop B, then we'd like to spend twice as much time at A as we
14. spend at B.
The simplest variant of the Metropolis-Hastings algorithm achieves this as follows: assume that in
every time-step, we pick a random new "proposed" location (selected uniformly across the entire
surface). If the proposed location is higher than where we're standing now, move to it. If the proposed
location is lower, then move to the new location with probability p, where p is the ratio of the height of
that point to the height of the current location. (i.e., flip a coin with a probability p of getting heads; if it
comes up heads, move to the new location; if it comes up tails, stay where we are). Keep a list of the
locations you've been at on every time step, and that list will (asyptotically) have the right proportion of
time spent in each part of the surface. (And for the A and B hills described above, you'll end up with
twice the probability of moving from B to A as you have of moving from A to B).
There are more complicated schemes for proposing new locations and the rules for accepting them, but
the basic idea is still:
(1) Pick a new "proposed" location
(2) Figure out how much higher or lower that location is compared to your current location;
(3) Probabilistically stay put or move to that location in a way that respects the overall goal of spending
time proportional to height of the location.
Algorithms to perform MCMC
There is a large family of algorithms that perform MCMC. Simplestly, most algorithms can be
expressed at a high level as follows:
1. Start at current position.
2. Propose moving to a new position
3. Accept the position based on the position's adherence to the data and prior distributions
4. If you accept: Move to the new position. Return to Step 1.
5. After a large number of iterations, return the positions.
(Source: http://stats.stackexchange.com/)
• Slice Sampling
Slice sampling is a type of Markov chain Monte Carlo algorithm for pseudo-random number sampling,
i.e., for drawing random samples from a statistical distribution.
The method is based on the observation that to sample a random variable one can sample uniformly
from the region under the graph of its density function.
• Swendsen-Wang Algorithm
The Swendsen–Wang algorithm is an algorithm for Monte Carlo simulation of the Ising model in which
the entire sample is divided into same-spin clusters. Each cluster is then assigned a new random spin
value.
It is one of the first algorithms based on global changes to the system in a single sweep of moves. The
original algorithm was designed for the Ising and Potts models, and later it was generalized to other
systems as well. A key ingredient of the method is based on the representation of the Ising or Potts
model through percolation models of connecting bonds due to Fortuin and Kasteleyn. These bonds
15. form so-called clusters.
It has been generalized by Barbu and Zhu (2005) to sampling arbitrary probabilities by viewing it as a
Metropolis–Hastings algorithm and computing the acceptance probability of the proposed Monte Carlo
move. The Swendsen–Wang method often mixes much better than simple Markov chains
such as Gibbs sampling (that is, single-spin updates, also known as the heat bath method).
Swendsen–Wang does not propose moves that enable rapid Exploration.
• Data Augmentation
Data augmentation adds value to base data by adding information derived from internal and external
sources within an enterprise. Data augmentation can help reduce the manual interventation required to
developed meaningful information and insight of important data, as well as significantly enhance data
quality.
The term data augmentation refers to methods for constructing iterative optimization. In computational
mathematics, an iterative method is a mathematical procedure that generates a sequence of improving
approximate solutions for a class of problems.
Optimization is the selection of a best element (with regard to some criteria) from some set of available
alternatives.
• Auxiliary variable
If a variable that is known for every unit of the population is not a variable of interest but is instead
employed to improve the sampling plan or to enhance estimation of the variables of interest, it is called
an auxiliary variable.
PROBLEM STATEMENT
Develop an application that takes as input an image and a set of pixel co-ordinates, and
outputs an image which has been segmented based on the given input. The output may
contain one or more highlighted segments. The segments within the image will be
random closed shapes.
16. Image Segmentation Using Monte Carlo
(Generalizing Swendsen-Wang For Image Segmentation)
An image is made up of pixels. Each pixel has a certain discreet value attached to it, in the form of
RGB color values. Hence in essence an image can be considered as a grid graph where each pixel is
represented by a vertex in the grid graph.
Python Code for getting a Graph (set of pixel co-ordinates) from an Input Image:
import pymaxflow
import pylab
import numpy as np
eps = 0.01
im = pylab.imread("vpython/the.png").astype(np.float32)
indices = np.arange(im.size).reshape(im.shape).astype(np.int32)
g = pymaxflow.PyGraph(im.size, im.size * 3)
g.add_node(im.size)
# adjacent
diffs = np.abs(im[:, 1:] - im[:, :-1]).ravel() + eps
e1 = indices[:, :-1].ravel()
e2 = indices[:, 1:].ravel()
g.add_edge_vectorized(e1, e2, diffs, 0 * diffs)
# adjacent up
diffs = np.abs(im[1:, 1:] - im[:-1, :-1]).ravel() + eps
e1 = indices[1:, :-1].ravel()
e2 = indices[:-1, 1:].ravel()
g.add_edge_vectorized(e1, e2, diffs, 0 * diffs)
# adjacent down
diffs = np.abs(im[:-1, 1:] - im[1:, :-1]).ravel() + eps
e1 = indices[:-1, :-1].flatten()
e2 = indices[1:, 1:].ravel()
g.add_edge_vectorized(e1, e2, diffs, 0 * diffs)
out = g.what_segment_vectorized()
pylab.imshow(out.reshape(im.shape))
pylab.show()
Markov chains are simulated for sampling from a target probabilities п(X) defined on a graph G.
17. The graph vertices represent elements of the system, the edges represent spatial relationships while X is
a vector of variables on the vertices which often take discrete values called labels or colors.
In order to run a Markov chain on a weighted graph constructed from an image, we need to have an
initial state. Our main goal is to segment out certain parts of an image, but we don’t know what we are
supposed to segment out.
We can always ask a user to select certain pixels from different parts of the image that they need
segmented and brought out. These selected pixel values serve as the initial state for out Markov Chain.
The main idea behind this technique to segment out a part of an image is that, we want to group similar
pixels together.
Since the edge weights between similar pixels will have higher probability of being chosen, we can
design an algorithm around this fact.
The pixels or vertices that are selected by running the Markov chain can be marked and if we perform a
minimum cut on the graph of selected vertices, we may get a closed shape that will, in theory be the
desired segmented image.
(Source: http://www.cs.rit.edu/~ssv7680/Final_Proposal.pdf)
Now, the edges between two vertices or pixels will carry some weight w. This value of w is decided by
comparing the values of the neighboring pixels. Since we are trying to model this problem to form a
Markov chain, it would make sense to have the edge weight as probabilities.
Hence, we can define a function f(x,y) where x and y are two adjacent pixels which gives us w,
depending on how similar x and y are as compared to each other.
(It is important to note that the value of w will always be between 0 and 1)
In this method, we partition the image into a number of disjoint regions to reduce the size of the
adjacency graph. We use a Canny edge detector and edge tracing to divide the image into “atomic
regions” with almost constant intensities.
(Source: Barbu and Zhu Generalizing Swendsen-Wang to Sampling Arbitrary Posterior
Probabilities.pdf)
Python Program for Implementation of Canny Edge Detection:
f = 'vpython/the.png'
img = Image.open(f).convert('L') #grayscale
imgdata = numpy.array(img, dtype = float)
G = ndi.filters.gaussian_filter(imgdata, 2.2) #gaussian low pass filter
sobelout = Image.new('L', img.size) #empty image
gradx = numpy.array(sobelout, dtype = float)
grady = numpy.array(sobelout, dtype = float)
sobel_x = [[-1,0,1],
[-2,0,2],
[-1,0,1]]
sobel_y = [[-1,-2,-1],
[0,0,0],
[1,2,1]]
width = img.size[1]
18. height = img.size[0]
#calculate |G| and dir(G)
for x in range(1, width-1):
for y in range(1, height-1):
px = (sobel_x[0][0] * G[x-1][y-1]) + (sobel_x[0][1] * G[x][y-1]) +
(sobel_x[0][2] * G[x+1][y-1]) + (sobel_x[1][0] * G[x-1][y]) +
(sobel_x[1][1] * G[x][y]) + (sobel_x[1][2] * G[x+1][y]) +
(sobel_x[2][0] * G[x-1][y+1]) + (sobel_x[2][1] * G[x][y+1]) +
(sobel_x[2][2] * G[x+1][y+1])
py = (sobel_y[0][0] * G[x-1][y-1]) + (sobel_y[0][1] * G[x][y-1]) +
(sobel_y[0][2] * G[x+1][y-1]) + (sobel_y[1][0] * G[x-1][y]) +
(sobel_y[1][1] * G[x][y]) + (sobel_y[1][2] * G[x+1][y]) +
(sobel_y[2][0] * G[x-1][y+1]) + (sobel_y[2][1] * G[x][y+1]) +
(sobel_y[2][2] * G[x+1][y+1])
gradx[x][y] = px
grady[x][y] = py
sobeloutmag = scipy.hypot(gradx, grady)
sobeloutdir = scipy.arctan2(grady, gradx)
scipy.misc.imsave('cannynewmag.png', sobeloutmag)
scipy.misc.imsave('cannynewdir.png', sobeloutdir)
for x in range(width):
for y in range(height):
if (sobeloutdir[x][y]<22.5 and sobeloutdir[x][y]>=0) or
(sobeloutdir[x][y]>=157.5 and sobeloutdir[x][y]<202.5) or
(sobeloutdir[x][y]>=337.5 and sobeloutdir[x][y]<=360):
sobeloutdir[x][y]=0
elif (sobeloutdir[x][y]>=22.5 and sobeloutdir[x][y]<67.5) or
(sobeloutdir[x][y]>=202.5 and sobeloutdir[x][y]<247.5):
sobeloutdir[x][y]=45
elif (sobeloutdir[x][y]>=67.5 and sobeloutdir[x][y]<112.5)or
(sobeloutdir[x][y]>=247.5 and sobeloutdir[x][y]<292.5):
sobeloutdir[x][y]=90
else:
sobeloutdir[x][y]=135
scipy.misc.imsave('cannynewdirquantize.png', sobeloutdir)
mag_sup = sobeloutmag.copy()
for x in range(1, width-1):
for y in range(1, height-1):
if sobeloutdir[x][y]==0:
19. if (sobeloutmag[x][y]<=sobeloutmag[x][y+1]) or
(sobeloutmag[x][y]<=sobeloutmag[x][y-1]):
mag_sup[x][y]=0
elif sobeloutdir[x][y]==45:
if (sobeloutmag[x][y]<=sobeloutmag[x-1][y+1]) or
(sobeloutmag[x][y]<=sobeloutmag[x+1][y-1]):
mag_sup[x][y]=0
elif sobeloutdir[x][y]==90:
if (sobeloutmag[x][y]<=sobeloutmag[x+1][y]) or
(sobeloutmag[x][y]<=sobeloutmag[x-1][y]):
mag_sup[x][y]=0
else:
if (sobeloutmag[x][y]<=sobeloutmag[x+1][y+1]) or
(sobeloutmag[x][y]<=sobeloutmag[x-1][y-1]):
mag_sup[x][y]=0
scipy.misc.imsave('cannynewmagsup.png', mag_sup)
m = numpy.max(mag_sup)
th = 0.2*m
tl = 0.1*m
gnh = numpy.zeros((width, height))
gnl = numpy.zeros((width, height))
for x in range(width):
for y in range(height):
if mag_sup[x][y]>=th:
gnh[x][y]=mag_sup[x][y]
if mag_sup[x][y]>=tl:
gnl[x][y]=mag_sup[x][y]
scipy.misc.imsave('cannynewgnlbeforeminus.png', gnl)
gnl = gnl-gnh
scipy.misc.imsave('cannynewgnlafterminus.png', gnl)
scipy.misc.imsave('cannynewgnh.png', gnh)
def traverse(i, j):
x = [-1, 0, 1, -1, 1, -1, 0, 1]
y = [-1, -1, -1, 0, 0, 1, 1, 1]
for k in range(8):
if gnh[i+x[k]][j+y[k]]==0 and gnl[i+x[k]][j+y[k]]!=0:
gnh[i+x[k]][j+y[k]]=1
traverse(i+x[k], j+y[k])
for i in range(1, width-1):
for j in range(1, height-1):
if gnh[i][j]:
20. gnh[i][j]=1
traverse(i, j)
scipy.misc.imsave('cannynewout.png', gnh)
z = Image.open("cannynewout.png")
z.show()
Fig13: Original SEM Image Fig14: Canny Edge Detetion
Each disjoint region, which we get after Canny edge detection followed by edge tracing and contour
closing, is coherent in the sense of fitting to some image models.
We take G as an adjacency graph whose vertices V are a set of atomic region. The edge probability
should represent a good similarity measure between the intensity model of the atomic regions.
As an approximate model for each atomic region v in V, we choose a 15-bin histogram h normalized to
1.
We chose the edge probability as -
qij = exp{-1/2(KL(hi||hj)+KL(hj||hi))}
where KL() is the Kullback-Leibler divergence between the two histograms. Edge probability leads to
good clustering.
21. Swendsen-Wang method clusters the vertices as connected componets after turning off some edges
probabilistically, and changes the color of one cluster as a whole.
Fig15: SW method (a) An adjacency graph G where each edge <i,j> is augmented with a binary
variable μij in {1,0}. (b) Edge connecting vertices of different colors are removed. (c) A number of
connected components obtained by turning off some edges in (b) probablistically
In this paper, a general cluster algorithm is present which extends the SW algorithm to general
Bayesian inference on graphs, and then present application in Image Segmentation.
We interpret SW as a Metropolis-Hastings step using the auxiliary variables for proposing the moves.
Each step is a reversible jump. The key observation is that the proposal probability ratio can be
calculated neatly as a ratio of products of probabilities on a small number of edges on the border of the
cluster.
22. Future-work: I wish to complete the SW algorithm for image segmentation and implement it in
python, by the end of July.
I further wish to work on motion analysis and continue my work on other Computer Vision and image
processing problems.