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
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))) # Compute sx, sy, the size of the projection in current frame 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))) # Determine size of the region in current frame sy = int(sy * sizeReg[1] / syS) sx = int(sx * sizeReg[0] / sxS) # Show results p = [int(xc), int(yc)] m, _ = imageMaxMin(projectionTarget) borderDistance = [sx - 2, sy - 2] for x, y in itertools.product(range(p[0] - sx, p[0] + sx), \ range(p[1] - sy, p[1] + sy)): if abs(x - p[0]) > borderDistance[0] or abs(y - p[1]) > borderDistance[1]: projectionTarget[y, x] = m showImageF(projectionTarget)
# 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])
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: watershed[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 watershed[y, x] == 0: floodRegion.append((y, x)) # 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: n = [] # List of neighbours
imageName = Input image name ''' pathToDir = "../../Images/Chapter3/Input/" imageName = "Horse.png" # Read image into array inputImage, width, height = imageReadL(pathToDir + imageName) # Show input image showImageL(inputImage) # Create image to store the normalization outputNormalizedImage = createImageL(width, height) # Maximum and range maxVal, miniVal = imageMaxMin(inputImage) brightRange = float(maxVal - miniVal) # Set the pixels in the output image for x, y in itertools.product(range(0, width), range(0, height)): # Normalize the pixel value according to the range outputNormalizedImage[y, x] = round( (inputImage[y, x] - miniVal) * 255.0 / brightRange) # Compute histogram histogramNormalizedImage = computeHistogram(outputNormalizedImage) # Show output image and plot histogram showImageL(outputNormalizedImage) plotHistogram(histogramNormalizedImage)
if bucket > 0 and bucket < 2 * height - 1: weight = c - int(c) accHorizontal[m, bucket] += (1.0 - weight) accHorizontal[m, bucket + 1] += weight # Lines between 45 and 135 degrees angle = ((45.0 + m) * pi) / 180.0 c = x - y / tan(angle) bucket = int(c) if bucket > 0 and bucket < 2 * width - 1: weight = c - int(c) accVertical[m, bucket] += (1.0 - weight) accVertical[m, bucket + 1] += weight # Find maximum maxH, _ = imageMaxMin(accHorizontal) maxV, _ = imageMaxMin(accVertical) maximum = max(maxH, maxV) peakThreshold = peakDetection * maximum # Plot accumulators plot3DHistogram(accHorizontal, [0, maximum]) plot3DHistogram(accVertical, [0, maximum]) # Prepare output image as a dark version of the input outputImage = createScaleImageL(inputImage, 0.5) # Peak detection peakHorizontal = peakDetectorImageL(accHorizontal, peakThreshold) peakVertical = peakDetectorImageL(accVertical, peakThreshold)
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] if addQuadraticTerm: for x, y in itertools.product(range(0, widthPad), range(0, heightPad)): corrImage[y, x] += -squaredTerm[y, x] showImageF(corrImage) maxima, minima = imageMaxMin(corrImage) plot3DHistogram(corrImage, [2 * (minima + maxima) / 3, maxima], [15, -47], False) # Compute Fourier coefficients imageCoeff, maxFrequencyW, maxFrequencyH = computeCoefficients(inputPad) templateCoeff, _, _ = computeCoefficients(templatePadFlip) # Frequency domain multiplication defines convolution is space domain resultCoeff = createImageF(1 + 2 * maxFrequencyW, 1 + 2 * maxFrequencyH, 2) for kw, kh in itertools.product(range(-maxFrequencyW, maxFrequencyW + 1), \ range(-maxFrequencyH, maxFrequencyH + 1)): w = kw + maxFrequencyW h = kh + maxFrequencyH resultCoeff[h,w][0] = (imageCoeff[h,w][0] * templateCoeff[h,w][0] - \ imageCoeff[h,w][1] * templateCoeff[h,w][1])
buketAngleBase = int((pointAngle * 180.0) / pi) # More buckets if the points are close for deltaBucket in range(-incAngle, +incAngle + 1): bucket = buketAngleBase + deltaBucket if bucket < 0: bucket = 360 + bucket if bucket >= 360: bucket = bucket - 360 w = (incAngle - fabs(deltaBucket)) / float(incAngle) accM[bucket] += w # Find maximum and plot histogram maximum, _ = imageMaxMin(accM) peakThreshold = peakDetection * maximum plotHistogram(accM) # Prepare output image as a dark version of the input outputImage = createScaleImageL(inputImage, 0.5) # Gather evidence for the r parameter in a second accumulator peaks = peakDetectorVector(accM, peakThreshold) for peakIndex in range(0, len(peaks)): m = peaks[peakIndex] accR = createVectorF(maxLenght) angle = (m * pi) / 180.0 for x, y in itertools.product(range(0, width), range(0, height)): if magnitude[y, x] != 0:
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 # Find maximum maximum, _ = imageMaxMin(accumulator) peakThreshold = peakDetection * maximum # Plot accumulator plot3DHistogram(accumulator) # Prepare output image as a dark version of the input outputImage = createScaleImageL(inputImage, 0.5) # Peak detection peaks = peakDetectorImageL(accumulator, peakThreshold) # Draw lines on output image for peakIndex in range(1, len(peaks)): m = (peaks[peakIndex])[0] r = (peaks[peakIndex])[1]
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
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] # Normalize for x, y in itertools.product(range(0, kernelSize), range(0, kernelSize)): kernelLaplacian[y, x] /= sumValues # Print kernel printImageRangeF(kernelLaplacian, [0, kernelSize - 1], [0, kernelSize - 1], ' 8.2f') # Plot surface maxValue, minValue = imageMaxMin(kernelLaplacian) plotSurface(kernelLaplacian, [minValue, maxValue], 1)
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)