def applyKernelMA(inputImage, kernelX, kernelY, normalizeMagnitude=False): height = len(inputImage) width = len(inputImage[0]) kernelHeight = len(kernelX) kerelWidth = len(kernelX[0]) kernelCentreY = int((kernelHeight - 1) / 2) kernelCentreX = int((kerelWidth - 1) / 2) # Create images to store the result magnitude = createImageF(width, height) direction = createImageF(width, height) imageX = createImageF(width, height) imageY = createImageF(width, height) # Convolution with two kernels for x,y in itertools.product(range(kernelCentreX, width - kernelCentreX), \ range(kernelCentreY, height - kernelCentreY)): sumKernel = [0.0, 0.0] sumKernelWeights = [0.0, 0.0] for wx, wy in itertools.product(range(0, kerelWidth), range(0, kernelHeight)): posY = y + wy - kernelCentreY posX = x + wx - kernelCentreX if posY > -1 and posY < height and posX > -1 and posX < width: sumKernel[0] += float(inputImage[posY, posX]) * float( kernelX[wy, wx]) sumKernelWeights[0] += float(kernelX[wy, wx]) sumKernel[1] += float(inputImage[posY, posX]) * float( kernelY[wy, wx]) sumKernelWeights[1] += float(kernelY[wy, wx]) # If we have to normalize if sumKernelWeights[0] != 0.0: imageX[y, x] = sumKernel[0] / sumKernelWeights[0] else: imageX[y, x] = sumKernel[0] # If we have to normalize if sumKernelWeights[1] != 0.0: imageY[y, x] = sumKernel[1] / sumKernelWeights[1] else: imageY[y, x] = sumKernel[1] magnitude[y, x] = sqrt(imageX[y, x] * imageX[y, x] + imageY[y, x] * imageY[y, x]) direction[y, x] = atan2(imageY[y, x], imageX[y, x]) if normalizeMagnitude == True: maximum, minimum = imageMaxMin(magnitude) for x, y in itertools.product(range(0, width), range(0, height)): magnitude[y, x] = (magnitude[y, x] - minimum) / float(maximum - minimum) return magnitude, direction, imageX, imageY
def regionSize(backProjImage, newBackProjImage, pos, newPos, sizeReg): # Compute geometric moments momS = createImageF(3, 3) momT = createImageF(3, 3) 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])): x, y = pos[0] + deltaX, pos[1] + deltaY for m, n in itertools.product(range(0, 3), range(0, 3)): momS[n, m] += (x**n) * (y**m) * backProjImage[y, x] x, y = newPos[0] + deltaX, newPos[1] + deltaY for m, n in itertools.product(range(0, 3), range(0, 3)): momT[n, m] += (x**n) * (y**m) * newBackProjImage[y, x] xc, yc = momS[1, 0] / momS[0, 0], momS[0, 1] / momS[0, 0] a = momS[2, 0] / momS[0, 0] - xc * xc b = 2 * (momS[1, 1] / momS[0, 0] - xc * yc) c = momS[0, 2] / momS[0, 0] - yc * yc sxS = int(sqrt((a + c - sqrt(b * b + (a - c) * (a - c)) / 2))) syS = int(sqrt((a + c + sqrt(b * b + (a - c) * (a - c)) / 2))) xc, yc = momT[1, 0] / momT[0, 0], momT[0, 1] / momT[0, 0] a = momT[2, 0] / momT[0, 0] - xc * xc b = 2 * (momT[1, 1] / momT[0, 0] - xc * yc) c = momT[0, 2] / momT[0, 0] - yc * yc sx = int(sqrt((a + c - sqrt(b * b + (a - c) * (a - c)) / 2))) sy = int(sqrt((a + c + sqrt(b * b + (a - c) * (a - c)) / 2))) sy = sy * sizeReg[1] / syS sx = sx * sizeReg[0] / sxS return [int(xc), int(yc)], [int(sx), int(sy)]
def weightedKrawtchoukPolynomials(p, width): # Data containers sigma = createVectorF(width) ro = createVectorF(width) K = createImageF(width, width) # Coefficient size N = width - 1 # Weight for x in range(0, width): sigma[x] = nCr(N, x) * pow(p, x) * pow(1 - p, N - x) # Scale factor. Commented direct computation and using for to avoid factorial #for n in range(0,width): # ro[n] = pow(-1,n) * pow((1-p)/p,n) * (float(factorial(n)) / risingFactorial(-N, n)) ro[0] = 1 for n in range(1, N): ro[n] = (-1 * ((1.0 - p) / p) * n / (-N + (n - 1))) * ro[n - 1] ro[N] = (((1.0 - p) / p) * N) * ro[N - 1] # Krawtchouk matrix that store result of the polynomial # Each row is a polynomial each column is the polynomial value for an x value # Alternatively, we could have used the polynomial generating function q = 1.0 / p for n, x in itertools.product(range(0, width), range(0, width)): for s in range(0, width): K[n, x] += pow(-1, s) * nCr(N - x, n - s) * nCr(x, s) * pow( q - 1, n - s) # Normalize rows for stability for n in range(0, width): scale = K[n, 0] for x in range(0, width): K[n, x] /= scale # Obtain the coefficients A of the polynomials from K # Solve for the coefficients A in A*C = K C = createImageF(width, width) for n, x in itertools.product(range(0, width), range(0, width)): C[n, x] = pow(x, n) CT = np.transpose(C) KT = np.transpose(K) AT = np.linalg.solve(CT, KT) # solves the equation A*x=b A*C = k, C'*A' = K' A = np.transpose(AT) # Product defining the weighted w = createImageF(width, width) for n, x in itertools.product(range(0, width), range(0, width)): w[n, x] = sqrt(sigma[x] / ro[n]) return K, A, sigma, ro, w
def backProjection(sourceImage, targetImage, qSource, pSource, pTarget, sizeReg, histoSize): height, width = len(sourceImage), len(sourceImage[0]) colourScale = 256.0 / histoSize # Projection 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] = qSource[Cr, Cb] Cb, Cr = colourFeature(targetImage[y, x], colourScale) projectionTarget[y, x] = qSource[Cr, Cb] # Compute geometric moments momS = createImageF(3, 3) momT = createImageF(3, 3) 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])): x, y = pSource[0] + deltaX, pSource[1] + deltaY for m, n in itertools.product(range(0, 3), range(0, 3)): momS[n, m] += (x**n) * (y**m) * projectionSource[y, x] x, y = pTarget[0] + deltaX, pTarget[1] + deltaY for m, n in itertools.product(range(0, 3), range(0, 3)): momT[n, m] += (x**n) * (y**m) * projectionTarget[y, x] xc, yc = momS[1, 0] / momS[0, 0], momS[0, 1] / momS[0, 0] a = momS[2, 0] / momS[0, 0] - xc * xc b = 2 * (momS[1, 1] / momS[0, 0] - xc * yc) c = momS[0, 2] / momS[0, 0] - yc * yc sxS = int(sqrt((a + c - sqrt(b * b + (a - c) * (a - c)) / 2))) syS = int(sqrt((a + c + sqrt(b * b + (a - c) * (a - c)) / 2))) xc, yc = momT[1, 0] / momT[0, 0], momT[0, 1] / momT[0, 0] a = momT[2, 0] / momT[0, 0] - xc * xc b = 2 * (momT[1, 1] / momT[0, 0] - xc * yc) c = momT[0, 2] / momT[0, 0] - yc * yc sx = int(sqrt((a + c - sqrt(b * b + (a - c) * (a - c)) / 2))) sy = int(sqrt((a + c + sqrt(b * b + (a - c) * (a - c)) / 2))) sy = sy * sizeReg[1] / syS sx = sx * sizeReg[0] / sxS return [int(xc), int(yc)], [int(sx), int(sy)]
def findLongestCentredSegmentinImage(imageName, gaussianKernelSize, sobelKernelSize, upperT, lowerT): # Read image into array and show inputImage, width, height = imageReadL(imageName) # Compute edges and find the segment in the image magnitude, _ = applyCannyEdgeDetector(inputImage, gaussianKernelSize, sobelKernelSize, upperT, lowerT) mainSegmentAverage = findLongestSegment(magnitude) # Compute centre numPoints = len(mainSegmentAverage) centre = [0, 0] for p in range(0, numPoints): centre[0] += (mainSegmentAverage[p])[0] centre[1] += (mainSegmentAverage[p])[1] centre[0] /= numPoints centre[1] /= numPoints # Respect to the center and convert to an image array shape = createImageF(numPoints, 2) for p in range(0, numPoints): y, x = (mainSegmentAverage[p])[0], (mainSegmentAverage[p])[1] shape[0, p] = y - centre[0] shape[1, p] = x - centre[1] return centre, shape, width, height
def reconstruction(coefficients): # Maximum frequency maxFrequencyH = int((len(coefficients) - 1) / 2) maxFrequencyW = int((len(coefficients[0]) - 1) / 2) height = 2 * maxFrequencyH width = 2 * maxFrequencyW # Adjust the size of the data to be even m = float(width) n = float(height) if width % 2 == 0: m = width + 1 if height % 2 == 0: n = height + 1 # Fundamental frequency ww = (2.0 * pi) / float(m) wh = (2.0 * pi) / float(n) reconstructionImage = createImageF(m, n) for x in range(0, width): printProgress(x, width - 1) for y in range(0, height): for kw,kh in itertools.product(range(-maxFrequencyW, maxFrequencyW + 1), \ range(-maxFrequencyH, maxFrequencyH + 1)): indexInArrayW = kw + maxFrequencyW indexInArrayH = kh + maxFrequencyH reconstructionImage[y,x] += \ (coefficients[indexInArrayH, indexInArrayW][0] / (m*n)) * (cos(x * ww * kw) * cos(y * wh * kh) - sin(x * ww * kw) * sin(y * wh * kh)) + \ (coefficients[indexInArrayH, indexInArrayW][1] / (m*n)) * (cos(x * ww * kw) * sin(y * wh * kh) + sin(x * ww * kw) * cos(y * wh * kh)) return reconstructionImage
def createLaplacianKernel(kernelSize, sigma): # 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] # Normalize for x, y in itertools.product(range(0, kernelSize), range(0, kernelSize)): kernelLaplacian[y, x] /= sumValues return kernelLaplacian
def applyKernelF(inputImage, kernelImage): height = len(inputImage) width = len(inputImage[0]) kernelHeight = len(kernelImage) kernelWidth = len(kernelImage[0]) kernelCentreY = int((kernelHeight - 1) / 2) kernelCentreX = int((kernelWidth - 1) / 2) # Create images to store the result outputImage = createImageF(width, height) for x, y in itertools.product(range(0, width), range(0, height)): sumKernel = 0.0 sumKernelWeights = 0.0 for wx, wy in itertools.product(range(0, kernelWidth), range(0, kernelHeight)): posY = y + wy - kernelCentreY posX = x + wx - kernelCentreX if posY > -1 and posY < height and posX > -1 and posX < width: sumKernel += float(inputImage[posY, posX]) * float( kernelImage[wy, wx]) sumKernelWeights += float(kernelImage[wy, wx]) # If we have to normalize if sumKernelWeights != 0.0: outputImage[y, x] = sumKernel / sumKernelWeights else: outputImage[y, x] = sumKernel return outputImage
def densityHistogram(image, position, regionRadius, sigma, histoSize): height = len(image) width = len(image[0]) # Quantization scale colourScale = 256.0 / histoSize histogram = createImageF(histoSize, histoSize) sumValue = 0 for deltaX, deltaY in itertools.product( range(-regionRadius[0], regionRadius[0]), range(-regionRadius[1], regionRadius[1])): x, y = position[0] + deltaX, position[1] + deltaY if x > 0 and y > 0 and x < width and y < height: w = exp(-(deltaX * deltaX + deltaY * deltaY) / (2 * sigma * sigma)) rgb = image[y, x] / 256.0 Cb = int((128 - 37.79 * rgb[0] - 74.203 * rgb[1] + 112 * rgb[2]) / colourScale) Cr = int((128 + 112 * rgb[0] - 93.786 * rgb[1] - 18.214 * rgb[2]) / colourScale) histogram[Cr, Cb] += w sumValue += w for r, b in itertools.product(range(0, histoSize), range(0, histoSize)): histogram[r, b] /= sumValue return histogram
def createSobelKernel(kenrelSize): sobelX = createImageF(kenrelSize, kenrelSize) sobelY = createImageF(kenrelSize, kenrelSize) # Create kernel for x, y in itertools.product(range(0, kenrelSize), range(0, kenrelSize)): # Smooth smoothX = factorial(kenrelSize - 1) / (factorial(kenrelSize - 1 - x) * factorial(x)) smoothY = factorial(kenrelSize - 1) / (factorial(kenrelSize - 1 - y) * factorial(y)) # Pascal if (kenrelSize - 2 - x >= 0): p1X = factorial(kenrelSize - 2) / (factorial(kenrelSize - 2 - x) * factorial(x)) else: p1X = 0 if (kenrelSize - 2 - y >= 0): p1Y = factorial(kenrelSize - 2) / (factorial(kenrelSize - 2 - y) * factorial(y)) else: p1Y = 0 # Pascal shift to the right xp = x - 1 if (kenrelSize - 2 - xp >= 0 and xp >= 0): p2X = factorial(kenrelSize - 2) / (factorial(kenrelSize - 2 - xp) * factorial(xp)) else: p2X = 0 yp = y - 1 if (kenrelSize - 2 - yp >= 0 and yp >= 0): p2Y = factorial(kenrelSize - 2) / (factorial(kenrelSize - 2 - yp) * factorial(yp)) else: p2Y = 0 # Sobel sobelX[y, x] = smoothX * (p1Y - p2Y) sobelY[y, x] = smoothY * (p1X - p2X) return sobelX, sobelY
def meanShift(inputImage, q, sizeReg, sigma, histoSize, newPos): # Weights weights = createImageF(2 * sizeReg[0], 2 * sizeReg[1]) currPos = [0, 0] colourScale = 256.0 / histoSize while (currPos != newPos): currPos = newPos qs = densityHistogram(inputImage, currPos, sizeReg, sigma, histoSize) # Weights for deltaX, deltaY in itertools.product(range(-sizeReg[0],sizeReg[0]), \ range(-sizeReg[1], sizeReg[1])): # Position of the pixel in the image and in the weight array x, y = currPos[0] + deltaX, currPos[1] + deltaY px, py = deltaX + sizeReg[0], deltaY + sizeReg[1] # Features Cb, Cr = colourFeature(inputImage[y, x], colourScale) # Update if qs[Cr, Cb] > 0: weights[py, px] = sqrt(q[Cr, Cb] / qs[Cr, Cb]) else: weights[py, px] = sqrt(q[Cr, Cb] / .000000000001) # Compute mean shift sums meanSum = [0, 0] kernelSum = 0 for deltaX, deltaY in itertools.product(range(-sizeReg[0],sizeReg[0]), \ range(-sizeReg[1], sizeReg[1])): # Position of the pixel in the image x, y = currPos[0] + deltaX, currPos[1] + deltaY # Kernel parameter w = exp(-(deltaX * deltaX + deltaY * deltaY) / (2 * sigma * sigma)) # Weight index px, py = deltaX + sizeReg[0], deltaY + sizeReg[1] # Mean sum meanSum[0] += w * weights[py, px] * x meanSum[1] += w * weights[py, px] * y # Kernel sum kernelSum += w * weights[py, px] # Mean shift newPos = [int(meanSum[0] / kernelSum), int(meanSum[1] / kernelSum)] return newPos
def createGaussianKernel(kernelSize): sigma = kernelSize / 3.0 kernelImage = createImageF(kernelSize, kernelSize) centre = (kernelSize - 1) / 2 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)) ) return kernelImage
def backProjectionImage(image, q, histoSize): height, width = len(image), len(image[0]) colourScale = 256.0 / histoSize # Projection projection = createImageF(width, height) for x, y in itertools.product(range(0, width), range(0, height)): Cb, Cr = colourFeature(image[y, x], colourScale) projection[y, x] = q[Cr, Cb] return projection
def geometricMoments(pixelList, numMoments): numPoints = len(pixelList) # Compute moments M = createImageF(numMoments, numMoments) for m, n in itertools.product(range(0, numMoments), range(0, numMoments)): for indexPixel in range(0, numPoints): y = (pixelList[indexPixel])[0] x = (pixelList[indexPixel])[1] val = (pixelList[indexPixel])[2] M[n, m] += (x**n) * (y**m) * val return M
def geometricInvariantMoments(pixelList, numMoments): numPoints = len(pixelList) # Compute moments M = createImageF(numMoments, numMoments) for m, n in itertools.product(range(0, numMoments), range(0, numMoments)): for indexPixel in range(0, numPoints): y = (pixelList[indexPixel])[0] x = (pixelList[indexPixel])[1] val = (pixelList[indexPixel])[2] M[n, m] += (x**n) * (y**m) * val # Geometric central Moments xc, yc = M[1, 0] / M[0, 0], M[0, 1] / M[0, 0] m11 = M[1, 1] / M[0, 0] - xc * yc m20 = M[2, 0] / M[0, 0] - xc**2 m02 = M[0, 2] / M[0, 0] - yc**2 if m20 < m02: t = -(0.5 * atan(2.0 * m11 / (m20 - m02)) + pi / 2.0) else: t = -(0.5 * atan(2.0 * m11 / (m20 - m02))) # Geometric invariant moments v = createImageF(numMoments, numMoments) vn = createImageF(numMoments, numMoments) for m, n in itertools.product(range(0, numMoments), range(0, numMoments)): for indexPixel in range(0, numPoints): y = (pixelList[indexPixel])[0] x = (pixelList[indexPixel])[1] val = (pixelList[indexPixel])[2] v[n, m] += ((x - xc) * cos(t) - (y - yc) * sin(t))**n * ((x - xc) * sin(t) + (y - yc) * cos(t))**m * val l = (1 + ((n + m) / 2.0)) vn[n, m] = v[n, m] / pow(M[0, 0], l) return vn
def imageLogF(image, scale=100): height = len(image) width = len(image[0]) maximum = amax(image) # Create a gray level image for display logImage = createImageF(width, height) # Scale the float values into gray scale values without 0 and negative values for y in range(0, height): for x in range(0, width): # Set to log value logImage[y, x] = log(1.0 + (abs(image[y, x]) / maximum) * scale) return logImage
def computeCoefficients(inputImage): height = len(inputImage) width = len(inputImage[0]) # Create coefficients Image. Two floats to represent a complex number # Maximum frequency according to sampling 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 if height % 2 == 0: n = height + 1 # Fundamental frequency ww = (2.0 * pi) / float(m) wh = (2.0 * pi) / float(n) # Compute values for kw in range(-maxFrequencyW, maxFrequencyW + 1): printProgress(kw + maxFrequencyW, numCoefficientsW - 1) for kh in range(-maxFrequencyH, maxFrequencyH + 1): indexInArrayW = kw + maxFrequencyW indexInArrayH = kh + maxFrequencyH for x, y in itertools.product(range(0, width), range(0, height)): coefficients[indexInArrayH, indexInArrayW][0] += inputImage[y, x] * ( cos(x * ww * kw) * cos(y * wh * kh) - sin(x * ww * kw) * sin(y * wh * kh)) coefficients[indexInArrayH, indexInArrayW][1] += inputImage[y, x] * ( cos(x * ww * kw) * sin(y * wh * kh) + sin(x * ww * kw) * cos(y * wh * kh)) for kw in range(-maxFrequencyW, maxFrequencyW + 1): for kh in range(-maxFrequencyH, maxFrequencyH + 1): coefficients[indexInArrayH, indexInArrayW][0] /= (m * n) coefficients[indexInArrayH, indexInArrayW][1] /= (m * n) return coefficients, maxFrequencyW, maxFrequencyH
def computePowerfromCoefficients(coefficients): # Maximum frequency maxFrequencyH = int((len(coefficients) - 1) / 2) maxFrequencyW = int((len(coefficients[0]) - 1) / 2) # Power powerImage = createImageF(1 + 2 * maxFrequencyW, 1 + 2 * maxFrequencyH) for kw in range(-maxFrequencyW, maxFrequencyW + 1): printProgress(kw + maxFrequencyW, 2 * maxFrequencyW) for kh in range(-maxFrequencyH, maxFrequencyH + 1): indexInArrayW = kw + maxFrequencyW indexInArrayH = kh + maxFrequencyH powerImage[indexInArrayH, indexInArrayW] = sqrt(coefficients[indexInArrayH, indexInArrayW][0] * coefficients[indexInArrayH, indexInArrayW][0] + \ coefficients[indexInArrayH, indexInArrayW][1] * coefficients[indexInArrayH, indexInArrayW][1]) return powerImage
def findLongesSegmentinImage(imageName, gaussianKernelSize, sobelKernelSize, upperT, lowerT): # Read image into array and show inputImage, width, height = imageReadL(imageName) # Compute edges and find the segment in the image magnitude, _ = applyCannyEdgeDetector(inputImage, gaussianKernelSize, sobelKernelSize, upperT, lowerT) mainSegmentAverage = findLongestSegment(magnitude) # Convert to an image array numPoints = len(mainSegmentAverage) shape = createImageF(numPoints, 2) for p in range(0, numPoints): y, x = (mainSegmentAverage[p])[0], (mainSegmentAverage[p])[1] shape[0, p] = y shape[1, p] = x return shape, width, height
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
def applyCannyEdgeDetector(inputImage, GaussianKernelSize, sobelKernelSize, upperT, lowerT, returnGradient=False): height = len(inputImage) width = len(inputImage[0]) normalizeMagnitude = True windowDelta = 1 # 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, mX, mY = applyKernelMA(gaussianImage, sobelX, sobelY, normalizeMagnitude) # Weight magnitude by the variance. This is useful for corner extraction since suppress the internal corner weightedMagnitude = createImageF(width, height) for x, y in itertools.product(range(0, width), range(0, height)): sumKernel = 1.0 / 8.0 for wx, wy in itertools.product(range(-1, 2), range(-1, 2)): posY = y + wy posX = x + wx if posY > -1 and posY < height and posX > -1 and posX < width: sumKernel += abs( float(inputImage[posY, posX]) - float(inputImage[y, x])) sumKernel /= 8.0 weightedMagnitude[y, x] = magnitude[y, x] * sumKernel # 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: normalAngle -= pi # Angle defining the first point baseAngle = int(4 * normalAngle / pi) * (pi / 4.0) # Integer delta positions for interpolation # We use -y since the image origin is in top corner x1, y1 = int(round(cos(baseAngle))), -int(round(sin(baseAngle))) x2, y2 = int(round(cos(baseAngle + pi / 4.0))), \ -int(round(sin(baseAngle + pi / 4.0))) # How far we are from (x1,y1). Maximum difference is math.pi / 4.0, so we multiply by 2 w = cos(2.0 * (normalAngle - baseAngle)) # Point to interpolate M1 = w * weightedMagnitude[y + y1, x + x1] + ( 1.0 - w) * weightedMagnitude[y + y2, x + x2] # Point to interpolate for pixels in the other side of the edge M2 = w * weightedMagnitude[y - y1, x - x1] + ( 1.0 - w) * weightedMagnitude[y - y2, x - x2] # Determine if it is a maximum. If so make sure it will be preserved if weightedMagnitude[y, x] > M1 and weightedMagnitude[y, x] > M2: maxImage[y, x] = magnitude[y, x] # To compute hysteresis thresholded images we require two thresholds edges = createImageF(width, height) potentialEdges = [] # Divide pixels as edges, no edges and we are not sure 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 # Resolve the potential edges for x, y in itertools.product(range(1, width - 1), range(1, height - 1)): # For each edge if edges[y, x] == 255: # Examine neighbour potentialEdges = [] for wx, wy in itertools.product( range(-windowDelta, windowDelta + 1), range(-windowDelta, windowDelta + 1)): # It becomes an edge if edges[y + wy, x + wx] == 128: edges[y + wy, x + wx] = 255 potentialEdges.append((y + wy, x + wx)) # Look into new edges while len(potentialEdges) > 0: # Take element from potential edges y = (potentialEdges[0])[0] x = (potentialEdges[0])[1] potentialEdges = potentialEdges[1:] # Examine neighbour for wx, wy in itertools.product( range(-windowDelta, windowDelta + 1), range(-windowDelta, windowDelta + 1)): # It becomes an edge if edges[y + wy, x + wx] == 128: edges[y + wy, x + wx] = 255 potentialEdges.append((y + wy, x + wx)) # Clean up remaining potential edges for x, y in itertools.product(range(1, width - 1), range(1, height - 1)): if edges[y, x] == 128: edges[y, x] = 0 if returnGradient == False: return edges, angle return edges, angle, mX, mY
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