<gh_stars>0
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 13 00:08:24 2018

@author: aman

This script will 
    1)  find the imageData folders which contain fly tracks
    2)  track the fly in the whole image

"""

import cv2
import os
import glob
import numpy as np
import re
import Tkinter as tk
import tkFileDialog as tkd
import random
from datetime import datetime
import time
#import copy
import csv
import sys

import multiprocessing as mp
import itertools


def present_time():
        now = datetime.now()
        return now.strftime('%Y%m%d_%H%M%S')

def natural_sort(l): 
    convert = lambda text: int(text) if text.isdigit() else text.lower() 
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
    return sorted(l, key = alphanum_key)


def getFolder(initialDir):
    '''
    GUI funciton for browsing and selecting the folder
    '''    
    root = tk.Tk()
    initialDir = tkd.askdirectory(parent=root,
                initialdir = initialDir, title='Please select a directory')
    root.destroy()
    return initialDir

def getFiles(dirname, extList):
    filesList = []
    for ext in extList:
        filesList.extend(glob.glob(os.path.join(dirname, ext)))
    return natural_sort(filesList)

def random_color():
    levels = range(32,256,32)
    return tuple(random.choice(levels) for _ in range(3))

def displayImstack(imStack, delay, winName):
    '''
    displays images from a given imagestack with 'delay'milliseconds
    '''
    for _,im in enumerate(imStack):
        cv2.imshow(winName, im)
        cv2.waitKey(delay)
    cv2.destroyAllWindows()


def getTrackColors(imArray):
    '''
    return the colors to be used for displaying the track
    '''
    blue = np.hstack((np.linspace(0, 255, num = len(imArray)/2),np.linspace(255, 0, num = (len(imArray)/2)+1)))
    green = np.linspace(255, 0, num = len(imArray))
    red = np.linspace(0, 255, num = len(imArray))
    return [c for c in zip(blue, green, red)]
   
def getImContours(args):
    '''
    returns the list of detected contour
    input:
        im:  image numpy array to be processed for contour detection
        params: dictionary of all parameters used for contour detection
        params :
            blurkernel
            block
            cutoff
            ellratio
            ellAxisRatioMin
            ellAxisRatioMax
            flyAreaMin
            flyAreaMax
    '''
    im = args[1].copy()
    params = args[2]
    contour = []
    im = cv2.medianBlur(im,params['blurKernel'])
    th = cv2.adaptiveThreshold(im,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,params['block'],params['cutoff'])
<<<<<<< HEAD
    contours, hierarchy = cv2.findContours(th, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
=======
    im2, contours, hierarchy = cv2.findContours(th, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a
    #print len(contours)
    try:
        contours = sorted(contours, key = cv2.contourArea)[-10:]
        ellRatio = [(float(cv2.fitEllipse(cnt)[1][0])/cv2.fitEllipse(cnt)[1][1], cv2.contourArea(cnt), cnt) for cnt in contours ]
        for cnt in ellRatio:
            if params['ellaxisRatioMin']<cnt[0]<params['ellaxisRatioMax'] and params['flyareaMin']<cnt[1]<params['flyareaMax']:
                contour.append([args[0], 
                                cv2.fitEllipse(cnt[2]),
                                cv2.contourArea(cnt[2]),
                                args[3]])
            else:
                pass
    except:
        pass
    if contour==[]:
        #print("no contour detected")
        contour.append([args[0],  [], args[3]])
    return contour

def imRead(fname):
    '''
    '''
    return cv2.imread(fname)

def imReadNCnt(args):
    '''
    input: 
        args[0] = path of the image to be read
        args[1] = parameters using which the image will be processed for contour detection
    output:
        im = array of the image read
        cnt = detected contour from the image "im"

    im = cv2.imread(x[0], cv2.IMREAD_GRAYSCALE)
    cnt = getImContours((im, x[1]))
    return [im, cnt]

    '''
    im = cv2.imread(args[0], cv2.IMREAD_GRAYSCALE)
    cnt = getImContours((args[0], im, args[1], args[2]))
    if cnt==[]:
        return [im]
    else:
        return cnt
    
def getFlycontour(dirname, imExts,
                  contourParams, header,
<<<<<<< HEAD
                  mpPool):
=======
                  workers):
>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a
    '''
    tracks the fly using cv2.SimpleBlobDetector method and saves the tracked flies in folders
    '''
    params = contourParams
    flist = getFiles(dirname, imExts)
    nImsToProcess = len(flist)
    print 'processing %i frames in\n==> %s'%(nImsToProcess, dirname)
<<<<<<< HEAD
    #pool = mp.Pool(processes=workers)
    startTime = time.time()
    poolArgList = itertools.izip(flist, itertools.repeat(params), np.arange(len(flist)))
    imgWithCnt = mpPool.map(imReadNCnt, poolArgList)
    t = time.time()-startTime
    print("imRead and Contours detection time for %d frames: %s Seconds at %5f FPS\n"%(len(imgWithCnt),t ,len(imgWithCnt)/float(t)))
=======
    pool = mp.Pool(processes=workers)
    startTime = time.time()
    poolArgList = itertools.izip(flist, itertools.repeat(params), np.arange(len(flist)))
    imgWithCnt = pool.map(imReadNCnt, poolArgList)
    t = time.time()-startTime
    print("imRead and Contours detection time for %d frames: %s Seconds at %f FPS\n"%(len(imgWithCnt),t ,len(imgWithCnt)/float(t)))
>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a
    contoursList = [header]
    for idx, i in enumerate(imgWithCnt):
        fname = '/'.join( i[0][0].split('/')[-4:])
        if i[0][1] != []:
            coordX = i[0][1][0][0]
            coordY = i[0][1][0][1]
            minorAxis = i[0][1][1][0]
            majorAxis = i[0][1][1][1]
            angle = i[0][1][2]
            area = i[0][2]
            contoursList.append([fname, coordX, coordY, minorAxis, majorAxis, angle, area,])
        else:
            contoursList.append([fname,0,0,0,0,0,0])

    return contoursList


baseDir = '/media/aman/data/flyWalk_data/tmp_climbing/CS1/'
#baseDir = '/media/pointgrey/data/flywalk/climbingData/uploaded/'
#baseDir = getFolder(baseDir)

try:
    baseDir = sys.argv[1]
except:
    baseDir = '/media/pointgrey/data/flywalk/'
    baseDir = getFolder(baseDir)
    pass
os.chdir(baseDir)

imExtensions = ['*.png', '*.jpeg']
imDataFolder = 'imageData'
statsfName = 'contoursStats'
statsFileHeader = ['frameDetails','x-coord','y-coord','minorAxis (px)','majorAxis (px)','angle','area (px)']

<<<<<<< HEAD
nThreads = 7
=======
nThreads = 4
>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a
#nImThresh = 100

params = {} # dict for holding parameter values for contour detection
params['blurKernel'] = 5
params['block'] = 123
params['cutoff'] = 15
params['ellaxisRatioMin'] = 0.2
params['ellaxisRatioMax'] = 0.5
params['flyareaMin'] = 300 
params['flyareaMax'] = 900 


rawdirs = natural_sort([ name for name in os.listdir(baseDir) if os.path.isdir(os.path.join(baseDir, name)) ])
<<<<<<< HEAD
pool = mp.Pool(processes=nThreads)

for idx, rawDir in enumerate(rawdirs):
    dirs = natural_sort([ os.path.join(rawDir, imDataFolder, name) for name in os.listdir(os.path.join(rawDir, imDataFolder)) if os.path.isdir(os.path.join(rawDir, imDataFolder, name)) ])
    csvList = glob.glob(os.path.join(rawDir, imDataFolder, '*.csv'))
    for _,imFolder in enumerate(dirs):
        statsFile = imFolder.rstrip('/')+'_'+statsfName+'_'+rawDir+'.csv'
        if statsFile not in csvList:
            if 'tracked' not in imFolder:
                flyContours = getFlycontour(imFolder, imExtensions, params, statsFileHeader, pool)
                with open(statsFile, "w") as f:
                    writer = csv.writer(f)
                    writer.writerows(flyContours)
                f.close()
        else:
            print('already processed\n==> %s'%imFolder)
        
















=======

for idx, rawDir in enumerate(rawdirs):
    dirs = natural_sort([ os.path.join(rawDir, imDataFolder, name) for name in os.listdir(os.path.join(rawDir, imDataFolder)) if os.path.isdir(os.path.join(rawDir, imDataFolder, name)) ])
    for _,imFolder in enumerate(dirs):
        if 'tracked' not in imFolder:
            flyContours = getFlycontour(imFolder, imExtensions, params, statsFileHeader, nThreads)
            statsFile = imFolder.rstrip('/')+'_'+statsfName+'_'+rawDir+'.csv'
            with open(statsFile, "w") as f:
                writer = csv.writer(f)
                writer.writerows(flyContours)
>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a




<<<<<<< HEAD
'''
dirname = '/media/aman/data/flyWalk_data/'

dirname = '/media/aman/data/flyWalk_data/tmp_climbing/CS1/tmp_20171201_195931_CS_20171128_0245_11-Climbing_male/imageData/20171201_195953/'
imExt = '.png'

#dirname = getFolder(dirname)

params = {} # dict for holding parameter values for contour detection
params['blurKernel'] = 5
params['block'] = 123
params['cutoff'] = 15
params['ellaxisRatioMin'] = 0.2
params['ellaxisRatioMax'] = 0.5
params['flyareaMin'] = 300 
params['flyareaMax'] = 900 

nImThresh = 100
statsfName = 'contoursStats'

nThreads = 4
csvFileHeader = ['frameDetails','x-coord','y-coord','minorAxis (px)','majorAxis (px)','angle','area (px)']
flyContours = getFlycontour(dirname, imExt, params, statsFileHeader, nThreads)

statsFile = dirname.rstrip('/')+'_'+statsfName+'.csv'
with open(statsFile, "w") as f:
    writer = csv.writer(f)
    writer.writerows(flyContours)


'''
=======

>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a

























#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 13 00:08:24 2018

@author: aman

This script will 
    1)  find the imageData folders which contain fly tracks
    2)  track the fly in the whole image

"""

