Skip to content

Instantly share code, notes, and snippets.

@noio
Created March 6, 2015 20:00
Show Gist options
  • Select an option

  • Save noio/8c76cf72a74bcd343ff8 to your computer and use it in GitHub Desktop.

Select an option

Save noio/8c76cf72a74bcd343ff8 to your computer and use it in GitHub Desktop.

Revisions

  1. noio created this gist Mar 6, 2015.
    95 changes: 95 additions & 0 deletions gistfile1.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,95 @@
    #!/usr/bin/env python

    import sys, os
    import numpy as np
    from matplotlib import cm
    from scipy import ndimage, misc, spatial

    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'

    filename = sys.argv[1]
    fileroot = os.path.splitext(filename)[0]

    image = misc.imread(filename)

    if len(sys.argv) > 2:
    hx = sys.argv[2]
    channels = [hx[0:2], hx[2:4], hx[4:6], "FF"]
    crack_color = [int(c, 16) for c in channels]
    else:
    crack_color = image[0,0]

    print "Cracks with color: %s" % (crack_color)

    cracks = np.all(image == crack_color, axis=-1)
    transparent = image[:,:,3] == 0

    regions = 1 - np.logical_or(cracks, transparent)

    labels, num_labels = ndimage.label(regions)


    # Structuring element that expands to bottom right
    # when used for dilation
    strel = np.array([[0,0,0],
    [0,1,1],
    [1,1,1]])


    # We're going to assign all the cracks to the closest region
    # in a way so that each crack pixel belongs to exactly one region

    # Create a list of coordinates
    positions = np.indices(labels.shape).transpose([1,2,0])

    # Filter that list by the pixels that belong to a region
    positions = positions[labels > 0]

    # A KDTree is super overkill but it does save on some code here.
    # Feed the KDTree the coordinates of all non-zero label positions
    kdtree = spatial.KDTree(positions)

    # Get positions of crack pixels
    crack_positions = np.transpose(np.nonzero(cracks))

    # Offset the cracks a tiny bit to bias the cracks to stick to
    # the closest pixel on the top-left
    crack_positions_offset = crack_positions.astype(float) + [[-0.1, -0.4]]

    dists, idxs = kdtree.query(crack_positions_offset)

    closest_region_position = positions[idxs]
    closest_region_label = labels[closest_region_position[:,0], closest_region_position[:,1]]

    # Assign the regions to the label matrix
    labels[ crack_positions[:,0], crack_positions[:,1] ] = closest_region_label

    # Save image that are transparent except for the region
    for label in range(1,num_labels+1):
    to_delete = (labels != label)
    isolated = np.copy(image)
    # Set all other pixels to transparent
    isolated[to_delete] = [0,0,0,0]
    # Compute a centroid
    cy, cx = np.average(np.transpose(np.nonzero(labels == label)), axis=0).astype(int)
    cy = round(cy / 4) * 4
    cx = round(cx / 4) * 4
    # Save the image using the centroid as name
    # We do this so that the names of unaffected pieces
    # stay the same if other pieces are merged or split
    savepath = '%s_s%03d_%03d.png' % (fileroot, cx, cy)
    if os.path.exists(savepath):
    status = WARNING + BOLD + "Overwriting" + ENDC
    else:
    status = OKGREEN + "New" + ENDC
    print "[%d/%d] %s %s" % (label, num_labels, status, os.path.basename(savepath))
    misc.imsave(savepath, isolated)

    # Save an image of the generated regions
    colormap = cm.get_cmap("Set3")
    colorlabels = colormap(labels / float(np.max(labels)))
    colorlabels[:,:,-1] = image[:,:,-1] / 255.0
    misc.imsave('%s_labels.png' % (fileroot), colorlabels)