     // Create dst bitmap image (empty for now)
     Bitmap* dst_bitmap = createBitmap(src_bitmap->width, src_bitmap->height, src_bitmap->depth);
 
+    // Dimensions of computing elements on the CUDA device.
+    // Computing the grid dimensions depends on PAD_TOP and PAD_LEFT.
+    unsigned int block_dim_x = THREADS_PER_BLOCK_X;
+    unsigned int block_dim_y = THREADS_PER_BLOCK_Y;
+    unsigned int grid_dim_x = (unsigned int) ceil((src_bitmap->width + PAD_LEFT + PAD_RIGHT_MIN) / ((double) block_dim_x));
+    unsigned int grid_dim_y = (unsigned int) ceil((src_bitmap->height + PAD_TOP + PAD_BOTTOM_MIN)/ ((double) block_dim_y));
+    dim3 block_dim(block_dim_x, block_dim_y);
+    dim3 grid_dim(grid_dim_x, grid_dim_y);
+
     // Pad the binary images with pixels on each side. This will be useful when
     // implementing the skeletonization algorithm, because the mask we use
     // depends on P2 and P4, which also have their own window.
     Padding padding_amounts;
     padding_amounts.top = PAD_TOP;
+    padding_amounts.bottom = (grid_dim_y * block_dim_y) - (src_bitmap->height + PAD_TOP);
     padding_amounts.left = PAD_LEFT;
-
-    // Dimensions of computing elements on the CUDA device.
-    // Computing the grid dimensions depends on PAD_TOP and PAD_LEFT.
-    unsigned int block_dim_x = THREADS_PER_BLOCK_X;
-    unsigned int block_dim_y = THREADS_PER_BLOCK_Y;
-    unsigned int grid_dim_x = (unsigned int) ceil((src_bitmap->width + padding_amounts.left) / ((double) block_dim_x));
-    unsigned int grid_dim_y = (unsigned int) ceil((src_bitmap->height + padding_amounts.top)/ ((double) block_dim_y));
-    dim3 block_dim(block_dim_x, block_dim_y);
-    dim3 grid_dim(grid_dim_x, grid_dim_y);
-
-    // Can now calculate padding for the right and bottom parts of the image,
-    // since we have the grid dimensions.
-    padding_amounts.right = ((unsigned int) ceil((src_bitmap->width + padding_amounts.left) / ((double) grid_dim_x))) - (src_bitmap->width + padding_amounts.left);
-    padding_amounts.bottom = ((unsigned int) ceil((src_bitmap->height + padding_amounts.top) / ((double) grid_dim_y))) - (src_bitmap->height + padding_amounts.top);
+    padding_amounts.right = (grid_dim_x * block_dim_x) - (src_bitmap->width + PAD_LEFT);
     pad_binary_bitmap(&src_bitmap, BINARY_WHITE, padding_amounts);
     pad_binary_bitmap(&dst_bitmap, BINARY_WHITE, padding_amounts);
 


    // iterative thinning algorithm
    unsigned int iterations = 0;
    do {
        skeletonize_pass<<<grid_dim, block_dim>>>(src_bitmap->data, dst_bitmap->data, src_bitmap->width, src_bitmap->height, padding_amounts);
        swap_bitmaps(&src_bitmap, &dst_bitmap);

        iterations++;
        printf(".");
        fflush(stdout);
    } while (!are_identical_bitmaps(src_bitmap, dst_bitmap));

    // Remove extra padding that was added to the images (don't care about
    // src_bitmap, so only need to unpad dst_bitmap)
    unpad_bitmap(&dst_bitmap, padding_amounts);

    // save 8-bit binary-valued grayscale version of dst_bitmap to dst_fname
    binary_to_grayscale(dst_bitmap);


#define PAD_TOP 2
#define PAD_LEFT 2
#define PAD_BOTTOM_MIN 1
#define PAD_RIGHT_MIN 1

#define P2(data, row, col, width) ((data)[((row)-1) * width +  (col)   ])
#define P3(data, row, col, width) ((data)[((row)-1) * width + ((col)-1)])