import cv2
import os
import glob
import numpy as np
import re
import Tkinter as tk
import tkFileDialog as tkd
import random
from datetime import datetime
import time
#import copy
import csv
import sys

import multiprocessing as mp
import itertools


def present_time():
        now = datetime.now()
        return now.strftime('%Y%m%d_%H%M%S')

def natural_sort(l): 
    convert = lambda text: int(text) if text.isdigit() else text.lower() 
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
    return sorted(l, key = alphanum_key)


def getFolder(initialDir):
    '''
    GUI funciton for browsing and selecting the folder
    '''    
    root = tk.Tk()
    initialDir = tkd.askdirectory(parent=root,
                initialdir = initialDir, title='Please select a directory')
    root.destroy()
    return initialDir

def getFiles(dirname, extList):
    filesList = []
    for ext in extList:
        filesList.extend(glob.glob(os.path.join(dirname, ext)))
    return natural_sort(filesList)

def random_color():
    levels = range(32,256,32)
    return tuple(random.choice(levels) for _ in range(3))

def displayImstack(imStack, delay, winName):
    '''
    displays images from a given imagestack with 'delay'milliseconds
    '''
    for _,im in enumerate(imStack):
        cv2.imshow(winName, im)
        cv2.waitKey(delay)
    cv2.destroyAllWindows()


