'''
pathToDir = "../../Images/Chapter2/Input/"
imageName = "Giraffe.png"

# Read image into array
inputImage, width, height = imageReadL(pathToDir + imageName)

# Show input image
showImageL(inputImage)

# Create coefficients Image. Maximum frequency according to sampling
maxFreqW = int(width / 2)
maxFreqH = int(height / 2)
numCoeffW = 1 + 2 * maxFreqW
numCoeffH = 1 + 2 * maxFreqH
coeff = createImageF(numCoeffW, numCoeffH)

# Adjust the size of the data to be even
m = float(width)
n = float(height)
if width % 2 == 0:
    m = width + 1.0
if height % 2 == 0:
    n = height + 1.0

# Fundamental frequency
ww = (2.0 * pi) / m
wh = (2.0 * pi) / n

# Compute values
for u in range(-maxFreqW, maxFreqW + 1):
Exemple #2
0
    imageName = Input image name
'''
pathToDir = "../../Images/Chapter2/Input/"
imageName = "Giraffe.png"

# Read image into array
inputImage, width, height = imageReadL(pathToDir + imageName)

# Show images
showImageL(inputImage)

# Compute coefficients
coeff, maxFreqW, maxFreqH = computeCoefficients(inputImage)

# Create low and high versions
coeffLow = createImageF(1 + 2 * maxFreqW, 1 + 2 * maxFreqH, 2)
coeffHigh = createImageF(1 + 2 * maxFreqW, 1 + 2 * maxFreqH, 2)

# Filter
cutFrequency = maxFreqW / 8

for kw,kh in itertools.product(range(-maxFreqW, maxFreqW + 1),        \
                               range(-maxFreqH, maxFreqH + 1)):
    IndexW, indexH = kw + maxFreqW, kh + maxFreqH

    if sqrt(kw * kw + kh * kh) < cutFrequency:
        coeffLow[indexH, IndexW][0] = coeff[indexH, IndexW][0]
        coeffLow[indexH, IndexW][1] = coeff[indexH, IndexW][1]
    else:
        coeffHigh[indexH, IndexW][0] = coeff[indexH, IndexW][0]
        coeffHigh[indexH, IndexW][1] = coeff[indexH, IndexW][1]
maxDisp = 10
step = 10

# Read image into array. both images must have same size
inputImage1, width, height = imageReadL(pathToDir + image1Name)
inputImage2, _, _  = imageReadL(pathToDir + image2Name)

# Show input image
showImageL(inputImage1)
showImageL(inputImage2)

# The center of the kernel
kernelCentre = int((kernelSize - 1) / 2)

# Compute Motion in sampled points
motionMagnitude = createImageF(width, height)
motionDirection = createImageF(width, height)
motionWeight = createImageF(width, height)
for x,y in itertools.product(range(2 * step, width-2*step, step),                 \
                             range(2 * step, height-2*step,step)):
    
    minDiference, nextDiference = float("inf"),  float("inf")
    mDisp = [0,0]
    for dx,dy in itertools.product(range(-maxDisp, maxDisp),                      \
                                   range(-maxDisp, maxDisp)):
        if dx != 0 or dy != 0:
            differenceMatching = 0
            for wx,wy in itertools.product(range(0, kernelSize),                  \
                                           range(0, kernelSize)):
                y1, x1 = y + wy - kernelCentre, x + wx - kernelCentre 
                y2, x2 = y1 + dy, x1 + dx
pathToDir = "../../Images/Chapter7/Input/"
imageName = "f14rs.png"
numMoments = 4
background = [200, 255] # white background image

# Read image into array and show
inputImage, width, height = imageReadL(pathToDir+imageName)
showImageL(inputImage)

# Get a list that contains the pixels of the shape in the form (y,x,val) 
# We could have used the border pixels
imageRegion = pixlesList(inputImage, background)

# Compute geometric moments
numPoints = len(imageRegion)
M = createImageF(numMoments,numMoments)
for m,n in itertools.product(range(0, numMoments), range(0, numMoments)):
    for indexPixel in range(0, numPoints):
        y = (imageRegion[indexPixel])[0]
        x = (imageRegion[indexPixel])[1]
        v = (imageRegion[indexPixel])[2]
        M[n,m] += (x**n) * (y**m) * v

# Geometric central Moments
xc,yc = M[1,0]/M[0,0], M[0,1]/M[0,0]
centMom = createImageF(numMoments,numMoments)
for m,n in itertools.product(range(0, numMoments), range(0, numMoments)):
    for indexPixel in range(0, numPoints):
        y = (imageRegion[indexPixel])[0]
        x = (imageRegion[indexPixel])[1]
        v = (imageRegion[indexPixel])[2]
inputImage, width, height = imageReadL(pathToDir + imageName)

# Show input image
showImageL(inputImage)

# Apply Gaussian kernel
gaussianKernel = createGaussianKernel(GaussianKernelSize)
gaussianImage = applyKernelF(inputImage, gaussianKernel)

# Apply Sobel kernel. We use normalized magnitude in this example
sobelX, sobelY = createSobelKernel(sobelKernelSize)
magnitude, angle, _, _ = applyKernelMA(gaussianImage, sobelX, sobelY,
                                       normalizeMagnitude)

# To store maximum suppression image
maxImage = createImageF(width, height)

# Non-maximum suppression
border = GaussianKernelSize
for x,y in itertools.product(range(border, width-border),                   \
                             range(border, height-border)):

    # Only potential edges can be maximum
    if magnitude[y, x] > lowerT:
        # The normal angle is perpendicular to the edge angle
        normalAngle = angle[y, x] - pi / 2.0

        # Make sure the angle is between 0 and pi
        while normalAngle < 0:
            normalAngle += pi
        while normalAngle > pi:
Exemple #6
0
lowerT = 0.3
peakDetection = 0.7

# Read image into array and show
inputImage, width, height = imageReadL(pathToDir + imageName)
showImageL(inputImage)

# Compute edges
magnitude, angle = applyCannyEdgeDetector(inputImage, gaussianKernelSize,
                                          sobelKernelSize, upperT, lowerT)
showImageF(magnitude)

# Line parametrisation for normals from 0 to 360 degrees and r positive form the image centre
# Parametrisation r = (x-cx) * cos(t) + (y-cy) * sin(t)
maxLenght = int(sqrt(height * height + width * width) / 2)
accumulator = createImageF(maxLenght, 360)
cx = int(width / 2)
cy = int(height / 2)

# Gather evidence
for x, y in itertools.product(range(0, width), range(0, height)):
    if magnitude[y, x] != 0:
        for m in range(0, 360):
            angle = (m * pi) / 180.0
            r = (x - cx) * cos(angle) + (y - cy) * sin(angle)
            bucket = int(r)
            if bucket > 0 and bucket < maxLenght - 1:
                weight = r - int(r)
                accumulator[m, bucket] += (1.0 - weight)
                accumulator[m, bucket + 1] += weight
Exemple #7
0
scale = max(max(inputWidth, inputHeight) / float(reducedSize), 1.0)
width, height = int(inputWidth / scale), int(inputHeight / scale)
scaledImage = scaleImageL(inputImage, width, height)
showImageL(scaledImage)

# Get a list that contains the pixels of the shape in the form (y,x,v)
shapeImage = pixlesList(scaledImage, background)
numPoints = len(shapeImage)

# Polynomials, coefficients and weights for the Krawtchouk polynomials
# Considering that A*C = k. For a the coefficients and C the powers x, x^2, x^3,..
N = max(width, height)
kW, aW, sigma, ro, w = weightedKrawtchoukPolynomials(p, N)

# Krawtchouk moments of the shape  by standard definition
Q = createImageF(numMoments, numMoments)
for m, n in itertools.product(range(0, numMoments), range(0, numMoments)):
    for indexPixel in range(0, numPoints):
        y, x = (shapeImage[indexPixel])[0], (shapeImage[indexPixel])[1]
        v = (shapeImage[indexPixel])[2]
        Q[n, m] += w[x, m] * kW[x, m] * w[y, n] * kW[y, n] * v
printImageRangeF(Q, [0, numMoments - 1], [0, numMoments - 1], " 8.2f")

# Krawtchouk moments from the geometric moments Gij = x**i , y**j.
G = createImageF(N, N)
for i, j in itertools.product(range(0, N), range(0, N)):
    for indexPixel in range(0, numPoints):
        y, x = (shapeImage[indexPixel])[0], (shapeImage[indexPixel])[1]
        v = (shapeImage[indexPixel])[2]
        G[j, i] += sqrt(sigma[x] * sigma[y]) * y**j * x**i * v
Exemple #8
0
    kernelSize = Kernel size
    sigma = Standard deviation
