예제 #1
0
lowerT = 0.05
numEntries = 90

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

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

# Compute reference point in the template
refPoint = [0, 0]
edgePoints = []
for x, y in itertools.product(range(0, widthTemplate),
                              range(0, heightTemplate)):
    if magnitudeTemplate[y, x] != 0:
        refPoint[0] += y
        refPoint[1] += x
        edgePoints.append((y, x))
numPts = len(edgePoints)
refPoint = [int(refPoint[0] / numPts), int(refPoint[1] / numPts)]

# Build Rtable as a list of lists
pathToDir = "../../Images/Chapter8/Input/"
imageName = "Logs.png"
cannyKernelSize = 7
upperT = 0.5
lowerT = 0.1
windowDelta = 3
suppWindow = 5

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

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

# Divide pixels into edge and region pixels
edgePixels = []
shapeImage = []
for x, y in itertools.product(range(0, width), range(0, height)):
    if magnitude[y, x] > 0:
        edgePixels.append((y, x))
    shapeImage.append((y, x))

# Radial is the minimal distance to the edge
distanceImage = createImageF(width, height)
numEdges = len(edgePixels)
for x in range(0, width):
    printProgress(x, width)
    for y in range(0, height):
예제 #3
0
        coeff[entryH, entryW][1] *= m * n

# Reconstruction
reconstruction = createImageF(width, height)
for u in range(-maxFreqW, maxFreqW + 1):
    printProgress(u + maxFreqW, numCoeffW)
    entryW = u + maxFreqW
    for v in range(-maxFreqH, maxFreqH + 1):
        entryH = v + maxFreqH
        for x in range(0, width):
            for y in range(0, height):

                reconstruction[y,x] += (coeff[entryH, entryW][0] / (m*n)) * (cos(x * ww * u) * cos(y * wh * v) - sin(x * ww * u) * sin(y * wh * v)) - \
                                       (coeff[entryH, entryW][1] / (m*n)) * (cos(x * ww * u) * sin(y * wh * v) + sin(x * ww * u) * cos(y * wh * v))

showImageF(reconstruction)

# Power
power = createImageF(1 + 2 * maxFreqW, 1 + 2 * maxFreqH)
for kw, kh in itertools.product(range(-maxFreqW, maxFreqW + 1),
                                range(-maxFreqH, maxFreqH + 1)):
    entryW = kw + maxFreqW
    entryH = kh + maxFreqH
    power[entryH, entryW] = sqrt(coeff[entryH, entryW][0] * coeff[entryH, entryW][0] +              \
                                 coeff[entryH, entryW][1] * coeff[entryH, entryW][1])

    power[entryH, entryW] = log(1.0 + power[entryH, entryW])

# Show the log of the power
powerLog = imageLogF(power)
showImageF(powerLog)
mYx = applyKernelF(mY, sobelX)
mYy = applyKernelF(mY, sobelY)

# Compute curvature
curvature = createImageF(width, height)
for x, y in itertools.product(range(0, width), range(0, height)):
    # If it is an edge
    if magnitude[y, x] > 0:
        Mx2, My2, MxMy = mX[y, x] * mX[y, x], mY[y, x] * mY[y, x], mX[
            y, x] * mY[y, x]

        if Mx2 + My2 != 0.0:
            p = 1.0 / pow((Mx2 + My2), 1.5)

            if op == "T":
                curvature[y,x] = p * (My2 * mXx[y,x] - MxMy * mYx[y,x] +  \
                                      Mx2 * mYy[y,x] - MxMy * mXy[y,x])
            if op == "TI":
                curvature[y,x] = p * (-My2 * mXx[y,x] + MxMy * mYx[y,x] - \
                                      Mx2 * mYy[y,x] + MxMy * mXy[y,x])
            if op == "N":
                curvature[y,x] = p * (Mx2  * mYx[y,x] - MxMy * mYx[y,x] - \
                                      MxMy * mYy[y,x] + My2  * mXy[y,x])
            if op == "NI":
                curvature[y,x] = p * (-Mx2 *  mYx[y,x] + MxMy * mXx[y,x] + \
                                      MxMy * mYy[y,x] - My2 *  mXy[y,x])

            curvature[y, x] = fabs(curvature[y, x])

showImageF(curvature, 2)
# Create an accumulator. We look in a reduced size image
accumulator = createImageF(width, height)
  
# Template matching
templateCentreX = int((widthTemplate - 1) / 2)
templateCentreY = int((heightTemplate - 1) / 2)
for x in range(0, width):  
    printProgress(x, width)
    for y in range(0, height):
        for wx,wy in itertools.product(range(0, widthTemplate), range(0, heightTemplate)):
            posY = y + wy - templateCentreY
            posX = x + wx - templateCentreX 
            
            # The threshold is used to accumulate only the edge pixels in an edge template
            # The difference of pixel values is inverted to show the best match as a peak
            if posY > -1 and posY <  height and  posX > -1 and posX <  width and            \
               templateImage[wy,wx] > thresholdVal:
                diff = 1.0 - abs(float(inputImage[posY,posX]) -                             \
                                 float(templateImage[wy, wx])) / 255.0
                
                accumulator[y,x] += diff*diff 
                        
# Show accumulator within a maxima and mininma region
maxima, minima = imageMaxMin(accumulator)
showImageF(accumulator)
plot3DHistogram(accumulator, [minima, maxima])




예제 #6
0
axisRange = [20, 65]
angleRange = [0, 4]
segmentLenghtThreshod = 0.20
pairsPerPoint = 30

# Sample points distance. Higher the eccentricity higher the distance so points give accurate positions
axisRatio = float(axisRange[1]) / (2.0 * float(axisRange[0]))
deltaPointRange = [int(axisRatio * axisRange[0]), int(1.2 * axisRange[1])]

# Read image #49 20 0.03490658503988659 125 77 2
inputImage, width, height = imageReadL(pathToDir + imageName)

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

# Find segments
segmentsList = []
segmentsImage = createImageF(width, height)
maxSegmentLenght = 0
for x, y in itertools.product(range(0, width), range(0, height)):
    if magnitude[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:]
예제 #7
0
# 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]

# Power
powerLow = computePowerfromCoefficients(coeffLow)
powerHigh = computePowerfromCoefficients(coeffHigh)

# Show power
powerLowLog = imageLogF(powerLow)
powerHighLog = imageLogF(powerHigh)
showImageF(powerLowLog)
showImageF(powerHighLog)

# Reconstruct image
imageLow = reconstruction(coeffLow)
imageHigh = reconstruction(coeffHigh)

showImageF(imageLow)
showImageF(imageHigh)
예제 #8
0
# Get a list of edge pixels
edgePixels = edgesList(inputImage, shapeImage, background)

# Compute the radial distance to the edge
distanceImage = createImageF(width, height)
numEdges = len(edgePixels)
for indexPixel in range(0, numPoints):
    y, x = (shapeImage[indexPixel])[0], (shapeImage[indexPixel])[1]
    minEdgeDist = FLT_MAX
    for indexEdge in range(0, numEdges):
        edgeY, edgeX = (edgePixels[indexEdge])[0], (edgePixels[indexEdge])[1]
        minEdgeDist = min(minEdgeDist, sqrt((edgeX - x)**2 + (edgeY - y)**2))
    distanceImage[y, x] = minEdgeDist

# Show distance
showImageF(distanceImage)

# Watershed image
watershed = createImageF(width, height)

# Initial regions by finding the maximum
suppWindow = 5  # Window used to find a maximum
regionIndex = 1  # Start id for a region
for indexPixel in range(0, numPoints):
    y, x = (shapeImage[indexPixel])[0], (shapeImage[indexPixel])[1]
    if watershed[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 watershed[wy, wx] != 0 or                                   \
예제 #9
0
    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)
showImageF(vertEdges)
showImageF(outputEdges)
    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):
    printProgress(u + maxFreqW, numCoeffW)
    entryW = u + maxFreqW
    for v in range(-maxFreqH, maxFreqH + 1):
        entryH = v + maxFreqH
        for x, y in itertools.product(range(0, width), range(0, height)):
            coeff[entryH, entryW] += inputImage[y,x] *                                      \
                 (cos(x * ww * u) + sin(x * ww * u)) * (cos(y * wh * v) + sin(y * wh * v))

# Include scale
for u in range(-maxFreqW, maxFreqW + 1):
    printProgress(u + maxFreqW, numCoeffW)
    entryW = u + maxFreqW
    for v in range(-maxFreqH, maxFreqH + 1):
        entryH = v + maxFreqH
        coeff[entryH, entryW] /= m * n

# Show transform in log form. The function converts negative values to positive,
# so it is similar to the power
coeffLog = imageLogF(coeff)
showImageF(coeffLog)
# Create Kernel
kernelLaplacian = createLaplacianKernel(kernelSize, sigma)

# Apply kernel
gaussianImage = applyKernelF(inputImage, kernelLaplacian)

# Zero-crossing detector
edges = createImageL(width, height)
kernelCentre = int((kernelSize - 1) / 2)
for x, y in itertools.product(range(1, width - 1), range(1, height - 1)):
    quadrantValue = [0.0, 0.0, 0.0, 0.0]
    for wx, wy in itertools.product(range(-1, 1), range(-1, 1)):
        quadrantValue[0] += gaussianImage[y + wy, x + wx]

    for wx, wy in itertools.product(range(-1, 1), range(0, 2)):
        quadrantValue[1] += gaussianImage[y + wy, x + wx]

    for wx, wy in itertools.product(range(0, 2), range(-1, 1)):
        quadrantValue[2] += gaussianImage[y + wy, x + wx]

    for wx, wy in itertools.product(range(0, 2), range(0, 2)):
        quadrantValue[3] += gaussianImage[y + wy, x + wx]

    maxVal, minVal = max(quadrantValue), min(quadrantValue)

    if maxVal > 0.0 and minVal < 0:
        edges[y, x] = 255

showImageF(gaussianImage)
showImageL(edges)
'''
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
printImageRangeF(outputDirection, [0, width - 1], [0, height - 1])

# Plot vectors
plotQuiver(outputMagnitude, outputDirection, 1300)
예제 #13
0
    for wx, wy in itertools.product(range(0, kernelSize), range(0,
                                                                kernelSize)):
        posY = y + wy - kernelCentre
        posX = x + wx - kernelCentre

        if posY > -1 and posY < height and posX > -1 and posX < width:
            mX += float(inputImage[posY, posX]) * sobelX[wy, wx]
            wX += sobelX[wy, wx]

            mY += float(inputImage[posY, posX]) * sobelY[wy, wx]
            wY += sobelY[wy, wx]

    if wX > 0:
        mX = mX / wX

    if wY > 0:
        mY = mY / wY

    outputMagnitude[y, x] = sqrt(mX * mX + mY * mY)
    outputDirection[y, x] = atan2(mY, mX)

# Threshold image
outputthresholdMagnitude = thresholdImage(outputMagnitude, threshold, True)

# Show output image
showImageF(outputMagnitude)
showImageL(outputthresholdMagnitude)

# Plot scaled vectors
plotQuiver(outputMagnitude, outputDirection, quiverScale, quiverSample)
for x,y in itertools.product(range(0, kernelSize), range(0, kernelSize)):
    kernelImage[y, x] = 255.0  
    
# Padding size
widthPad, heightPad = width+kernelSize-1, height+kernelSize-1   

# Padding input
inputPad = createImageF(widthPad, heightPad)
for x,y in itertools.product(range(0, width), range(0, height)):
    inputPad[y,x] = inputImage[y,x] 
 
# Padding and flip template
templatePadFlip = createImageF(widthPad, heightPad)
for x,y in itertools.product(range(0, kernelSize), range(0, kernelSize)):
    templatePadFlip[y, x] = kernelImage[kernelSize-y-1, kernelSize-x-1]
showImageF(templatePadFlip)

# Compute coefficients 
imageCoeff, maxFrequencyW, maxFrequencyH = computeCoefficients(inputPad)
templateCoeff, _, _ = computeCoefficients(templatePadFlip)

# Show the log of the power of the input image and template
powerImage = computePowerfromCoefficients(imageCoeff)
powerImageLog = imageLogF(powerImage)
showImageF(powerImageLog)

powerTemplate = computePowerfromCoefficients(templateCoeff)
powerTemplateLog = imageLogF(powerTemplate)
showImageF(powerTemplateLog)

# Frequency domain multiplication
        coefficients[indexInArrayH, indexInArrayW][1] *= m * n

# Power
power = createImageF(1 + 2 * maxFrequencyW, 1 + 2 * maxFrequencyH)
for kw,kh in itertools.product(range(-maxFrequencyW, maxFrequencyW + 1),                  \
                               range(-maxFrequencyH, maxFrequencyH + 1)):
    indexInArrayW = kw + maxFrequencyW
    indexInArrayH = kh + maxFrequencyH
    power[indexInArrayH, indexInArrayW] =                                                 \
            sqrt(coefficients[indexInArrayH, indexInArrayW][0] *                          \
                 coefficients[indexInArrayH, indexInArrayW][0] +                          \
                 coefficients[indexInArrayH, indexInArrayW][1] *                          \
                 coefficients[indexInArrayH, indexInArrayW][1])

# Show the log of the power
powerLog = imageLogF(power)
showImageF(powerLog)

# Phase
phase = createImageF(1 + 2 * maxFrequencyW, 1 + 2 * maxFrequencyH)
for kw,kh in itertools.product(range(-maxFrequencyW, maxFrequencyW + 1),                  \
                               range(-maxFrequencyH, maxFrequencyH + 1)):
    indexInArrayW = kw + maxFrequencyW
    indexInArrayH = kh + maxFrequencyH
    phase[indexInArrayH, indexInArrayW] =                                                 \
                    atan2(coefficients[indexInArrayH, indexInArrayW][1],                  \
                          coefficients[indexInArrayH, indexInArrayW][0])

# Show phase
showImageF(phase)
예제 #16
0
# Read image into array
inputImage, width, height  = imageReadL(pathToDir + imageName)

# Shift the image
shiftDistance =  int(width / 3);
shiftImage = createImageL(width, height)

for x,y in itertools.product(range(0, width), range(0, height)):
    xShift = (x - shiftDistance) % width 
    shiftImage[y][x] = inputImage[y][xShift]

# Show images
showImageL(inputImage)
showImageL(shiftImage)

# Compute power and phase 
powerImage, phaseImage  = computePowerandPhase(inputImage)
powerShiftImage, phaseShiftImage = computePowerandPhase(shiftImage)
 
# Show power
powerImageLog = imageLogF(powerImage)
powerShiftImageLog = imageLogF(powerShiftImage)
showImageF(powerImageLog)
showImageF(powerShiftImageLog)

# show phase
showImageF(phaseImage)
showImageF(phaseShiftImage)

# 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)

# Compute correlation in image domain sum of square differences
squaredTerm = createImageF(widthPad, heightPad)
corrImage = createImageF(widthPad, heightPad)
for x, y in itertools.product(range(0, widthPad), range(0, heightPad)):
    for w,h in itertools.product(range(-widthTemplate+1,1),                         \
                                 range(-heightTemplate+1,1)):
        p, q = x + w, y + h
        if p >= 0 and q >= 0 and p < width and q < height:
            squaredTerm[y, x] += inputPad[q, p] * inputPad[q, p]
            corrImage[y, x] += 2.0 * templatePad[h + heightTemplate - 1,
                                                 w + widthTemplate -
                                                 1] * inputPad[q, p]
예제 #18
0
for iteration in range(0, numIterations):
    for x, y in itertools.product(range(0, width), range(0, height)):
        image[y, x] = outputImage[y, x]

    for x, y in itertools.product(range(0, width), range(0, height)):
        sumWeights = 0
        outputImage[y, x] = 0

        centrePixleValue = image[y, x]
        for wx, wy in itertools.product(range(0, kernelSize),
                                        range(0, kernelSize)):
            posY, posX = y + wy - kernelCentre, x + wx - kernelCentre

            if posY > -1 and posY < height and posX > -1 and posX < width:
                # Weight according to gradient
                weight = exp(-pow((image[posY, posX] - centrePixleValue) /
                                  k, 2))

                # Use lambda to weight the pixel value
                if posY != y and posX != x:
                    weight *= lamda

                sumWeights += weight
                outputImage[y, x] += weight * float(image[posY, posX])
        # Normalize
        if sumWeights > 0:
            outputImage[y, x] /= sumWeights

# Show output image
showImageF(outputImage)
imageName = "Shapes.png"
GaussianKernelSize = 7
sobelKernelSize = 3
upperT = 0.4
lowerT = 0.2
windowDelta = 2

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

# Show input image
showImageL(inputImage)

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

# Compute curvature by subtracting the direction of neighbors
curvature = createImageF(width, height)
for x,y in itertools.product(range(0, width), range(0, height)):
    # Edge
    if magnitude[y,x] > 0:  
        # Consider neighbor edges
        edgesNeigbor = [ ]
        for wx,wy in itertools.product(range(-windowDelta, windowDelta+1),       \
                                       range(-windowDelta, windowDelta+1)):
            if magnitude[y+wy, x+wx] > 0 : 
                edgesNeigbor.append((y+wy,x+wx))
               
        # Use dot product to measure angle difference
        np = len(edgesNeigbor)     
예제 #20
0
#plot3DHistogram(q)

# Projection by setting the pixel's value to the high in the histogram for
#  the source and target images
colourScale = 256.0 / histoSize
projectionSource = createImageF(width, height)
projectionTarget = createImageF(width, height)
for x, y in itertools.product(range(0, width), range(0, height)):

    Cb, Cr = colourFeature(sourceImage[y, x], colourScale)
    projectionSource[y, x] = q[Cr, Cb]

    Cb, Cr = colourFeature(targetImage[y, x], colourScale)
    projectionTarget[y, x] = q[Cr, Cb]

showImageF(projectionSource)
showImageF(projectionTarget)

# Compute geometric moments of the source and target image regions
momS = createImageF(3, 3)
momT = createImageF(3, 3)
ps, pt = positions[0], positions[1]
sizeSearch = [int(sizeReg[0] * 1.5), int(sizeReg[1] * 1.5)]
for deltaX, deltaY in itertools.product(range(-sizeSearch[0], sizeSearch[0]),   \
                                        range(-sizeSearch[1], sizeSearch[1])):
    xs, ys = ps[0] + deltaX, ps[1] + deltaY
    xt, yt = pt[0] + deltaX, pt[1] + deltaY
    for m, n in itertools.product(range(0, 3), range(0, 3)):
        momS[n, m] += (xs**n) * (ys**m) * projectionSource[y, x]
        momT[n, m] += (xt**n) * (yt**m) * projectionTarget[y, x]
예제 #21
0
                for wx, wy in itertools.product(range(px - 1, px + 2),
                                                range(py - 1, py + 2)):
                    if wy >= 0 and wy < height and wx >= 0 and wx < width:
                        if inputImage[wy, wx] <= threshold and regionsImage[
                                wy, wx] == 0:
                            growRegion.append((wy, wx))

            nextRegionID += 1

    # Update times for regions
    for idRegion in incSizeRegions:
        # Update the size
        incSize = incSizeRegions[idRegion]
        sizeRegions[idRegion] += incSize

        # Update  stable
        if incSize < incThreshold:
            timeRegions[idRegion] += 1
        else:
            timeRegions[idRegion] = 0

        # Stable region condition
        if timeRegions[idRegion] > timeThreshold and sizeRegions[
                idRegion] > minRegionSize:
            for x, y in itertools.product(range(0, width), range(0, height)):
                if regionsImage[y, x] == idRegion:
                    resultImage[y, x] = 255
            timeRegions[idRegion] = 0

showImageF(resultImage)
                                GaussianKernelSize, sobelKernelSize, upperT, lowerT, True)        \

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

# Compute curvature
curvature = createImageF(width, height)
for x,y in itertools.product(range(0, width), range(0, height)):
    # If it is an edge
    if magnitude[y,x] > 0:
        A, B, C = 0.0, 0.0, 0.0
        for wx,wy in itertools.product(range(0, kernelSize), range(0, kernelSize)):
            posY = y + wy - kernelCentre
            posX = x + wx - kernelCentre 
                
            if posY > -1 and posY <  height and posX > -1 and posX <  width:
                A += mX[posY,posX] * mX[posY,posX]
                B += mY[posY,posX] * mY[posY,posX]
                C += mX[posY,posX] * mY[posY,posX]
                    
        if op == "H":
                curvature[y,x] = (A * B) - (C * C) - (k * ((A+B) * (A+B)))
        if op == "M":
                d = mX[y,x] * mX[y,x] + mY[y,x] * mY[y,x]
                if d != 0.0:
                    curvature[y,x] = (A * mY[y,x] * mY[y,x] -                   \
                                      2.0 * C * mX[y,x] * mY[y,x] +             \
                                      B * mX[y,x] * mX[y,x]) / d

showImageF(curvature)
        # Maximum difference is pi / 4.0, so we multiply by 2
        w = cos(2.0 * (normalAngle - baseAngle))

        # Point to interpolate
        M1 = w * magnitude[y + y1, x + x1] + (1.0 - w) * magnitude[y + y2,
                                                                   x + x2]

        # Point to interpolate for pixels in the other side of the edge
        M2 = w * magnitude[y - y1, x - x1] + (1.0 - w) * magnitude[y - y2,
                                                                   x - x2]

        # Determine if it is a maximum. If so make sure it will be preserved
        if magnitude[y, x] > M1 and magnitude[y, x] > M2:
            maxImage[y, x] = magnitude[y, x]

showImageF(maxImage)

# To compute hysteresis thresholded images we require two thresholds
edges = createImageF(width, height)
potentialEdges = []

# Divide pixels as edges, no edges and unassigned
for x, y in itertools.product(range(1, width - 1), range(1, height - 1)):
    # These are edges
    if maxImage[y, x] > upperT: edges[y, x] = 255
    # These are pixels that we do not want as edges
    if maxImage[y, x] < lowerT: edges[y, x] = 0
    # These may be edges
    if maxImage[y, x] > lowerT and maxImage[y, x] <= upperT:
        edges[y, x] = 128