def getTrackColors(imArray):
    '''
    return the colors to be used for displaying the track
    '''
    blue = np.hstack((np.linspace(0, 255, num = len(imArray)/2),np.linspace(255, 0, num = (len(imArray)/2)+1)))
    green = np.linspace(255, 0, num = len(imArray))
    red = np.linspace(0, 255, num = len(imArray))
    return [c for c in zip(blue, green, red)]
   
def getImContours(args):
    '''
    returns the list of detected contour
    input:
        im:  image numpy array to be processed for contour detection
        params: dictionary of all parameters used for contour detection
        params :
            blurkernel
            block
            cutoff
            ellratio
            ellAxisRatioMin
            ellAxisRatioMax
            flyAreaMin
            flyAreaMax
    '''
    im = args[1].copy()
    params = args[2]
    contour = []
    im = cv2.medianBlur(im,params['blurKernel'])
    th = cv2.adaptiveThreshold(im,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,params['block'],params['cutoff'])
<<<<<<< HEAD
    contours, hierarchy = cv2.findContours(th, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
=======
    im2, contours, hierarchy = cv2.findContours(th, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a
    #print len(contours)
    try:
        contours = sorted(contours, key = cv2.contourArea)[-10:]
        ellRatio = [(float(cv2.fitEllipse(cnt)[1][0])/cv2.fitEllipse(cnt)[1][1], cv2.contourArea(cnt), cnt) for cnt in contours ]
        for cnt in ellRatio:
            if params['ellaxisRatioMin']<cnt[0]<params['ellaxisRatioMax'] and params['flyareaMin']<cnt[1]<params['flyareaMax']:
                contour.append([args[0], 
                                cv2.fitEllipse(cnt[2]),
                                cv2.contourArea(cnt[2]),
                                args[3]])
            else:
                pass
    except:
        pass
    if contour==[]:
        #print("no contour detected")
        contour.append([args[0],  [], args[3]])
    return contour

def imRead(fname):
    '''
    '''
    return cv2.imread(fname)

def imReadNCnt(args):
    '''
    input: 
        args[0] = path of the image to be read
        args[1] = parameters using which the image will be processed for contour detection
    output:
        im = array of the image read
        cnt = detected contour from the image "im"

    im = cv2.imread(x[0], cv2.IMREAD_GRAYSCALE)
    cnt = getImContours((im, x[1]))
    return [im, cnt]

    '''
    im = cv2.imread(args[0], cv2.IMREAD_GRAYSCALE)
    cnt = getImContours((args[0], im, args[1], args[2]))
    if cnt==[]:
        return [im]
    else:
        return cnt
    
def getFlycontour(dirname, imExts,
                  contourParams, header,
<<<<<<< HEAD
                  mpPool):
=======
                  workers):
>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a
    '''
    tracks the fly using cv2.SimpleBlobDetector method and saves the tracked flies in folders
    '''
    params = contourParams
    flist = getFiles(dirname, imExts)
    nImsToProcess = len(flist)
    print 'processing %i frames in\n==> %s'%(nImsToProcess, dirname)
<<<<<<< HEAD
    #pool = mp.Pool(processes=workers)
    startTime = time.time()
    poolArgList = itertools.izip(flist, itertools.repeat(params), np.arange(len(flist)))
    imgWithCnt = mpPool.map(imReadNCnt, poolArgList)
    t = time.time()-startTime
    print("imRead and Contours detection time for %d frames: %s Seconds at %5f FPS\n"%(len(imgWithCnt),t ,len(imgWithCnt)/float(t)))
=======
    pool = mp.Pool(processes=workers)
    startTime = time.time()
    poolArgList = itertools.izip(flist, itertools.repeat(params), np.arange(len(flist)))
    imgWithCnt = pool.map(imReadNCnt, poolArgList)
    t = time.time()-startTime
    print("imRead and Contours detection time for %d frames: %s Seconds at %f FPS\n"%(len(imgWithCnt),t ,len(imgWithCnt)/float(t)))
>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a
    contoursList = [header]
    for idx, i in enumerate(imgWithCnt):
        fname = '/'.join( i[0][0].split('/')[-4:])
        if i[0][1] != []:
            coordX = i[0][1][0][0]
            coordY = i[0][1][0][1]
            minorAxis = i[0][1][1][0]
            majorAxis = i[0][1][1][1]
            angle = i[0][1][2]
            area = i[0][2]
            contoursList.append([fname, coordX, coordY, minorAxis, majorAxis, angle, area,])
        else:
            contoursList.append([fname,0,0,0,0,0,0])

    return contoursList


baseDir = '/media/aman/data/flyWalk_data/tmp_climbing/CS1/'
#baseDir = '/media/pointgrey/data/flywalk/climbingData/uploaded/'
#baseDir = getFolder(baseDir)

try:
    baseDir = sys.argv[1]
except:
    baseDir = '/media/pointgrey/data/flywalk/'
    baseDir = getFolder(baseDir)
    pass
os.chdir(baseDir)

imExtensions = ['*.png', '*.jpeg']
imDataFolder = 'imageData'
statsfName = 'contoursStats'
statsFileHeader = ['frameDetails','x-coord','y-coord','minorAxis (px)','majorAxis (px)','angle','area (px)']

<<<<<<< HEAD
nThreads = 7
=======
nThreads = 4
>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a
#nImThresh = 100

params = {} # dict for holding parameter values for contour detection
params['blurKernel'] = 5
params['block'] = 123
params['cutoff'] = 15
params['ellaxisRatioMin'] = 0.2
params['ellaxisRatioMax'] = 0.5
params['flyareaMin'] = 300 
params['flyareaMax'] = 900 


rawdirs = natural_sort([ name for name in os.listdir(baseDir) if os.path.isdir(os.path.join(baseDir, name)) ])
<<<<<<< HEAD
pool = mp.Pool(processes=nThreads)

for idx, rawDir in enumerate(rawdirs):
    dirs = natural_sort([ os.path.join(rawDir, imDataFolder, name) for name in os.listdir(os.path.join(rawDir, imDataFolder)) if os.path.isdir(os.path.join(rawDir, imDataFolder, name)) ])
    csvList = glob.glob(os.path.join(rawDir, imDataFolder, '*.csv'))
    for _,imFolder in enumerate(dirs):
        statsFile = imFolder.rstrip('/')+'_'+statsfName+'_'+rawDir+'.csv'
        if statsFile not in csvList:
            if 'tracked' not in imFolder:
                flyContours = getFlycontour(imFolder, imExtensions, params, statsFileHeader, pool)
                with open(statsFile, "w") as f:
                    writer = csv.writer(f)
                    writer.writerows(flyContours)
                f.close()
        else:
            print('already processed\n==> %s'%imFolder)
        
















=======

for idx, rawDir in enumerate(rawdirs):
    dirs = natural_sort([ os.path.join(rawDir, imDataFolder, name) for name in os.listdir(os.path.join(rawDir, imDataFolder)) if os.path.isdir(os.path.join(rawDir, imDataFolder, name)) ])
    for _,imFolder in enumerate(dirs):
        if 'tracked' not in imFolder:
            flyContours = getFlycontour(imFolder, imExtensions, params, statsFileHeader, nThreads)
            statsFile = imFolder.rstrip('/')+'_'+statsfName+'_'+rawDir+'.csv'
            with open(statsFile, "w") as f:
                writer = csv.writer(f)
                writer.writerows(flyContours)
>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a




<<<<<<< HEAD
'''
dirname = '/media/aman/data/flyWalk_data/'

dirname = '/media/aman/data/flyWalk_data/tmp_climbing/CS1/tmp_20171201_195931_CS_20171128_0245_11-Climbing_male/imageData/20171201_195953/'
imExt = '.png'

#dirname = getFolder(dirname)

params = {} # dict for holding parameter values for contour detection
params['blurKernel'] = 5
params['block'] = 123
params['cutoff'] = 15
params['ellaxisRatioMin'] = 0.2
params['ellaxisRatioMax'] = 0.5
params['flyareaMin'] = 300 
params['flyareaMax'] = 900 

nImThresh = 100
statsfName = 'contoursStats'

nThreads = 4
csvFileHeader = ['frameDetails','x-coord','y-coord','minorAxis (px)','majorAxis (px)','angle','area (px)']
flyContours = getFlycontour(dirname, imExt, params, statsFileHeader, nThreads)

statsFile = dirname.rstrip('/')+'_'+statsfName+'.csv'
with open(statsFile, "w") as f:
    writer = csv.writer(f)
    writer.writerows(flyContours)


'''
=======

>>>>>>> 5da1375de0a6b04d2e543502a8003d5c0285498a
#!/usr/bin/env python # -*- coding: utf-8 -*- Created on Mon Aug 13 00:08:24 2018  @author: aman  This script will      1)  find the imageData folders which contain fly tracks     2)  track the fly in the whole image #import copy GUI funciton for browsing and selecting the folder displays images from a given imagestack with 'delay'milliseconds return the colors to be used for displaying the track returns the list of detected contour     input:         im:  image numpy array to be processed for contour detection         params: dictionary of all parameters used for contour detection         params :             blurkernel             block             cutoff             ellratio             ellAxisRatioMin             ellAxisRatioMax             flyAreaMin             flyAreaMax #print len(contours) #print("no contour detected") input:          args[0] = path of the image to be read         args[1] = parameters using which the image will be processed for contour detection     output:         im = array of the image read         cnt = detected contour from the image "im"      im = cv2.imread(x[0], cv2.IMREAD_GRAYSCALE)     cnt = getImContours((im, x[1]))     return [im, cnt] tracks the fly using cv2.SimpleBlobDetector method and saves the tracked flies in folders #pool = mp.Pool(processes=workers) #baseDir = '/media/pointgrey/data/flywalk/climbingData/uploaded/' #baseDir = getFolder(baseDir) #nImThresh = 100 # dict for holding parameter values for contour detection dirname = '/media/aman/data/flyWalk_data/'  dirname = '/media/aman/data/flyWalk_data/tmp_climbing/CS1/tmp_20171201_195931_CS_20171128_0245_11-Climbing_male/imageData/20171201_195953/' imExt = '.png'  #dirname = getFolder(dirname)  params = {} # dict for holding parameter values for contour detection params['blurKernel'] = 5 params['block'] = 123 params['cutoff'] = 15 params['ellaxisRatioMin'] = 0.2 params['ellaxisRatioMax'] = 0.5 params['flyareaMin'] = 300  params['flyareaMax'] = 900   nImThresh = 100 statsfName = 'contoursStats'  nThreads = 4 csvFileHeader = ['frameDetails','x-coord','y-coord','minorAxis (px)','majorAxis (px)','angle','area (px)'] flyContours = getFlycontour(dirname, imExt, params, statsFileHeader, nThreads)  statsFile = dirname.rstrip('/')+'_'+statsfName+'.csv' with open(statsFile, "w") as f:     writer = csv.writer(f)     writer.writerows(flyContours)