Advertisement
akariya

[ECE558] Final Project Blob Detection

Dec 6th, 2019
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.68 KB | None | 0 0
  1. import cv2
  2. import numpy as np
  3. import math
  4. import matplotlib.pyplot as plt
  5. import argparse
  6. from collections import Counter
  7. np.fft.restore_all()
  8.  
  9.  
  10. def resize(img, newY, newX):
  11.  
  12.     res = np.zeros([newY, newX], dtype = 'uint8')
  13.     i = 0
  14.     factY = newY/img.shape[0]
  15.     factX = newX/img.shape[1]
  16.     while(i < newY):
  17.         j = 0
  18.         while(j < newX):
  19.             res[i][j] = img[math.floor(i/factY)][math.floor(j/factX)]
  20.             j += 1
  21.         i += 1
  22.  
  23.     return np.uint8(res)
  24.  
  25. def conv2(img, kernel, padding_style):
  26.  
  27.     h, w = kernel.shape
  28.     yO, xO = img.shape
  29.     paddedImg = np.zeros([yO + math.floor(h/2) + math.floor(h/2), xO + math.floor(w/2) + math.floor(w/2)], dtype='float32')
  30.     paddedImg[math.floor(h/2) : yO + math.floor(h/2),math.floor(w/2) : xO + math.floor(w/2)] = img[:,:]
  31.  
  32.     if(padding_style == 'zero-padding'):
  33.         paddedImg = paddedImg
  34.     elif(padding_style == 'wrap-around'):
  35.         i = math.floor(w/2) - 1
  36.         j = xO + math.floor(w/2) - 1
  37.         while(i >= 0):
  38.             paddedImg[:,i] = paddedImg[:,j]
  39.             j -= 1
  40.             i -= 1
  41.         i = math.floor(h/2) - 1
  42.         j = yO + math.floor(w/2) - 1
  43.         while(i >= 0):
  44.             paddedImg[i,:] = paddedImg[j,:]
  45.             j -= 1
  46.             i -= 1
  47.         i = math.floor(w/2) + xO
  48.         j = math.floor(w/2)
  49.         while(i < paddedImg.shape[1]):
  50.             paddedImg[:,i] = paddedImg[:,j]
  51.             j += 1
  52.             i += 1
  53.         i = math.floor(h/2) + yO
  54.         j = math.floor(h/2)
  55.         while(i < paddedImg.shape[0]):
  56.             paddedImg[i,:] = paddedImg[j,:]
  57.             j += 1
  58.             i += 1
  59.     elif(padding_style == 'copy-edge'):
  60.         i = math.floor(w/2) - 1
  61.         j = math.floor(w/2)
  62.         while(i >= 0):
  63.             paddedImg[:,i] = paddedImg[:,j]
  64.             i -= 1
  65.         i = math.floor(h/2) - 1
  66.         j = math.floor(h/2)
  67.         while(i >= 0):
  68.             paddedImg[i,:] = paddedImg[j,:]
  69.             i -= 1
  70.         i = math.floor(w/2) + xO
  71.         j = xO + math.floor(w/2) - 1
  72.         while(i < paddedImg.shape[1]):
  73.             paddedImg[:,i] = paddedImg[:,j]
  74.             i += 1
  75.         i = math.floor(h/2) + yO
  76.         j = yO + math.floor(h/2) - 1
  77.         while(i < paddedImg.shape[0]):
  78.             paddedImg[i,:] = paddedImg[j,:]
  79.             i += 1
  80.     elif(padding_style == 'reflect-across-edge'):
  81.         i = math.floor(w/2) - 1
  82.         j = math.floor(w/2)
  83.         while(i >= 0):
  84.             paddedImg[:,i] = paddedImg[:,j]
  85.             j += 1
  86.             i -= 1
  87.         i = math.floor(h/2) - 1
  88.         j = math.floor(h/2)
  89.         while(i >= 0):
  90.             paddedImg[i,:] = paddedImg[j,:]
  91.             j += 1
  92.             i -= 1
  93.         i = math.floor(w/2) + xO
  94.         j = xO + math.floor(w/2) - 1
  95.         while(i < paddedImg.shape[1]):
  96.             paddedImg[:,i] = paddedImg[:,j]
  97.             j -= 1
  98.             i += 1
  99.         i = math.floor(h/2) + yO
  100.         j = yO + math.floor(h/2) - 1
  101.         while(i < paddedImg.shape[0]):
  102.             paddedImg[i,:] = paddedImg[j,:]
  103.             j -= 1
  104.             i += 1
  105.  
  106.     img = paddedImg
  107.     y, x = img.shape
  108.     c = 1
  109.     imgF = np.fft.fft2(img)
  110.     imgFS = np.fft.fftshift(imgF)
  111.     kernelF = np.fft.fft2(kernel, [y,x])
  112.     kernelFS = np.fft.fftshift(kernelF)
  113.     imgF = imgFS * kernelFS
  114.     imgishift = np.fft.ifftshift(imgF)
  115.     img = np.fft.ifft2(imgishift)
  116.     img = np.abs(img)
  117.     img = img[h-1:h-1+yO, w-1:w-1+xO]
  118.     return img
  119.  
  120. def laplacian_of_gaussian_kernel(size_x, size_y, sigma):
  121.  
  122.     x, y = np.mgrid[-size_x//2 + 1:size_x//2 + 1,-size_y//2 + 1:size_y//2 + 1]
  123.     kernel = (-1 / (np.pi * (sigma ** 4))) * (1 - (((x ** 2) + (y ** 2))/(2 * (sigma ** 2)))) * np.exp((-1) * (((x ** 2) + (y ** 2))/(2 * (sigma ** 2))))
  124.     kernel = (kernel + kernel.mean()) * (sigma ** 2)
  125.     return kernel
  126.  
  127. def generate_scale_space(img, num_of_scales, sigma, scale_multiplier):
  128.  
  129.     scale_space = []
  130.     sigmas = []
  131.     for i in range(0, num_of_scales):
  132.         scaled_sigma = sigma * (scale_multiplier ** i)
  133.         kernel_size = max(1,math.floor(6*scaled_sigma))
  134.         if(kernel_size % 2 == 0):
  135.             kernel_size += 1
  136.         kernel = laplacian_of_gaussian_kernel(kernel_size, kernel_size, scaled_sigma)
  137.         current = conv2(img, kernel, 'copy-edge')
  138.         scale_space.append(current.astype('float64'))
  139.         sigmas.append(scaled_sigma)
  140.         # cv2.imshow('Scale Space', np.uint8(current))
  141.         # cv2.waitKey(0)
  142.         # cv2.destroyAllWindows()
  143.  
  144.     scale_space = np.array([i for i in scale_space])
  145.     return scale_space, sigmas
  146.  
  147. def nms_3D(scale_space_2D_NMS, threshold, sigma_scale, up_scale):
  148.  
  149.     y, x = scale_space_2D_NMS[0].shape[0], scale_space_2D_NMS[0].shape[1]
  150.     num_of_scales = len(scale_space_2D_NMS)
  151.     coordinates = []
  152.     for k in range(0, num_of_scales):
  153.         current = np.zeros([y, x], dtype = 'float64')
  154.         for i in range(1, y):
  155.             for j in range(1, x):
  156.                 img_slice = scale_space_2D_NMS[max(0, k-1):min(num_of_scales, k+2),i-1:i+2,j-1:j+2]
  157.                 result = np.max(img_slice.flatten())
  158.                 if(np.uint8(result) >= threshold and result == scale_space_2D_NMS[k,i,j] and Counter(img_slice.flatten())[result] == 1):
  159.                     coordinates.append((up_scale * i, up_scale * j, up_scale * sigma_scale[k]))
  160.                     current[i][j] = result
  161.  
  162.     coordinates = list(set(coordinates))            
  163.     return coordinates
  164.  
  165.  
  166. def build_octaves(img, num_of_scales, sigma, scale_multiplier, num_of_octaves):
  167.        
  168.     octaves = []
  169.     sigma_scales = []
  170.     for i in range(num_of_octaves):
  171.         scale_space, sigmas = generate_scale_space(img, num_of_scales, sigma, scale_multiplier)
  172.         octaves.append(scale_space)
  173.         sigma_scales.append(sigmas)
  174.         if(i < num_of_octaves - 1):
  175.             width = int(img.shape[1] * 50 / 100)
  176.             height = int(img.shape[0] * 50 / 100)
  177.             dim = (width, height)
  178.             img = resize(img, height, width)
  179.             sigma = 2 * sigma
  180.     return octaves, sigma_scales
  181.  
  182.  
  183. def non_max_draw(img, coordinates, label):
  184.     y, x, c = img.shape
  185.     done = np.zeros([y, x, c], dtype = 'uint8')
  186.     coordinates = np.array(coordinates)
  187.     coordinates = coordinates[coordinates[:,2].argsort()]
  188.     sigmasss = []
  189.     i = 0
  190.     while(i < len(coordinates)):
  191.         y, x, sigma_k = coordinates[i]
  192.         if(done[int(y),int(x),0] == 255):
  193.             i += 1
  194.             continue
  195.         sigmasss.append(np.float32(sigma_k * (2 ** 0.5)))
  196.         img = cv2.circle(img, (int(x), int(y)), np.float32((sigma_k * (2 ** 0.5)) * 1.2), (0, 0, 255), 1)
  197.         done = cv2.circle(done, (int(x), int(y)), np.float32(sigma_k * (4 ** 0.5)), (255, 255, 255), -1)
  198.         i += 1
  199.     cv2.imshow(label, np.uint8(img))
  200.  
  201. def detect_bobs(img, num_of_octaves, num_of_scales, sigma, scale_multiplier):
  202.     octaves, sigma_scale = build_octaves(img, num_of_scales, sigma, scale_multiplier, num_of_octaves)
  203.     coordinates = []
  204.     # set particular index to change threshold for that index, eg: 3rd octave, index = 2, set thresholds[2] = 0
  205.     thresholds = [32] * num_of_octaves
  206.     for i, octave in enumerate(octaves):
  207.         coordinates += nms_3D(octave, thresholds[i], sigma_scale[i], 2 ** i)
  208.  
  209.     img = cv2.cvtColor(img.astype('uint8'), cv2.COLOR_GRAY2BGR)
  210.     img = non_max_draw(img, coordinates, 'Blobs')
  211.     cv2.waitKey(0)
  212.     cv2.destroyAllWindows()
  213.  
  214. # driver code
  215. parser = argparse.ArgumentParser(description='Blob Detection')
  216. requiredArgs = parser.add_argument_group('required arguments')
  217. requiredArgs.add_argument('-i', action='store', dest='img_path',help='Enter image path (relative path)', required=True)
  218. requiredArgs.add_argument('-o', action='store', dest='num_of_octaves', type=str, help='Enter number of ocatves', required=True)
  219. requiredArgs.add_argument('-n', action='store', dest='num_of_scales', type=str, help='Enter number of layers in the octave', required=True)
  220. requiredArgs.add_argument('-s', action='store', dest='sigma', type=str, help='Enter starting sigma', required=True)
  221. requiredArgs.add_argument('-k', action='store', dest='scale_multiplier', type=str, help='Enter scale multiplier', required=True)
  222.  
  223. args = parser.parse_args()
  224. img_path = args.img_path
  225. num_of_octaves = int(args.num_of_octaves)
  226. num_of_scales = int(args.num_of_scales)
  227. sigma = float(args.sigma)
  228. scale_multiplier = float(args.scale_multiplier)
  229.  
  230. img = cv2.imread(img_path, 0)
  231. img = img.astype('float64')
  232.  
  233. detect_bobs(img, num_of_octaves, num_of_scales, sigma, scale_multiplier)
  234.  
  235.  
  236. # to display log kernel
  237. # kernel = laplacian_of_gaussian_kernel(81, 81, 13.5)
  238. # plt.imshow(kernel, interpolation='none')
  239. # plt.colorbar()
  240. # plt.show()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement