<gh_stars>1-10
#import caffe
import numpy as np
import  skimage.filters as filters
#import shapefeatures
#from skimage.feature import peak_local_max
#from skimage.feature import corner_peaks
#from skimage.morphology import watershed
#import skimage.measure as measure
#import skimage.segmentation as segmentation
#import scipy.ndimage as ndimage
#import sklearn
#import sklearn.ensemble
from scipy import misc


def detect(imfile, clf, opts):
    step = opts['detection_step']
    downsample = opts['image_downsample']
    size = opts['patch_size'][0]

    p = predict(clf, imfile, step, size, downsample)

    boxes = get_boxes(imfile, p, step, size, gauss=opts['gauss'], threshold=opts['detection_probability_threshold'] )

    found = non_maximum_suppression(boxes, overlapThresh=opts['detection_overlap_threshold'])
    return found

def predict(classifier, img_filename, step, size, downsample=1):
    img = misc.imread(img_filename)
    height, width,channels = img.shape

    probs = np.zeros((img.shape[0]*1.0/step,img.shape[1]*1.0/step))
    patches = []

    y=0
    while y+(size) < height:
                #rows
                x = 0
                predictions=[]
                while (x+(size) < width):
                    left = x
                    right = x+(size)
                    top = y
                    bottom = y+(size)
                    patches.append(img[top:bottom:downsample, left:right:downsample,:])
                    x += step
                y += step

    p = np.array(patches)
    p = np.swapaxes(p,1,3)
    p = np.swapaxes(p,2,3)
    predictions = classifier.predict_proba(p)
    
    i=0
    y=0
    while y+(size) < height:
                x = 0
                while (x+(size) < width):
                    left = x
                    right = x+(size)
                    top = y
                    bottom = y+(size)
                    probs[y/step,x/step]=predictions[i,1]
                    i+=1
                    x += step
                y += step

    return probs


def get_boxes(img_filename, probs, step, size, gauss=0,threshold=0.5):

    if gauss != 0:
        probs = filters.gaussian_filter(probs, gauss)
        
    img = misc.imread(img_filename)
    height, width,channels = img.shape

    boxes=[]

    i=0
    y=0
    while y+(size) < height:
                x = 0
                while (x+(size) < width):
                    left = int(x)
                    right = int(x+(size))
                    top = int(y)
                    bottom = int(y+(size))
                    if probs[y/step,x/step] > threshold:
                        boxes.append([left,top,right,bottom,probs[y/step,x/step]])
                    i+=1
                    x += step
                y += step

    if len(boxes) == 0:
        return np.array([])

    boxes =  np.vstack(boxes)
    return boxes


# Malisiewicz et al.
# Python port by <NAME>
def non_maximum_suppression(boxes, overlapThresh=0.5):
  # if there are no boxes, return an empty list
  if len(boxes) == 0:
    return []

  # if the bounding boxes integers, convert them to floats --
  # this is important since we'll be doing a bunch of divisions
  if boxes.dtype.kind == "i":
    boxes = boxes.astype("float")

  # initialize the list of picked indexes 
  pick = []

  # grab the coordinates of the bounding boxes
  x1 = boxes[:,0]
  y1 = boxes[:,1]
  x2 = boxes[:,2]
  y2 = boxes[:,3]
  scores = boxes[:,4]
  # compute the area of the bounding boxes and sort the bounding
  # boxes by the score/probability of the bounding box
  area = (x2 - x1 + 1) * (y2 - y1 + 1)
  idxs = np.argsort(scores)[::-1]

  # keep looping while some indexes still remain in the indexes
  # list
  while len(idxs) > 0:
    # grab the last index in the indexes list and add the
    # index value to the list of picked indexes
    last = len(idxs) - 1
    i = idxs[last]
    pick.append(i)

    # find the largest (x, y) coordinates for the start of
    # the bounding box and the smallest (x, y) coordinates
    # for the end of the bounding box
    xx1 = np.maximum(x1[i], x1[idxs[:last]])
    yy1 = np.maximum(y1[i], y1[idxs[:last]])
    xx2 = np.minimum(x2[i], x2[idxs[:last]])
    yy2 = np.minimum(y2[i], y2[idxs[:last]])

    # compute the width and height of the bounding box
    w = np.maximum(0, xx2 - xx1 + 1)
    h = np.maximum(0, yy2 - yy1 + 1)

    # compute the ratio of overlap
    overlap = (w * h) / area[idxs[:last]]

    # delete all indexes from the index list that have
    idxs = np.delete(idxs, np.concatenate(([last],
      np.where(overlap > overlapThresh)[0])))

  # return only the bounding boxes that were picked using the
  # integer data type
  return boxes[pick].astype("int")

'''
def nms_felz(boxes, step, size, lim=0, prob=MAX, pos=MAX, overlapThresh = 0.5, probs=None, probs_area = 90):

    probs_area = int(probs_area / step)

    # if there are no boxes, return an empty list
    if len(boxes) == 0:
        return np.array([])

    # initialize the list of picked indexes
    pick = []

    # grab the coordinates of the bounding boxes
    x1 = boxes[:,0]
    y1 = boxes[:,1]
    x2 = boxes[:,2]
    y2 = boxes[:,3]
    p  = boxes[:,4]

    # compute the area of the bounding boxes and sort the bounding
    # boxes by the bottom-right y-coordinate of the bounding box
    area = (x2 - x1 + 1) * (y2 - y1 + 1)
    idxs = np.argsort(p)
    # keep looping while some indexes still remain in the indexes
    # list
    while len(idxs) > 0:
        # grab the last index in the indexes list, add the index
        # value to the list of picked indexes, then initialize
        # the suppression list (i.e. indexes that will be deleted)
        # using the last index
        last = len(idxs) - 1
        i = idxs[last]
        suppress = [last]

        merged_probs = [p[i]]
        merged_c = []
        merged_c.append( ( (x1[i] + x2[i])/2.0, (y1[i] + y2[i])/2.0 ) )

        for pos in xrange(0, last):
            # grab the current index
            j = idxs[pos]

            # find the largest (x, y) coordinates for the start of
            # the bounding box and the smallest (x, y) coordinates
            # for the end of the bounding box
            xx1 = max(x1[i], x1[j])
            yy1 = max(y1[i], y1[j])
            xx2 = min(x2[i], x2[j])
            yy2 = min(y2[i], y2[j])

            # compute the width and height of the bounding box
            w = max(0, xx2 - xx1 + 1)
            h = max(0, yy2 - yy1 + 1)

            # compute the ratio of overlap between the computed
            # bounding box and the bounding box in the area list
            overlap = float(w * h) / area[j]

            # if there is sufficient overlap, suppress the
            # current bounding box
            if overlap > overlapThresh:
                suppress.append(pos)


                merged_probs.append(p[j])

                merged_c.append( ( (x1[j] + x2[j])/2.0, (y1[j] + y2[j])/2.0 ) )

        if len(merged_probs) >= lim:

            if pos==MEAN:
                    tot_prob = sum(merged_probs)
                    box_center_x = sum(  [  merged_c[i][0] * merged_probs[i]/tot_prob for i in xrange(len(merged_probs))])
                    box_center_y = sum(  [  merged_c[i][1] * merged_probs[i]/tot_prob for i in xrange(len(merged_probs))])
            else:
                box_center_x = (x1[i]+x2[i] ) /2
                box_center_y = (y1[i]+y2[i] ) /2

            pr = 0
            if prob == MEAN:
                pr = sum(merged_probs)
                pr *= (1.0/(len(merged_probs)))
            elif prob == AREA:
                pr = probs[box_center_y - probs_area/2 : box_center_y + probs_area/2,  box_center_x - probs_area/2 : box_center_x + probs_area/2 ].mean()
            elif prob == NUM:
                pr = sum(merged_probs)
            else:
                pr = p[i]

            pick.append([ box_center_x-size/2, box_center_y-size/2, box_center_x+size/2, box_center_y+size/2, pr])

        idxs = np.delete(idxs, suppress)
    if len(pick)== 0:
        return np.array([])
    # return only the bounding boxes that were picked
    return np.vstack(pick)
'''