'''
pathToDir = "../../Images/Chapter3/Input/"
imageName = "Giraffe.png"
kernelSize = 9
sigma = 3.0

# Read image into array
inputImage, width, height = imageReadL(pathToDir + imageName)

# Show input image
showImageL(inputImage)

# Create image to store kernel 
kernelImage = createImageF(kernelSize, kernelSize)

# Three float array to store colors to be used in the surface plot
colorsRGB = createImageF(kernelSize, kernelSize, 3)

# Set the pixels of Gaussian kernel
centre = (kernelSize - 1) / 2
sumValues = 0
for x,y in itertools.product(range(0, kernelSize), range(0, kernelSize)):
    kernelImage[y,x] = exp( -0.5 * (pow((x - centre)/sigma, 2.0) +    \
                                    pow((y - centre)/sigma, 2.0)) ) 
    sumValues += kernelImage[y,x] 
     
    # This is only set for the plot
    colorsRGB[y,x] = [kernelImage[y,x], kernelImage[y,x], kernelImage[y,x]]
Exemple #9
0
def findLongestSegment(edges):
    height, width = len(edges), len(edges[0])
    # Find line segments
    segmentsList = []
    segmentsImage = createImageF(width, height)
    maxSegmentLenght = 0
    maxSegmentIndex = 0
    for x, y in itertools.product(range(0, width), range(0, height)):
        if edges[y, x] != 0 and segmentsImage[y, x] == 0:
            segment = []
            segmentPoints = [(y, x)]
            segmentsImage[y, x] = 255
            while len(segmentPoints) > 0:
                yc = (segmentPoints[0])[0]
                xc = (segmentPoints[0])[1]
                segment.append((yc, xc))
                segmentPoints = segmentPoints[1:]

                for dx, dy in itertools.product(range(-1, 2), range(-1, 2)):
                    xn, yn = xc + dx, yc + dy
                    if dx != 0 or dy != 0 and xn > 0 and yn > 0 and xn < width and yn < height:
                        if edges[yn, xn] != 0 and segmentsImage[yn, xn] == 0:
                            segmentPoints.append((yn, xn))
                            segmentsImage[yn, xn] = 255

            segmentsList.append(segment)
            if len(segment) > maxSegmentLenght:
                maxSegmentLenght = len(segment)
                maxSegmentIndex = len(segmentsList) - 1

    mainSegment = []
    segment = segmentsList[maxSegmentIndex]
    curentElement = segment.pop(0)
    sy, sx = curentElement[0], curentElement[1]

    mainSegment.append(curentElement)

    numPoints = len(segment)
    while numPoints > 0:
        closestElement = [0, float("inf")]
        cy, cx = curentElement[0], curentElement[1]
        for p in range(0, numPoints):
            y, x = (segment[p])[0], (segment[p])[1]
            d = sqrt((cx - x) * (cx - x) + (cy - y) * (cy - y))
            if d < closestElement[1] or (d == closestElement[1] and y > cy):
                closestElement = [p, d]

        # If we are closer to the first point, then end now
        dFirst = sqrt((cx - sx) * (cx - sx) + (cy - sy) * (cy - sy))
        if (cx != sx or cy != sy) and 2 * dFirst < closestElement[1]:
            break

        curentElement = segment.pop(closestElement[0])
        numPoints = len(segment)

        mainSegment.append(curentElement)
    numPoints = len(mainSegment)

    # Average to get more accurate direction
    averageSize = 1
    totalPixels = float(1 + 2 * averageSize)
    mainSegmentAverage = []
    for p in range(0, numPoints):
        y, x = 0, 0
        for w in range(-averageSize, averageSize + 1):
            p1 = p + w
            if p1 < 0: p1 = p1 + numPoints
            if p1 >= numPoints: p1 = p1 - numPoints
            x += (mainSegment[p1])[1]
            y += (mainSegment[p1])[0]
        mainSegmentAverage.append((y / totalPixels, x / totalPixels))

    return mainSegmentAverage
        m = atan(-float(y1 - refPoint[0]) / (x1 - refPoint[1]))
    else:
        m = 1.57
    k = angleTemplate[y1, x1] - m
    # Scale
    distCentre = sqrt((y1 - refPoint[0]) * (y1 - refPoint[0]) +
                      (x1 - refPoint[1]) * (x1 - refPoint[1]))
    distPoints = sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1))
    c = distCentre / distPoints
    # Insert in the table. The angle is in the interval -pi/2 to pi/2
    entryIndex = int((beta + (pi / 2.0)) / deltaAngle)
    entry = rTable[entryIndex]
    entry.append((k, c))

# Gather evidence for the location
accumulator = createImageF(width, height)
for x1, y1 in itertools.product(range(0, width), range(0, height)):
    if magnitude[y1, x1] != 0:
        # Looking for potential the second points along a line
        secondPoints = []
        m = tan(angle[y1, x1] - alpha)
        if m > -1 and m < 1:
            for delta in range(minimaDistPoints, maxDistPoints):
                x2 = min(x1 + delta, width - 1)
                y2 = int(y1 - m * (x2 - x1))
                if y2 > 0 and y2 < height and magnitude[y2, x2] != 0:
                    secondPoints.append((y2, x2))
                    break
            for delta in range(minimaDistPoints, maxDistPoints):
                x2 = max(0, x1 - delta)
                y2 = int(y1 - m * (x2 - x1))
Exemple #11
0
def watherShed(distanceImage, shapeImage, suppWindow):
    height, width = len(distanceImage), len(distanceImage[0])
    watershedImage = createImageF(width, height)

    # Initial regions by finding the maximum
    regionIndex = 1  # Start id for a region. Any number different from zero
    numPoints = len(shapeImage)
    for indexPixel in range(0, numPoints):
        y, x = (shapeImage[indexPixel])[0], (shapeImage[indexPixel])[1]
        if watershedImage[y, x] == 0:
            peak = True
            for wx,wy in itertools.product(range(x-suppWindow, x+suppWindow+1), \
                                           range(y-suppWindow, y+suppWindow+1)):
                if wy >= 0 and wy < height and wx >= 0 and wx < width:
                    if watershedImage[wy, wx] != 0 or                           \
                       distanceImage[y, x] < distanceImage[wy, wx]:
                        peak = False
            if peak:
                for wx,wy in itertools.product(range(x-suppWindow, x+suppWindow+1), \
                                               range(y-suppWindow, y+suppWindow+1)):
                    if wy >= 0 and wy < height and wx >= 0 and wx < width:
                        watershedImage[wy, wx] = regionIndex
                regionIndex += 1

    floodRegion = []  # The region we need to flood
    for indexPixel in range(0, numPoints):
        y, x = (shapeImage[indexPixel])[0], (shapeImage[indexPixel])[1]
        if watershedImage[y, x] == 0:
            floodRegion.append((y, x))

    # This is not required. We do it to get a better display
    # Create random regions ID. We change the ID for a random value so we get a random gray level when showing the regions
    c = sample(range(regionIndex), regionIndex)
    for indexPixel in range(0, numPoints):
        y, x = (shapeImage[indexPixel])[0], (shapeImage[indexPixel])[1]
        if watershedImage[y, x] != 0:
            watershedImage[y, x] = c[int(watershedImage[y, x])] + 1

    # Flooding
    maxDistance, _ = imageMaxMin(distanceImage)
    for floodValue in range(int(maxDistance), 0, -1):
        flooded = True
        while flooded:
            flooded = False
            newFloodRegion = []
            growRegion = []
            shuffle(floodRegion)
            for indexPixel in range(0, len(floodRegion)):
                y, x = (floodRegion[indexPixel])[0], (
                    floodRegion[indexPixel])[1]

                # Points not flooded will be considered in following iterations
                if distanceImage[y, x] <= floodValue:
                    newFloodRegion.append((y, x))
                else:
                    #  list of neighbours
                    n = []
                    for wx, wy in itertools.product(range(-1, 2), range(-1,
                                                                        2)):
                        posX, posY = x + wx, y + wy
                        if posY > -1 and posY < height and posX > -1 and posX < width:
                            if watershedImage[posY, posX] != 0:
                                n.append(watershedImage[posY, posX])

                    # No neighbours, so we cannot grow
                    if (len(n) == 0):
                        newFloodRegion.append((y, x))
                    else:
                        # Grow of only one type of region
                        if len(set(n)) == 1:
                            growRegion.append((y, x, n[0]))
                            flooded = True

            for pixel in growRegion:
                watershedImage[pixel[0], pixel[1]] = pixel[2]

            floodRegion = newFloodRegion

    # Set the borders
    shedID = regionIndex + 1
    for indexPixel in range(0, numPoints):
        y, x = (shapeImage[indexPixel])[0], (shapeImage[indexPixel])[1]
        if watershedImage[y, x] == 0 and distanceImage[y, x] > 0.5:
            watershedImage[y, x] = shedID

    return watershedImage
Exemple #12
0
pathToDir = "../../Images/Chapter2/Input/"
imageName = "Square.png"

# Read image into array
inputImage, width, height = imageReadL(pathToDir + imageName)

# Show input image
showImageL(inputImage)

# Create coefficients Image. Two floats to represent a complex number
# Maximum frequency according to sampling
maxFreqW = int(width / 2)
maxFreqH = int(height / 2)
numCoeffW = 1 + 2 * maxFreqW
numCoeffH = 1 + 2 * maxFreqH
coeff = createImageF(numCoeffW, numCoeffH, 2)

# Adjust the size of the data to be even
m = float(width)
n = float(height)
if width % 2 == 0:
    m = width + 1.0
if height % 2 == 0:
    n = height + 1.0

# Fundamental frequency
ww = (2.0 * pi) / m
wh = (2.0 * pi) / n

# Fourier Transform
for u in range(-maxFreqW, maxFreqW + 1):
from ImagePropertiesUtilities import imageMaxMin
from PlotUtilities import plotSurface

# Math and iteration
from math import exp
from timeit import itertools
'''
Parameters:
    kernelSize = Size of the kernel
    sigma = Standard deviation of the kernel
'''
kernelSize = 15
sigma = 1.5

# To store kernel
kernelLaplacian = createImageF(kernelSize, kernelSize)

# Create kernel
s2Inv = 1.0 / (sigma * sigma)
kernelCentre = (kernelSize - 1) / 2

# Generate kernel values
sumValues = 0.0
for x, y in itertools.product(range(0, kernelSize), range(0, kernelSize)):
    nx2 = float(x - kernelCentre) * float(x - kernelCentre)
    ny2 = float(y - kernelCentre) * float(y - kernelCentre)
    s = 0.5 * (nx2 + ny2) * s2Inv

    kernelLaplacian[y, x] = -s2Inv * s2Inv * (1.0 - s) * exp(-s)
    sumValues += kernelLaplacian[y, x]
'''
pathToDir = "../../Images/Chapter2/Input/"
imageName = "Square.png"

# Read image into array
inputImage, width, height = imageReadL(pathToDir + imageName)

# Show input image
showImageL(inputImage)

# Create coefficients Image. Two floats to represent a complex number
maxFrequencyW = int(width / 2)
maxFrequencyH = int(height / 2)
numCoefficientsW = 1 + 2 * maxFrequencyW
numCoefficientsH = 1 + 2 * maxFrequencyH
coefficients = createImageF(numCoefficientsW, numCoefficientsH, 2)

# Adjust the size of the data to be even
m = float(width)
n = float(height)
if width % 2 == 0:
    m = width + 1.0
if height % 2 == 0:
    n = height + 1.0

# Fundamental frequency
ww = (2.0 * pi) / m
wh = (2.0 * pi) / n

# Compute coefficients
for kw in range(-maxFrequencyW, maxFrequencyW + 1):
from timeit import itertools
'''
Parameters:
    pathToDir = Input image directory
    imageName = Input image name
'''
pathToDir = "../../Images/Chapter4/Input/"
imageName = "Squares.png"

# Read image into array
inputImage, width, height = imageReadL(pathToDir + imageName)

# Show input image
showImageL(inputImage)

outputMagnitude = createImageF(width, height)
outputDirection = createImageF(width, height)

for x, y in itertools.product(range(0, width - 1), range(0, height - 1)):
    mX, mY = 0.0, 0.0
    for c in range(-1, 2):
        mX += float(inputImage[y - 1, x + c]) - float(inputImage[y + 1, x + c])
        mY += float(inputImage[y + c, x - 1]) - float(inputImage[y + c, x + 1])
    outputMagnitude[y, x] = sqrt(mX * mX + mY * mY)
    outputDirection[y, x] = atan2(mY, mX)

# Show output image
showImageF(outputMagnitude)
showImageF(outputDirection)

# Print pixel's values in an image range
pathToDir = "../../Images/Chapter5/Input/"
imageName = "Eye.png"
templateName = "EyeTemplate.png"
addQuadraticTerm = True

# Read image into array
inputImage, width, height = imageReadL(pathToDir + imageName)
templateImage, widthTemplate, heightTemplate = imageReadL(pathToDir +
                                                          templateName)

# We pad the input and template to this size
widthPad = width + widthTemplate - 1
heightPad = height + heightTemplate - 1

# Pad input
inputPad = createImageF(widthPad, heightPad)
for x, y in itertools.product(range(0, width), range(0, height)):
    inputPad[y, x] = inputImage[y, x]

# Pad and invert template
templatePad = createImageF(widthPad, heightPad)
templatePadFlip = createImageF(widthPad, heightPad)
for x, y in itertools.product(range(0, widthTemplate),
                              range(0, heightTemplate)):
    templatePad[y, x] = templateImage[y, x]
    templatePadFlip[y, x] = templateImage[heightTemplate - y - 1,
                                          widthTemplate - x - 1]

# Show input image and template
showImageF(inputPad)
showImageF(templatePad)
Exemple #17
0
'''
Parameters:
    pathToDir = Input image directory
    imageName = Input image name
'''
pathToDir = "../../Images/Chapter4/Input/"
imageName = "Squares.png"

# Read image into array
inputImage, width, height = imageReadL(pathToDir + imageName)

# Show input image
showImageL(inputImage)

# Create images to store the results
horizEdges = createImageF(width, height)
vertEdges = createImageF(width, height)
outputEdges = createImageF(width, height)

for x, y in itertools.product(range(0, width - 1), range(0, height - 1)):

    horizEdges[y,
               x] = abs(float(inputImage[y, x]) - float(inputImage[y + 1, x]))
    vertEdges[y,
              x] = abs(float(inputImage[y, x]) - float(inputImage[y, x + 1]))

    outputEdges[y,x] = abs(2.0* float(inputImage[y,x]) -                        \
                       float(inputImage[y+1,x]) - float(inputImage[y,x+1]))

# Show horizontal, vertical and all edges
showImageF(horizEdges)
# Obtain the angular functions and plot 
sumArcLenghts, normArcLenghts, angularFunc, cumulativeFunc, cumulativeNormFunc =         \
                                                          computeAngularFunctions(shape)
plotCurveXY(sumArcLenghts,angularFunc, [-3.2, 3.2])
plotCurveXY(normArcLenghts,cumulativeNormFunc, [-3.2, 3.2])

# Number of coefficients
numEdges = len(sumArcLenghts)
shapeLenght = sumArcLenghts[numEdges - 1]

# If number descriptors is 0 use the maximum according to the lenght
if numDescriptors == 0:
    numDescriptors = 1 + int(numEdges /2)

# Compute coefficients 
coefficients = createImageF(numDescriptors, 2)
lenghtNorm = 2.0 * pi / shapeLenght
for k in range(1, numDescriptors):
    arcLenght = 0
    for p in range(0, numEdges):
        coefficients[0, k] += cumulativeFunc[p] * (sumArcLenghts[p] - arcLenght)          \
                                                * cos(k * sumArcLenghts[p] * lenghtNorm)
        coefficients[1, k] += cumulativeFunc[p] * (sumArcLenghts[p] - arcLenght)          \
                                                * sin(k * sumArcLenghts[p] * lenghtNorm)
        arcLenght = sumArcLenghts[p]
  
    coefficients[0, k] = coefficients[0, k] *(2.0/shapeLenght)
    coefficients[1, k] = coefficients[1, k] *(2.0/shapeLenght) - (2.0/k)

# Rotation invariant descriptors
descriptors = createVectorF(numDescriptors)
imageName = "Logs.png"
suppWindow = 5

# Read image into array and show
inputImage, width, height = imageReadL(pathToDir + imageName)
showImageL(inputImage)

# Apply Sobel kernel. We use normalized magnitude in this example
sobelX, sobelY = createSobelKernel(3)
normalizeMagnitude = False
magnitude, _, _, _ = applyKernelMA(inputImage, sobelX, sobelY,
                                   normalizeMagnitude)
showImageF(magnitude)

# Apply Gaussian kernel
gaussianKernel = createGaussianKernel(10)
gaussianImage = applyKernelF(magnitude, gaussianKernel)

# Invert the image and add all pixels to the shape
shapeImage = []
distanceImage = createImageF(width, height)
maxGradient, minGradient = imageMaxMin(gaussianImage)
for x, y in itertools.product(range(0, width), range(0, height)):
    distanceImage[y, x] = maxGradient - gaussianImage[y, x]
    shapeImage.append((y, x))
showImageF(distanceImage)

# Watershed of the distance image
watershed = watherShed(distanceImage, shapeImage, suppWindow)
showImageF(watershed)