Digital Image Processing - Problem Set 5

Student Names:

  • Karolay Ardila Salazar
  • Julián Sibaja García
  • Andrés Simancas Mateus

Definitions


In [2]:
'''This is a definition script, so we do not have to rewrite code'''

import numpy as np
import os
import cv2
import matplotlib.pyplot as mplt
import random
import json


# set matplotlib to print inline (Jupyter)
%matplotlib inline

# path prefix
pth = '../data/'

# files to be used as samples
# list *files* holds the names of the test images
files = sorted(os.listdir(pth))
print files

# Usefull function
def rg(img_path):
    return cv2.imread(pth+img_path, cv2.IMREAD_GRAYSCALE)


['Fall-Nature-Background-Pictures.jpg', 'Fig6.21(b).jpg', 'Woman.bmp', 'blown_ic.png', 'blurry_moon.png', 'bottles.png', 'building.jpg', 'cameraman.png', 'cameraman_new.png', 'check.png', 'chest.jpg', 'ckt_board_saltpep_prob_pt05.png', 'connected.jpg', 'contact_lens_original.png', 'crosses.png', 'darkPollen.jpg', 'dark_fountain.jpg', 'face.png', 'face.tif', 'fingerprint.jpg', 'flower.jpg', 'fruits.jpg', 'hiro.jpg', 'hubble-original.tif', 'hut.jpg', 'image_0001.jpg', 'image_0002.jpg', 'image_0003.jpg', 'image_0004.jpg', 'image_0005.jpg', 'image_0006.jpg', 'image_0007.jpg', 'image_0008.jpg', 'image_0009.jpg', 'image_0010.jpg', 'image_0011.jpg', 'image_0012.jpg', 'image_0013.jpg', 'image_0014.jpg', 'image_0015.jpg', 'image_0016.jpg', 'image_0017.jpg', 'image_0018.jpg', 'image_0019.jpg', 'image_0020.jpg', 'lena.jpg', 'lightPollen.jpg', 'lowContrastPollen.jpg', 'mms.jpg', 'moon.jpg', 'new_bottles.jpg', 'new_cameraman.png', 'new_chest.bmp', 'noisy_fingerprint.jpg', 'out.png', 'pollen.jpg', 'rectangle.png', 'rose.bmp', 'runway.jpg', 'shapes.PNG', 'skull.bmp', 'small_blobs.jpg', 'spheres.jpg', 'spine.jpg', 'squares.jpg', 'steve_blog.png', 'test_pattern_blurring_orig.png', 'three_bottles.jpg', 'translated_rectangle.png', 'weld_x-ray.jpg']

Problem 1

Write a function that describes each object in a binary image using the Hu statistical moments. The Hu moments are invariant to rotation, scale and translation. These moments can be defined for each region in a binary image. The OpenCV function to compute these moments is cv2.HuMoments. Write down the equations that compute the seven Hu moments for a region.

Análisis

La siguiente función tiene como objetivo encontrar los Hu moments que describen a cada objeto de la imagen shapes.png. Para esto primero guardamos la matriz de la imagen en una variable. Luego definimos nuestra función que recibe una imagen como parámetro. Aplicamos threshold a la imagen para luego con la resultante hallar los objetos con la función cv2.findContours. Ya que tenemos los valores de los contours, podemos mostrar cuantos de estos encontró con su longitud y confirmamos que sean la misma cantidad de objetos que se encuentran en la imagen. Ahora, para cada uno de estos objetos aplicamos cv2.huMoments y mostramos en pantalla los resultados.

Seven Hu moments

$ I_1 = n_{20} + n_{02} $
$ I_2 = (n_{20} - n_{02})^2 + 4n_{11}^2 $
$ I_3 = (n_{30} - n_{12})^2 + (n_{21} - n_{03})^2 $
$ I_4 = (n_{30} + n_{12})^2 + (n_{21} + n_{03})^2 $
$ I_5 = (n_{30} - 3n_{12})(n_{30} + n_{12})[(n_{30} + n_{12})^2 - 3(n_{21} + n_{03})^2] + (3n_{21} - n_{03})(n_{21} + n_{03})(3(n_{30} + n_{12})^2 - (n_{21} + n_{03})^2) $
$ I_6 = (n_{20} - n_{02})[(n_{30} + n_{12})^2 - (n_{21} + n_{03})^2] + 4n_{11}(n_{30} + n_{12})(n_{21} + n_{03}) $
$ I_7 = (3n_{21} - n_{03})(n_{30} + n_{12})[(n_{30} + n_{12})^2 - 3(n_{21} + n_{03})^2] - (n_{30} - 3n_{12})(n_{21} + n_{03})(3(n_{30} + n_{12})^2 - (n_{21} + n_{03})^2) $


In [15]:
image = rg(files[-11])

def huMoments(image):
    ret, threshold = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

    _, contours, _ = cv2.findContours(threshold, cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
    print "Number of contours detected = " + str(len(contours))

    for i in range(len(contours)):
        Hu = cv2.HuMoments(cv2.moments(contours[i])).flatten()
        print str(i) + ' = ' + str(Hu)

    mplt.figure()
    mplt.imshow(image, cmap='gray')
    mplt.title(files[-11])
    
huMoments(image)


Number of contours detected = 17
0 = [  2.28516566e-01   1.51622505e-02   5.96665390e-03   5.40948254e-04
   6.85106641e-07   3.28556348e-05  -6.89289716e-07]
1 = [  3.17013085e-01   6.36120231e-02   8.90898720e-03   1.53855917e-03
   3.75848984e-06   1.21466674e-04  -4.28024355e-06]
2 = [  1.99008905e-01   1.19945861e-02   1.20201210e-27   1.93115646e-27
   2.80774704e-54   1.75276435e-28  -8.79450435e-55]
3 = [  1.66666667e-01   3.31013624e-28   1.21865554e-24   9.78172683e-25
   1.06054885e-48   1.42417596e-38  -1.25781086e-49]
4 = [ 0.17468087  0.00273563  0.          0.          0.          0.          0.        ]
5 = [  1.69595887e-01   9.84987155e-04   3.51718976e-25   8.84382491e-25
   4.53997327e-49   2.60273073e-26  -1.92800200e-49]
6 = [  1.67320569e-01   2.18395085e-04   6.04141661e-26   9.70553149e-27
  -4.09612928e-53  -1.13085454e-28  -2.31419389e-52]
7 = [ 0.16055151  0.00044483  0.          0.          0.          0.          0.        ]
8 = [  1.59335088e-01   3.75621064e-05   0.00000000e+00   0.00000000e+00
   0.00000000e+00   0.00000000e+00   0.00000000e+00]
9 = [  1.92605334e-01   5.75224452e-05   4.56454726e-03   1.73328362e-06
   1.25684113e-10   1.03278959e-08  -8.92875585e-11]
10 = [  4.45430323e-01   1.61360408e-01   1.17355201e-02   1.17694241e-03
  -3.73389436e-06  -4.31886663e-04  -2.27823793e-06]
11 = [  1.59443034e-01   8.51478779e-05   3.63693328e-25   3.94573460e-25
   1.49468737e-49   3.58169841e-27   9.67947241e-52]
12 = [  2.10668986e-01   7.29318139e-03   5.14334090e-03   1.48139184e-04
  -1.12337625e-07  -1.13815356e-05  -6.40389335e-08]
13 = [  1.78938677e-01   4.88891125e-03   3.06789442e-29   3.62255049e-30
  -2.93766069e-59   2.19659387e-31   2.44016147e-59]
14 = [  1.68247463e-01   5.29431001e-04   2.95389356e-30   2.78871078e-30
   7.04940966e-60   5.37719928e-32  -3.79058412e-60]
15 = [  2.04941906e-01   1.66523218e-02   6.86356103e-28   6.28955975e-28
   4.13224848e-55   7.93111328e-29  -3.83391967e-57]
16 = [ 0.16825966  0.00053353  0.          0.          0.          0.          0.        ]

Problem 2

Write a function that detects corners on an image using the Harris corner detection method. You can use the OpenCV built-in functions. Your function should output the $N$ detected corner locations in a $2 \times N$ matrix. Visualize your results by plotting the corners on top of the input image. Apply your function to the binary image shapes.png and to the grayscale image face.tif.

Análisis

Primeramente cargamos las dos imágenes de interés. Luego creamos la función cornerDetection que recive como argumento una imagen. Guardamos los corners que hayamos por la función cv2.goodFeaturesToTrack en una variable y luego iteramos sobre estos para hayar las posiciones x,y donde los mostraremos en forma de círculo en la imagen a través de .ravel. Finalmente mostramos la imagen resultante.


In [19]:
img = rg(files[-11])
img_2 = rg(files[18])

def cornerDetection(img):
    corners = cv2.goodFeaturesToTrack(img,100,0.01,10)
    corners = np.int0(corners)

    for k in corners:
        x,y = k.ravel()
        cv2.circle(img, (x,y), 3, 255, -1)
        print x,y

    mplt.figure()
    mplt.imshow(cv2.cvtColor(img, cv2.COLOR_GRAY2BGR))
    
cornerDetection(img)
cornerDetection(img_2)


989 206
880 211
378 338
836 351
693 351
944 321
888 321
944 265
888 265
390 265
331 265
637 256
596 256
836 246
693 246
637 222
596 222
390 211
331 211
157 98
87 98
555 96
879 81
817 81
157 37
87 37
879 27
817 27
332 391
601 90
928 117
449 404
1036 331
555 46
207 158
923 406
1014 393
581 190
394 100
307 56
216 56
307 45
216 45
75 171
55 171
75 130
55 130
933 405
949 403
437 403
427 402
965 401
409 400
980 399
399 399
996 397
381 397
371 396
361 395
344 393
590 358
457 358
180 354
168 354
191 353
157 353
147 351
203 350
137 348
223 342
124 342
590 281
457 281
912 210
934 209
957 208
979 207
225 201
122 201
210 194
137 194
200 191
148 191
568 189
190 189
556 188
180 188
168 188
544 187
532 186
520 185
508 184
496 183
484 182
472 181
460 180
448 179
557 178
436 178
424 177
63 79
136 78
17 48
59 7
134 11
69 1
59 67
67 93
102 178
147 5
52 51
47 29
50 15
13 32
77 81
1 72
5 51
113 90
97 153
109 146
46 81
4 39
101 163
57 23
134 226
133 95
36 19
172 287
113 166
77 93
106 213
26 5
138 68
169 19
38 9
152 20
55 93
70 68
37 31
88 144
9 83
85 179
7 22
164 111
56 173
6 11
123 90
165 153
26 19
189 155
189 8
174 298
114 137
258 250
87 71
56 34
28 83
70 211
179 16
187 171
155 183
177 113
35 201
245 234
3 1
128 71
14 243
45 1
29 58
169 62
45 67
10 65
210 87
251 287
47 40
95 26
142 56
34 43
62 54
184 294
96 212
26 133
32 245
16 254
177 26
177 79
4 170
82 213
29 215
121 179
86 190
171 186
155 211
106 23
5 141
164 4
29 69
298 107
28 255
148 237

Problem 3

A company that bottles a variety of industrial chemicals has heard of your success solving imaging problems and hires you to design an approach for detecting when bottles are not full. The bottles appear as shown below as they move along a conveyor line past an automatic filling and capping station. A bottle is considered imperfectly filled when the level of the liquid is below the midway point between the bottom of the neck and the shoulder of the bottle.The shoulder is defined as the region of the bottle where the sides and slanted portion of the bottle intersect. The bottles are moving, but the company has an imaging system equipped with an illumination flash front end that effectively stops motion, so you will be given images that look very close to the sample shown below.

Propose a solution for detecting bottles that are not filled properly. State clearly all assumptions that you make and that are likely to impact the solution you propose. Implement your solution and apply it to the images bottles.tif, new_bottles.jpg and three_bottles.jpg. Visualize the results of your algorithm by highlighting with false colors the regions that are detected as correctly filled bottles and the regions that are detected as not properly filled bottles.

Comentario

La idea es encontrar las botellas que no están llenas apropiadamente. No se requirió de comandos demasiado complejos de OpenCV, de hecho ninguno además de threshold, filter2D y erode. La idea se puede resumir como sigue:

  • Encontrar el ancho promedio de las botellas, este ancho promedio es aproximadamente el mínimo valor posible de líquido en una botella correcta,
  • Encontrar la altura en la imagen en la que ocurre por primera vez el ancho promedio (este va a ser el nivel límite de líquido)
  • Encontrar la cantidad de botellas de la imagen,
  • Encontrar los centros de estas botellas,
  • Al nivel mínimo verificar qué botella tiene aire todavía e indexarla.

Para empezar se suaviza la imagen con un filtro2D y se umbraliza la misma para separar las botellas del fondo; este valor se almacena. Luego la idea es encontrar el número de botellas que hay y su ancho; para esto creamos una regla (un vector de ceros) que sumamos con cada fila de la imagen. Lo resultante de la operación es un vector con intervalos de ceros y unos (unos son regiones de las botellas), se miden las regiones de unos y el número de las mismas; la moda del número de regiones es el número de botellas que hay, la media de máximo de cada medición es el ancho de las botellas. Debido a que este ancho hallado es ciertamente menor que el ancho real, sirve como el ancho de la botella en el que ocurre la altura de líquido mínima. Cabe notar que en la medición de las regiones hecha anteriormente se calcularon los centros de las botellas (centros de cada región) y se estimó la altura mínima del líquido a través del ancho promedio.

Luego de esto se umbralizó la imagen inicial con el fin de obtener las regiones de aire únicamente (fue necesario hacer erosión para remover elementos pequeños). Esta imagen se evaluó en la fila de altura de agua mínima y se extrajeron las regiones de aire a esta altura; el centro de estas regiones se contrasto con el centro de las botellas para saber a qué botella pertenecían y de esta forma identificarlas.


In [121]:
# Images to test
MIN_DIST = 30
LEVEL_OFFSET_INV = 10
LEVEL_OFFSET = 90
imgs = [files[i] for i in [5, -3, -20]]

# Bad bottle detector
def badBottleDetector(img):
    h, w = img.shape
    
    # Smooth
    kernel = np.ones((3,3),np.float32)/9
    simg = cv2.filter2D(img, -1, kernel)
    simg_c = simg.copy()
    
    _, simg_ct = cv2.threshold(simg_c, np.mean(simg_c)+LEVEL_OFFSET, 1, cv2.THRESH_BINARY)
    _, simg_cn = cv2.threshold(simg_c, LEVEL_OFFSET_INV, 1, cv2.THRESH_BINARY)
    kernel = np.ones((5,5), np.uint8)
    simg_ct = cv2.erode(simg_ct, kernel, iterations=1)
    
    bottles = list()
    sizes = list()
    indices = list()
    centers = list()
    for i in range(h):
        ruler = np.zeros([1, w]) + simg_cn[i: i+1]
        ruler = ruler[0]
        
        seed = 0
        break_points = list()
        for j in range(len(ruler)):
            if (ruler[j] != seed) or (j == len(ruler)-1 and ruler[j] == 1):
                break_points.append(j)
                seed = int(not seed)
        
        dist = list()
        center = list()
        for j in range(0, len(break_points)-1, 2):
            if break_points[j+1] - break_points[j] > MIN_DIST:
                dist.append(break_points[j+1] - break_points[j])
                center.append(int((break_points[j+1] + break_points[j])/2))
                
        if dist:
            bottles.append(len(dist))
            sizes.append(np.max(dist))
            indices.append(i)
            centers.append(center)
        
    counts = np.bincount(bottles)
    num_bottles = np.argmax(counts)
    base_size = int(np.mean(sizes))
    centers = [c for c in centers if len(c) == num_bottles]
    
    center = list()
    for i in range(num_bottles):
        bt = [c[i] for c in centers]
        center.append(int(np.mean(bt)))
    
    index = 0
    for i in range(len(sizes)):
        if sizes[i] > base_size:
            index = i
            break
    liquid_min_limit = indices[index]
    
    # Check which bottle has air at index liquid_min_limit
    ruler = np.zeros([1, w]) + simg_ct[liquid_min_limit: liquid_min_limit+1]
    ruler = ruler[0]
        
    seed = 0
    break_points = list()
    for j in range(len(ruler)):
        if (ruler[j] != seed) or (j == len(ruler)-1 and ruler[j] == 1):
            break_points.append(j)
            seed = int(not seed)
        
    dist = list()
    centers = list()
    for j in range(0, len(break_points)-1, 2):
        if break_points[j+1] - break_points[j] > MIN_DIST:
            dist.append(break_points[j+1] - break_points[j])
            centers.append(int((break_points[j+1] + break_points[j])/2))
                
    final = [0]*len(center)
    for c in centers:
        ct = [np.abs(cc - c) for cc in center]
        final[np.argmin(ct)] = 1
        
    print('Final decision. Bottles not correct are marked with 1s: ')
    print(final)
            
    printer([img, simg_cn, simg_ct], ['Original image', 'inv', 'liquid'])
    
def printer(iss, des):
    # Printing
    f, ax = mplt.subplots(1, len(iss), figsize=(10,10))
    
    for i in range(len(iss)):
        ax[i].imshow(iss[i], cmap='gray')
        ax[i].set_title(des[i])


for i in imgs:
    badBottleDetector(rg(i))


Final decision. Bottles not correct are marked with 1s: 
[0, 0, 1, 0, 0]
Final decision. Bottles not correct are marked with 1s: 
[0, 1, 1, 1, 0]
Final decision. Bottles not correct are marked with 1s: 
[0, 1, 0, 0, 0]

Problem 4

Suppose that you are observing objects in the night sky. Suppose that only ‘big’ objects are important to your observation. In this scenario, ‘small’ objects are considered noise. Write a python function that processes the image as follows:

  1. Use a 15x15 averaging filter to blur the image.

  2. Apply a threshold of 0.25 to binarize the resulting blurred image.

  3. Use the binary image to ‘mask’ the noise of the original image: simply perform an element-wise multiplication of the binary image and the original image.

  4. Use connected component analysis on the binary image to count the number of ‘big’ objects found.

The function should take three inputs: an image matrix, the size of the averaging filter and threshold value. Make sure your function displays the intermediary results of each step outlined above.

Apply your function to the input image ‘hubble-original.tif’. Try different values of smoothing kernel size and threshold value. Analyze the relationship between number of objects found and smoothing kernel size and threshold value. In particular, you might want to observe the result when using an averaging filter of size n=1 (i.e. no smoothing).

Comentarios

La idea del programa siguiente es encontrar cuerpos grandes en las imágenes; para ello se realizan los procedimientos anteriormente pedidos, esto es el filtro 15x15, la aplicación de la umbralización para crear la máscara, la eliminación de ruido de la imagen original y el análisis de cuerpo conexo. Estos pasos son sencillos de realizar y ya se han implementado anteriormente, a excepción del análisis de cuerpo conexo. Para comprobar conexión en un cuerpo, se elige un punto de semilla (aquel punto con intensidad de 1), a partir de este punto se analizan los vecinos de forma recursiva, esto es, se vuelve a llamar la función sobre los vecinos si estos tienen intensidad de 1. Esto arroja la cantidad de cuerpos conexos en la imagen, sin embargo, no hay garantía que estos cuerpos sean grandes. Para asegurar lo anterior se cuentan también el número de miembros de cada cuerpo, si este exede cierto umbral establecido, se cuenta como cuerpo grande.


In [174]:
img_origin = rg('hubble-original.tif')

BIG_OBJECT_COUNT = 80

def printer(iss, des):
    # Printing
    f, ax = mplt.subplots(1, len(iss), figsize=(15,15))
    
    for i in range(len(iss)):
        ax[i].imshow(iss[i], cmap='gray')
        ax[i].set_title(des[i])
        
def connectedLabeling(mat, i, j, h, w):
    mat[i][j] = 0
    if i+1 < h and mat[i+1][j] == 1:
        return 1 + connectedLabeling(mat, i+1, j, h, w)
    elif i-1 > -1 and mat[i-1][j] == 1:
        return 1 + connectedLabeling(mat, i-1, j, h, w)
    elif j+1 < w and mat[i][j+1] == 1:
        return 1 + connectedLabeling(mat, i, j+1, h, w)
    elif j-1 > -1 and mat[i][j-1] == 1:
        return 1 + connectedLabeling(mat, i, j-1, h, w)
    elif i-1 > -1 and j-1 > -1 and mat[i-1][j-1] == 1:
        return 1 + connectedLabeling(mat, i-1, j-1, h, w)
    elif i-1 > -1 and j+1 < w and mat[i-1][j+1] == 1:
        return 1 + connectedLabeling(mat, i-1, j+1, h, w)
    elif i+1 < h and j-1 > -1 and mat[i+1][j-1] == 1:
        return 1 + connectedLabeling(mat, i+1, j-1, h, w)
    elif i+1 < h and j+1 < w and mat[i+1][j+1] == 1:
        return 1 + connectedLabeling(mat, i+1, j+1, h, w)
    else:
        return 1

def countObjects(img, avg_size, th):
    kernel = np.ones((avg_size,avg_size),np.float32)/(avg_size*avg_size)
    fimg = cv2.filter2D(img, -1, kernel)
    _, timg = cv2.threshold(fimg, 255*th, 1, cv2.THRESH_BINARY)

    masked = img * timg

    # Count the objects in the masked image
    timgc = timg.copy()

    h, w = maskc.shape
    for i in range(h):
        for j in range(w):
            if timgc[i][j] == 1:
                neighbors = connectedLabeling(timgc, i, j, h, w)

                if neighbors > BIG_OBJECT_COUNT:
                    # print(neighbors)
                    timgc[i][j] = 1

    count = np.sum(timgc)
    print('Objetos grandes encontrados: ' + str(count))
    print('Se definió objeto grande aquel cuyo conjunto conexo tiene más de ' + str(BIG_OBJECT_COUNT) + ' miembros')
    print('Este parámetro se puede variar')

    printer([img, timg, timgc, maskc], ['Original', 'Threshold', 'Counting', 'Masked'])
    
sizes = [1, 5, 15, 25]
ths = [0.5, 0.5, 0.25, 0.3]
for i in range(len(sizes)):
    countObjects(img_origin, sizes[i], ths[i])


Objetos grandes encontrados: 9
Se definió objeto grande aquel cuyo conjunto conexo tiene más de 80 miembros
Este parámetro se puede variar
Objetos grandes encontrados: 7
Se definió objeto grande aquel cuyo conjunto conexo tiene más de 80 miembros
Este parámetro se puede variar
Objetos grandes encontrados: 33
Se definió objeto grande aquel cuyo conjunto conexo tiene más de 80 miembros
Este parámetro se puede variar
Objetos grandes encontrados: 6
Se definió objeto grande aquel cuyo conjunto conexo tiene más de 80 miembros
Este parámetro se puede variar

Problem 5

Write a function that extracts local interest points and computes their descriptors using the SIFT transform. You can find implementations of the SIFT transform in OpenCV.

Your function should return two matrices: A first matrix of size $3 \times N$, where $N$ is the number of detected points in the image, and the 3 elements correspond to the $x$, $y$ locations and $s$ size of the detected points. A second matrix of size $128 \times N$ that contains the SIFT descriptor of each interest point.

Apply your function to all car images image_00XX.jpg. Store the results of each image in a separate data file.

Comentarios

La Siguiente función hace uso de la implementación de la transformada de SIFT que tiene OpenCV. La función utilizada fue detectAndCompute. La función que se creó, recibe la array de una imagen en escala de grises y regresa los puntos (x,y) y la escala de la imagen en la que fueron encontrados como una matriz de numpy 3xN y también los respectivos descriptores de SIFT para cada punto en otra matriz. También se puede pasar como segundo parametro a la función un booleano que determina si se imprime o no la imagen con los puntos sobre ella, en el caso por defecto, que es False, no imprime nada. Los datos se guardan en archivos de texto en formato json.


In [2]:
def getPointsAndDescriptors(img,show_img = False):
    
    # Getting Keypoint structure object and Descriptor Array
    sift = cv2.SIFT()
    kp, D = sift.detectAndCompute(img,None)
    
    # Getting the array of points (x,y,s)
    points = np.zeros((3,len(kp)))
    for i in range(len(kp)):
        points[0][i] = kp[i].pt[0]
        points[1][i] = kp[i].pt[1]
        points[2][i] = kp[i].size
        
    if show_img == True:
        img_s = cv2.drawKeypoints(img, kp, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
        mplt.imshow(img_s), mplt.xticks([]), mplt.yticks([]), mplt.figure()
    
    return points, D
    
# 25 -45 ind of cars images
for i in range(25,45):
    img_name = files[i]
    img = rg(img_name)
    points, D = getPointsAndDescriptors(img)
    f = open("data_image_"+str(i-24)+".json","w")
    data = {"points":points.tolist(),"Descriptors": D.tolist()}
    json.dump(data,f, sort_keys=True, indent=4)
    f.close()
    print "Points and SIFT descriptors for image "+str(i-24)+" extracted"
    
print "Done!"


Points and SIFT descriptors for image 1 extracted
Points and SIFT descriptors for image 2 extracted
Points and SIFT descriptors for image 3 extracted
Points and SIFT descriptors for image 4 extracted
Points and SIFT descriptors for image 5 extracted
Points and SIFT descriptors for image 6 extracted
Points and SIFT descriptors for image 7 extracted
Points and SIFT descriptors for image 8 extracted
Points and SIFT descriptors for image 9 extracted
Points and SIFT descriptors for image 10 extracted
Points and SIFT descriptors for image 11 extracted
Points and SIFT descriptors for image 12 extracted
Points and SIFT descriptors for image 13 extracted
Points and SIFT descriptors for image 14 extracted
Points and SIFT descriptors for image 15 extracted
Points and SIFT descriptors for image 16 extracted
Points and SIFT descriptors for image 17 extracted
Points and SIFT descriptors for image 18 extracted
Points and SIFT descriptors for image 19 extracted
Points and SIFT descriptors for image 20 extracted
Done!

In [ ]: