From ce5a4b372ff4350fc3dfeb3233824dca73ded780 Mon Sep 17 00:00:00 2001
From: unknown <Ed@.(none)>
Date: Tue, 30 Aug 2011 23:40:38 -0400
Subject: [PATCH] Created a git repository

---
 __init__.py                       |   0
 filelist/__init__.py              |   0
 filelist/filesettings.py          |   9 +
 filelist/filetools.py             |  82 +++++
 filelist/models.py                | 207 +++++++++++
 filelist/odysseus/imageio.py      | 324 ++++++++++++++++
 filelist/odysseus/imageprocess.py | 590 ++++++++++++++++++++++++++++++
 filelist/populatedb.py            |  35 ++
 filelist/views.py                 | 170 +++++++++
 htroot/filter.htm                 |  54 +++
 htroot/processing.htm             | 221 +++++++++++
 settings.py                       |  98 +++++
 templates/imglist.html            |  24 ++
 templates/methodlist.html         |  18 +
 templates/paramlist.html          |  15 +
 templates/runloglist.html         |  47 +++
 templates/sampleimages.html       |   3 +
 urls.py                           |  31 ++
 18 files changed, 1928 insertions(+)
 create mode 100644 __init__.py
 create mode 100644 filelist/__init__.py
 create mode 100644 filelist/filesettings.py
 create mode 100644 filelist/filetools.py
 create mode 100644 filelist/models.py
 create mode 100644 filelist/odysseus/imageio.py
 create mode 100644 filelist/odysseus/imageprocess.py
 create mode 100644 filelist/populatedb.py
 create mode 100644 filelist/views.py
 create mode 100644 htroot/filter.htm
 create mode 100644 htroot/processing.htm
 create mode 100644 settings.py
 create mode 100644 templates/imglist.html
 create mode 100644 templates/methodlist.html
 create mode 100644 templates/paramlist.html
 create mode 100644 templates/runloglist.html
 create mode 100644 templates/sampleimages.html
 create mode 100644 urls.py

diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/filelist/__init__.py b/filelist/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/filelist/filesettings.py b/filelist/filesettings.py
new file mode 100644
index 0000000..9e8d82b
--- /dev/null
+++ b/filelist/filesettings.py
@@ -0,0 +1,9 @@
+IMG_LOCS = {"cimages":"C:\\images\\"}
+RL_LOCS = {"crunlogs":"C:\\runlogs\\"}
+STATIC_DIR = "./static/"
+#THUMB_DIR = "C:\\thumb\\"
+PNG_DIR = "C:\\django\\django\\clinamen\\static\\png\\"
+PNG_URL = "../../../static/png/"
+THUMB_DIR = "C:\\django\\django\\clinamen\\static\\thumb\\"
+THUMB_URL = "../../../static/thumb/"
+THUMB_SIZE = 64
diff --git a/filelist/filetools.py b/filelist/filetools.py
new file mode 100644
index 0000000..ec76ecc
--- /dev/null
+++ b/filelist/filetools.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+"""Functions to easily process file names."""
+
+import os
+import glob
+import re
+
+
+def sort_files_by_date(filelist, newestfirst=True):
+    """Return a list of files sorted by time, newest first by default"""
+
+    mod_time_file = [(os.lstat(item).st_mtime, item) for item in filelist]
+
+    if newestfirst:
+        mod_time_file.sort(reverse=True)
+    else:
+        mod_time_file.sort()
+
+    return [file[1] for file in mod_time_file]
+
+
+def get_files_in_dir(dirname, ext='TIF', globexpr=None, sort=True):
+    """Return a list of all files in a directory with extension ext
+
+    When ``globexpr`` is given, ``ext`` is ignored and the Python glob module
+    is used to search for all files with the given pattern.
+
+    **Inputs**
+
+      * dirname: string, full path to the directory
+      * ext: string, extension of the files to process
+      * globexpr: string, glob search expression (can contain wildcards)
+      * sort: bool, if True the results are sorted by file date/time, newest
+        first
+
+    **Outputs**
+
+      * imgs: list of strings, each string in the list is the complete path to
+        a file
+
+    """
+
+    if globexpr:
+        imgs = glob.glob(os.path.join(dirname, ''.join(globexpr)))
+    else:
+        imgs = glob.glob(os.path.join(dirname, ''.join(['*.', ext])))
+    if sort:
+        imgs = sort_files_by_date(imgs)
+
+    return imgs
+
+
+def find_imgnames(imglist, startstr, stopstr):
+    """Finds names from imglist between startstr and stopstr in time-ordered way
+
+    **Inputs**
+
+      * imglist: list of str, containing paths of images on disc
+      * startstr: str, part of the name of the oldest image by date that is
+                  wanted
+      * stopstr: str, part of the name of the newest image by date that is
+                  wanted
+
+    **Outputs**
+
+      * imgs: list of str, containing the found paths to image files
+
+    """
+
+    imgs = sort_files_by_date(imglist, newestfirst=False)
+    for img in imgs:
+        found_one = re.search(startstr, img)
+        if found_one:
+            start_idx = imgs.index(img)
+            break
+    for img in imgs:
+        found_one = re.search(stopstr, img)
+        if found_one:
+            stop_idx = imgs.index(img)
+            break
+
+    return imgs[start_idx:stop_idx+1]
diff --git a/filelist/models.py b/filelist/models.py
new file mode 100644
index 0000000..b1bc608
--- /dev/null
+++ b/filelist/models.py
@@ -0,0 +1,207 @@
+import os
+import numpy as np
+import scipy as sp
+import re
+import inspect
+import collections
+#from odysseus.imageio import imgimport_intelligent, list_of_frames
+os.environ['DJANGO_SETTINGS_MODULE'] = "settings"
+from django.db import models
+import filelist.filesettings as filesettings
+import Image
+
+class RunLogInfo(models.Model):
+	#path = models.FilePathField(filesettings.RL_DIR, primary_key=True)
+	path = models.CharField(max_length=200, primary_key=True)
+	loc_key = models.CharField(max_length=100)
+	time = models.DateTimeField()
+	sequencepath = models.CharField(max_length=200)
+	listiterationnumber = models.IntegerField(null=True, blank=True)
+	liststarttime = models.DateTimeField(null=True,blank=True)
+	sequenceduration = models.FloatField(null=True,blank=True)
+	description = models.TextField(null=True, blank=True)
+	exceptions = models.TextField(null=True, blank=True)
+	class Meta:
+		ordering=['-time']
+		
+class VariableValue(models.Model):
+	name = models.CharField(max_length=30)
+	value = models.FloatField()
+	runlog = models.ForeignKey('RunLogInfo')
+
+class ImageInfo(models.Model):
+	#path = models.FilePathField(filesettings.IMG_DIR, primary_key=True)
+	path = models.CharField(max_length=100, primary_key=True)
+	loc_key = models.CharField(max_length=100)
+	time = models.DateTimeField()
+	height = models.IntegerField(null=True, blank=True)
+	width = models.IntegerField(null=True, blank=True)
+	number_of_frames = models.IntegerField(null=True, blank=True)
+	imgtype = models.ForeignKey('ImageType', null=True, blank=True)
+	runlog = models.ForeignKey('RunLogInfo', null=True, blank=True)	
+	def makeRawFrames(self):
+		frames = np.dstack(list_of_frames(self.path))
+		
+		self.width = np.size(frames,0)
+		self.height = np.size(frames,1)	
+		self.number_of_frames = np.size(frames,2)
+				
+		for ii in range(np.size(frames,2)):
+			filename = os.path.splitext(os.path.split(self.path)[1])[0]+'_'+str(ii)+'.png'
+			
+			newframe = RawFrame(sourceimage=self, framenumber=ii)
+			newframe.saveframe(frames[:,:,ii], filename)
+			newframe.save()
+	def deleteProcFrames(self):
+		ProcessedFrame.objects.filter(sourceimage=self).delete()
+	def ProcessImage(self): 
+		for method in self.imgtype.methods.all():
+			procmodule = __import__(method.modulename)
+			procmethod = getattr(procmodule, method.name)
+			argdict = {}
+			for param in TypeParameters.objects.filter(imagetype=self.imgtype, methodargument__method=method):
+				argdict[param.methodargument.name]=param.value
+			for ROIparam in TypeROI.objects.filter(imagetype=self.imgtype, methodargument__method=method):
+				argdict[ROIParam.methodargument.name]=ROIparam.ToDict()
+			result=procmethod(self.path, **argdict)
+			if not isinstance(result,tuple):
+				result = (result,)
+			for ii in range(len(result)):
+				if isarray(result[ii]):
+					filename=os.path.splitext(os.path.split(self.path)[1])[0]+'_'+method.name+'_'+str(ii)+'.png'
+						
+					newrecord = ProcessedFrame(sourceimage=self, method=method, framenumber=ii) 
+					newrecord.saveframe(result[ii], filename)
+					newrecord.save()
+				else:
+					newrecord = ProcessedValue(sourceimage=self, method=method, value=float(item[ii]), index=ii)
+					newrecord.save()
+	def getClosestSequence(self):
+		sql = "SELECT * FROM filelist_runloginfo ORDER BY ABS(TIMESTAMPDIFF(SECOND, time,'" + self.time.strftime('%Y-%m-%d %H:%M:%S') + "')) LIMIT 1"
+		for retrunlog in RunLogInfo.objects.raw(sql):
+			self.runlog = retrunlog
+	def getTypeFromDescription(self): 
+		matchObj = re.search("imgtype=(\w+)", self.runlog.description)
+		if matchObj:
+			self.imgtype= matchObj.group(1)		
+	class Meta:
+		ordering=['-time']
+
+class FrameInfo(models.Model):
+	pngpath = models.CharField(max_length=100, primary_key=True)
+	pngurl = models.CharField(max_length=100)
+	pngheight = models.IntegerField()
+	pngwidth = models.IntegerField()
+	thumbpath = models.CharField(max_length=100)
+	thumburl = models.CharField(max_length=100)	
+	thumbheight = models.IntegerField()
+	thumbwidth = models.IntegerField()
+	framenumber = models.IntegerField(null=True, blank=True)
+	sourceimage = models.ForeignKey('ImageInfo', null=True, blank=True)	
+	def saveframe(self, frame, filename):
+		self.pngpath=os.path.join(filesettings.PNG_DIR,filename)
+		self.pngurl=filesettings.PNG_URL+filename
+		self.thumbpath=os.path.join(filesettings.THUMB_DIR,filename)
+		self.thumburl=filesettings.THUMB_URL+filename		
+		
+		im=sp.misc.toimage(frame)
+		im.save(self.pngpath)
+			
+		self.pngwidth = np.size(frame,0)
+		self.pngheight = np.size(frame,1)			
+		aspect=float(self.pngwidth)/float(self.pngheight)
+		
+		if aspect>1:
+			self.thumbwidth = filesettings.THUMB_SIZE
+			self.thumbheight = int(filesettings.THUMB_SIZE/aspect)
+		else:
+			self.thumbwidth = int(filesettings.THUMB_SIZE * aspect)
+			self.thumbheight = filesettings.THUMB_SIZE
+		im.thumbnail([self.thumbwidth, self.thumbheight], Image.ANTIALIAS) 		
+		im.save(self.thumbpath)				
+	class Meta:
+		abstract=True
+		ordering=['framenumber']
+	
+class ProcessingMethod(models.Model):
+	modulename = models.CharField(max_length=100)
+	name = models.CharField(max_length=30) 
+	def getargs(self):
+		procmodule = __import__(self.modulename)
+		#procmethod = procmodule.getAttr(procmodule, self.name)
+		procmethod = getattr(procmodule, self.name)
+		argspec = inspect.getargspec(procmethod)
+		for keyword in argspec.args[1:]:
+			newmetharg, created = MethodArgument.objects.get_or_create(method=self, name=keyword)
+			if re.search("roi_(\w+)", keyword):
+				newmetharg.isROI = True
+			newmetharg.save()
+	class Meta:
+		unique_together = ("modulename", "name")
+	
+class MethodArgument(models.Model):
+	method = models.ForeignKey('ProcessingMethod')
+	name = models.CharField(max_length=30)	
+	isROI = models.NullBooleanField(null=True, blank=True)
+
+class ImageType(models.Model):
+	name = models.CharField(max_length=30, primary_key=True)
+	methods = models.ManyToManyField('ProcessingMethod')
+	parameters = models.ManyToManyField('MethodArgument', through='TypeParameters')	
+	sample = models.ForeignKey('RawFrame', null=True, blank=True)
+	def ClearProcessed(self):
+		ProcessedFrame.objects.filter(sourceimage__imgtype=self).delete()
+	def ProcessType(self):
+		#imtype = ImageType.objects.get(name=self.name)
+		#for iminfo in imtype.ImageInfo_set.all():
+		for iminfo in self.imageinfo_set.all():
+			iminfo.ProcessImage()
+	
+class TypeParameters(models.Model):
+	imagetype = models.ForeignKey('ImageType')
+	methodargument = models.ForeignKey('MethodArgument')
+	value = models.FloatField()	
+	class Meta:
+		unique_together = ("imagetype", "methodargument")
+		
+class TypeROI(models.Model):
+	imagetype = models.ForeignKey('ImageType')
+	methodargument = models.ForeignKey('MethodArgument')
+	x1 = models.IntegerField(null=True, blank=True)
+	x2 = models.IntegerField(null=True, blank=True)
+	y1 = models.IntegerField(null=True, blank=True)
+	y2 = models.IntegerField(null=True, blank=True)
+	def ToDict(self):
+		return {"x1": x1, "x2": x2, "y1": y1, "y2": y2}
+	class Meta:
+		unique_together = ("imagetype", "methodargument")
+
+class ProcessedFrame(FrameInfo):
+	method = models.ForeignKey('ProcessingMethod', null=True, blank=True)
+	
+class RawFrame(FrameInfo):
+	class Meta:
+		abstract=False
+	
+class ProcessedValue(models.Model):
+	sourceimage = models.ForeignKey('ImageInfo')
+	method = models.ForeignKey('ProcessingMethod', null=True, blank=True)
+	value = models.FloatField()
+	index = models.IntegerField(null=True, blank=True)
+	class Meta:
+		unique_together = ("sourceimage", "method")
+
+def get_iterable(x):
+	if isinstance(x, collections.Iterable):
+		return x
+	else:
+		return (x,)
+
+def isarray(s):
+	try:
+		len(s)
+		return True
+	except TypeError:
+		return False
+	
+	
\ No newline at end of file
diff --git a/filelist/odysseus/imageio.py b/filelist/odysseus/imageio.py
new file mode 100644
index 0000000..5f4f065
--- /dev/null
+++ b/filelist/odysseus/imageio.py
@@ -0,0 +1,324 @@
+#!/usr/bin/env python
+"""I/O functions for several image formats.
+
+The relevant formats are TIF, hdf5 and ascii. For ascii and binary numpy formats
+no separate functions are provided for saving an image. This is because saving
+in these formats requires just a single command:
+ascii: np.savetxt('filename', img)
+binary (.npy): np.save('filename', img)
+
+"""
+
+import os
+
+import numpy as np
+import scipy as sp
+# if available, use Zach Pincus' pil_lite which has correct 16-bit TIFF loading
+try:
+    import pil_lite.pil_core.Image as Image
+except ImportError:
+    import Image
+#import tables
+
+
+def list_of_frames(img_name):
+    """Return the list of frames for an image file.
+
+    Details are as described in the imgimport_intelligent docstring.
+
+    """
+
+    img = Image.open(img_name)
+    imglist = []
+
+    try:
+        for i in xrange(8):
+            if img.mode == 'I':
+                imdata = np.asarray(img, dtype=np.int16)
+            else:
+                imdata = np.asarray(img, dtype=np.float32)
+            # fix 3-channel TIFF images
+            if np.rank(imdata)==3:
+                imdata = imdata[:,:,0] + 256*imdata[:,:,1] + 65536*imdata[:,:,2]
+            imglist.append(imdata)
+            img.seek(i+1) # next frame
+    except EOFError:
+        pass
+
+    if not imglist:
+        raise ImportError, 'No frames detected in file %s' %img_name
+    else:
+        return imglist
+
+
+def imgimport_intelligent(img_name, foo=3, bar=4, roi_baz=[12,24,56,78]):
+    """Opens an image file containing one or more frames
+
+    The number of frames in the image is automatically detected. If it is a
+    single frame, it is assumed to be a transmission image. If there are three
+    frames, the first one is assumed to be probe with atoms (pwa), the second
+    one probe without atoms (pwoa) and the third one a dark field (df).
+    For four frames, it is assumed to be (pwoa, pwa, df1, df2).
+    For six frames, the first two are discarded (they are for clearing the
+    CCD charge on the Coolsnap camera), three to six are (pwoa, pwa, df1, df2).
+
+    **Inputs**
+
+      * img_name: string containing the full path to an image
+
+    **Outputs**
+
+      * img_array: 3D array, containing the three or four frames of the image,
+                   in the  order (pwa, pwoa, df, df2).
+
+    **Notes**
+
+    The datatype has to be set to float in Winview, otherwise there is a
+    strange problem reading the frames; support for 16-bit tif files is
+    lacking a bit in PIL. Note: when pil_lite is available this does work.
+
+    The same support is lacking in MS .Net apparently, hence the weird check
+    for 3-channel TIFFs. What happens here is that XCamera can output multipage
+    8-bit RGB TIFFs. Each page is of shape (M,N,3), where the 8-bit color
+    channels combine to output 24-bit B/W data.
+
+    """
+
+    imglist = list_of_frames(img_name)
+
+    if len(imglist)==1:
+        return imglist[0]
+    elif len(imglist) in [3, 4]:
+        # make an array from the list of frames, with shape (img[0], img[1], 3)
+        img_array = np.dstack(imglist)
+    elif len(imglist)==6:
+        # get rid of first two frames, they're junk. then swap pwoa, pwa.
+        img_array = np.dstack([imglist[3], imglist[2], imglist[5], imglist[4]])
+    elif len(imglist)==8:
+        # get rid of first two frames, then 2x PWA, 2x DF, 2x PWOA (swap DF, PWOA)
+        img_array = np.dstack([imglist[2], imglist[3], imglist[6], imglist[7],
+                               imglist[4], imglist[5]])
+    else:
+        raise ImportError, 'Number of frames is %s' %(len(imglist))
+
+    return img_array
+
+
+def import_rawframes(img_name):
+    """Opens an image file containing three frames
+
+    The datatype has to be set to float in Winview, otherwise there is a
+    strange problem reading the frames; support for 16-bit tif files is
+    lacking a bit in PIL.
+
+    **Inputs**
+
+      * img_name: string containing the full path to an image
+
+    **Outputs**
+
+      * img_array: 3D array, containing the three frames of the image
+
+    """
+
+    img = Image.open(img_name)
+    # note the reversed order because Image and asarray have reversed order
+    img_array = np.zeros((img.size[1], img.size[0], 3), dtype=np.float32)
+
+    img_array[:, :, 0] = np.asarray(img, dtype=np.float32)
+    try:
+        img.seek(1) # next frame
+        img_array[:, :, 1] = np.asarray(img, dtype=np.float32)
+        img.seek(2) # next frame
+        img_array[:, :, 2] = np.asarray(img, dtype=np.float32)
+    except EOFError:
+        print 'This image contains less than 3 frames'
+        return None
+
+    return img_array
+
+
+def import_rawimage(img_name):
+    """Opens an image file and returns it as an array."""
+
+    im = Image.open(img_name)
+
+    return np.asarray(im)
+
+
+def import_xcamera(img_name, ext='xraw'):
+    """Load the three .xraw files from XCamera
+
+    It is assumed that the file with extension .xraw0 contains the probe
+    with atoms (pwa), the one with extension .xraw1 the probe without atoms
+    (pwoa), and the one with extension .xraw2 the dark field (df).
+
+    **Inputs**
+
+      * img_name: str, name of the image with or without extension
+                  (the extension is stripped and replaced by `ext`.
+      * ext: str, the extension of the XCamera file. Normally xraw or xroi.
+
+    **Outputs**
+
+      * raw_array: 3D array, containing the three raw frames (pwa, pwoa, df)
+
+    """
+
+    if ext=='xraw':
+        rawext = ['.xraw0', '.xraw1', '.xraw2']
+    elif ext=='xroi':
+        rawext = ['.xroi0', '.xroi1', '.xroi2']
+    else:
+        raise ValueError, 'Unknown extension for XCamera file'
+
+    basename = os.path.splitext(img_name)[0]
+    try:
+        pwa = np.loadtxt(''.join([basename, rawext[0]]), dtype=np.int16)
+        pwoa = np.loadtxt(''.join([basename, rawext[1]]), dtype=np.int16)
+        df = np.loadtxt(''.join([basename, rawext[2]]), dtype=np.int16)
+    except IOError, e:
+        print e
+        return None
+
+    raw_array = np.dstack([pwa, pwoa, df])
+
+    return raw_array
+
+
+def save_tifimage(imgarray, fname, dirname=None):
+    """Save a single image in TIF format
+
+    **Inputs**
+
+      * imgarray: 2D array, containing a single frame image
+      * fname: str, filename of the file to save, optionally including
+               the full path to the directory
+      * dirname: str, if not None, fname will be appended to dirname to
+                 obtain the full path of the file to save.
+
+    **Notes**
+
+    Multiple frame tif images are not supported. For such data hdf5 is the
+    recommended format.
+
+    """
+
+    if dirname:
+        fname = os.path.join(dirname, fname)
+    fname = ''.join([os.path.splitext(fname)[0], '.tif'])
+
+    im = sp.misc.toimage(imgarray, mode='F')
+    im.save(fname, mode='F')
+
+
+def save_hdfimage(imgarray, fname, dirname=None):
+    """Save an image to an hdf5 file
+
+    **Inputs**
+
+      * imgarray: ndarray, containing the image data. If the array is 2D,
+                  it is assumed that this is a single frame image. If it is
+                  3D, the frames will be saved as separate arrays:
+                  ('pwa', 'pwoa', 'df'), and if there is a fourth frame this
+                  is df2.
+      * fname: str, filename of the file to save, optionally including
+               the full path to the directory
+      * dirname: str, if not None, fname will be appended to dirname to
+                 obtain the full path of the file to save.
+
+    """
+
+    if dirname:
+        fname = os.path.join(dirname, fname)
+    fname = ''.join([os.path.splitext(fname)[0], '.h5'])
+
+    # Open a new empty HDF5 file
+    h5file = tables.openFile(fname, mode='w')
+
+    if len(imgarray.shape)==2:
+        # Get the root group
+        root = h5file.root
+        # Save image in the HDF5 file
+        h5file.createArray(root, 'img', imgarray, title='Transmission image')
+
+    elif len(imgarray.shape)==3:
+        # image frames to be saved
+        pwa = imgarray[:, :, 0]
+        pwoa = imgarray[:, :, 1]
+        df = imgarray[:, :, 2]
+        # Get the root group
+        root = h5file.createGroup("/", 'rawframes', 'The raw image frames')
+        # Save image in the HDF5 file
+        h5file.createArray(root, 'pwa', pwa, title='Probe with atoms')
+        h5file.createArray(root, 'pwoa', pwoa, title='Probe without atoms')
+        h5file.createArray(root, 'df', df, title='Dark field')
+
+        if imgarray.shape[2] > 3:
+            df2 = imgarray[:, :, 3]
+            h5file.createArray(root, 'df2', df2, title='Dark field 2')
+
+    else:
+        print 'imgarray does not have the right dimensions, shape is: ', \
+              imgarray.shape
+
+    h5file.close()
+
+
+def load_hdfimage(fname, dirname=None, ext_replace=True):
+    """Load an image from an hdf5 file
+
+    **Inputs**
+
+      * fname: str, filename of the file to save, optionally including
+               the full path to the directory
+      * dirname: str, if not None, fname will be appended to dirname to
+                 obtain the full path of the file to save.
+      * ext_replace: bool, if True replaces the extension of fname with `.h5`
+
+    **Outputs**
+
+      * transimg: ndarray, the image data
+
+    """
+
+    if dirname:
+        fname = os.path.join(dirname, fname)
+    if ext_replace:
+        fname = ''.join([os.path.splitext(fname)[0], '.h5'])
+
+    h5file = tables.openFile(fname, mode='r')
+
+    try:
+        transimg = np.asarray(h5file.root.img)
+        return transimg
+
+    except tables.NoSuchNodeError:
+        pwa = np.asarray(h5file.root.rawframes.pwa)
+        pwoa = np.asarray(h5file.root.rawframes.pwoa)
+        df = np.asarray(h5file.root.rawframes.df)
+        imgarray = np.dstack([pwa, pwao, df])
+        return imgarray
+
+    finally:
+        h5file.close()
+
+
+def convert_xcamera_to_hdf5(imglist, ext='xraw'):
+    """Convert every file in imglist to an hdf5 file.
+
+    The raw files are saved in the hdf5 file as
+    `root.rawframes.pwa`, `root.rawframes.pwoa`, `root.rawframes.df`.
+    Their dtype is uint16, which results in files of a third smaller than
+    the xcamera text files.
+
+    **Inputs**
+
+      * imglist: list of str, paths to .xraw0 files
+      * ext: str, the extension of the XCamera file. Normally xraw or xroi.
+
+    """
+
+    for img in imglist:
+        imgarray = import_xcamera(img, ext=ext)
+        save_hdfimage(imgarray, img)
diff --git a/filelist/odysseus/imageprocess.py b/filelist/odysseus/imageprocess.py
new file mode 100644
index 0000000..99587b6
--- /dev/null
+++ b/filelist/odysseus/imageprocess.py
@@ -0,0 +1,590 @@
+#!/usr/bin/env python
+"""Image processing functions
+
+Some functionality is independent of the type of image, for example
+smoothing, thresholding and interpolation. Other functionality is specific
+to cold atom experiments, for example calculating optical density and
+transmission for absorption images.
+
+"""
+
+import os
+
+import scipy as sp
+import scipy.ndimage as ndimage
+import numpy as np
+import Image
+import matplotlib as mpl
+import pylab
+
+
+def trans2od(transimg, maxod=3.5):
+    """Calculates the optical density image from a transmission image
+
+    For pixels with strange values due to noise, replace the value of that pixel
+    by the maximum OD that can be experimentally measured.
+
+    """
+
+    odimg = np.where(transimg>np.exp(-maxod), -np.log(transimg), maxod)
+
+    return odimg
+
+
+def od2trans(odimg, maxod=3.5):
+    """Calculates the transmission image from an optical density image
+
+    For pixels with strange values due to noise, replace the value of that pixel
+    by the maximum OD that can be experimentally measured.
+
+    """
+
+    transimg = np.where(odimg<maxod, np.exp(-odimg), np.exp(-maxod))
+
+    return transimg
+
+
+def calc_absimage(raw_frames, norm_edge=0.):
+    """Calculates the transmission image and optical density.
+
+    **Inputs**
+
+      * raw_frames: 3D array, containing three or four images;
+                    probe with atoms (pwa), probe without atoms (pwoa),
+                    dark field (df) and `optionally` a second dark field (df2).
+                    If there is no second dark field, the same one is used
+                    twice.
+      * norm_edge: bool, if True, normalize to one using the edge (it is assumed
+                   no atoms are visible on the edge.
+
+    **Outputs**
+
+      * transimg: 2d array containing the transmission image,
+              defined as (pwa - df)/(pwoa - df2).
+      * odimg: 2d array containing the optical density for each pixel
+
+    """
+
+    pwa = raw_frames[:, :, 0]
+    pwoa = raw_frames[:, :, 1]
+    df = raw_frames[:, :, 2]
+    try:
+        df2 = raw_frames[:, :, 3]
+    except IndexError:
+        df2 = df
+
+    nom = pwa - df
+    den = pwoa - df2
+    nom = np.where(nom<1, 1, nom)
+    den = np.where(den<1, 1, den)
+    if norm_edge:
+        nom = normalize_edgestrip(nom)
+        den = normalize_edgestrip(den)
+
+    transimg = nom.astype(float)/den
+    odimg = -np.log(transimg)
+
+    return transimg, odimg
+
+
+def threshold_image(img, thres=0.5, below=True):
+    """Returns a binary array (ones and zeros) depending on pixel values.
+
+    **Inputs**
+
+      * img: array, containing an image (also works for non-image data)
+      * thres: scalar value, the threshold value
+      * below: boolean value, True means that each element of img that is below
+           thres gives a 1 in the thresholded image, and each element that
+	   is above it a 0.
+
+    **Outputs**
+
+      * thres_img: array, containing ones and zeros as a result of
+                   thresholding the input array.
+
+    """
+
+    if below:
+        thres_img = np.where(img<thres, 1, 0)
+    else:
+        thres_img = np.where(img<thres, 0, 1)
+
+    return thres_img
+
+
+def find_fitrange(od_prof, od_max=1, min_cutoff=8):
+    """Select a suitable range of radii to use for fitting the image.
+
+    When the optical density saturates at a certain range of radii, and then
+    that data range is used for fitting, it throws off the fit. Therefore
+    a cutoff value for the maximum optical density should be specified, and the
+    fit only done for values of OD smaller than that. The data is smoothed,
+    and the index for the radius where the OD drops below OD_max is determined.
+
+    **Inputs**
+
+      * od_prof: 1D array, containing the radially averaged optical density
+                 profile.
+
+    **Outputs**
+
+      * cutoff: int, the larger value of index of rcoord where od_prof<od_max
+                     or min_cutoff.
+
+    **Optional inputs**
+
+      * od_max: float, the maximum desired value of the optical density
+      * min_cutoff: int, the minimum value for the cutoff index. The reason to
+                    use this is that a radially averaged profile is very noisy
+                    around the center which may skew a fit.
+
+    """
+    try:
+        od_new = smooth(od_prof, window_len=15)
+        cutoff = mpl.mlab.find(od_new<od_max).min()
+    except ValueError:
+        # no values below the cutoff
+        cutoff = min_cutoff
+
+    cutoff = max(cutoff, min_cutoff)
+    if cutoff > od_prof.size:
+        raise ValueError, 'Input array is smaller than min_cutoff'
+
+    return cutoff
+
+
+def radial_interpolate(img, com, dr, phi=None, elliptic=None, full_output=False):
+    """Does radial averaging around the center of mass of the image.
+
+    Radial averaging of the image data on circles spaced by dr around the
+    center of mass. The number of points on each circle is dphi*sqrt(i+1),
+    with i the circle index. A bilinear interpolation method is used.
+
+    **Inputs**
+
+      * img: 2D array, normally containing image data
+      * com: 1D array with two elements, the center of mass coordinates in
+             pixels
+      * dr: radial step size in pixels
+
+    **Outputs**
+
+      * rcoord: 1D array containing the radial coordinate
+      * rad_profile: 1D array containing the averaged profile
+
+    **Optional inputs**
+
+      * phi: 1D array, the angles along which line profiles are taken. More
+             values in phi means a more precise radial average; default is
+             2*pi times the maximum radius in pixels
+      * elliptic: tuple, containing two elements. the first one is the
+        ellipticity (or ratio of major and minor axes), the second one is the
+        angle by which the major axis is rotated from the y-axis.
+      * full_output: bool, selects whether rprofiles and phi are returned
+
+    """
+
+    xsize, ysize = img.shape
+    # number of used points in radial direction, stops if image edge is reached
+    rmax = np.array([xsize-com[0], com[0], ysize-com[1], com[1]]).min()
+    rcoord = np.arange(0, rmax, dr)
+    if not phi:
+        phi = np.linspace(0, 2*np.pi, rmax*np.pi)
+
+    rprofiles = lineprofiles(img, com, rcoord, phi, elliptic=elliptic)
+    rad_profile = rprofiles.mean(axis=1)
+
+    if full_output:
+        return rcoord, rad_profile, rprofiles, phi
+    else:
+        return rcoord, rad_profile
+
+
+def lineprofiles(img, com, rcoord, phi, elliptic=None):
+    """Generate radial profiles around center of mass
+
+    Line profiles without any averaging are generated. This is useful for
+    comparing the radially averaged profile with, to make sure that that is a
+    valid procedure.
+
+    **Inputs**
+
+      * img: 2D array, normally containing image data
+      * com: 1D array with two elements, the center of mass coordinates in pixels
+      * rcoord: 1D array, radial coordinate for line profiles
+                this is usually obtained from radial_interpolate
+      * phi: 1D array, angles along which line profiles are required
+
+    **Outputs**
+
+      * rprofiles: 2D array, containing radial profiles along angles
+
+    **Optional inputs**
+
+      * elliptic: tuple, containing two elements. the first one is the
+        ellipticity (or ratio of major and minor axes), the second one is the
+        angle by which the major axis is rotated from the y-axis. This should
+        be the same as used for radial averaging.
+
+    **Notes**
+
+      The form used for mapping an ellipse to (x,y) coordinates is:
+      x = a\cos\phi\cos\alpha - b\sin\phi\sin\alpha
+      y = b\sin\phi\cos\alpha + a\cos\phi\sin\alpha
+
+    """
+
+    indshape = (phi.size, rcoord.size)
+
+    if elliptic:
+        (ell, rot) = elliptic
+    else:
+        (ell, rot) = (1, 0)
+
+    xr = com[0] + (np.ones(indshape)*rcoord).transpose()*np.cos(phi)*np.cos(rot) -  \
+         ell*(np.ones(indshape)*rcoord).transpose()*np.sin(phi)*np.sin(rot)
+    yr = com[1] + ell*(np.ones(indshape)*rcoord).transpose()*np.sin(phi)*np.cos(rot) - \
+         (np.ones(indshape)*rcoord).transpose()*np.cos(phi)*np.sin(rot)
+
+    rprofiles = bilinear_interpolate(xr, yr, img)
+
+    return rprofiles
+
+
+# move out the plotting part!
+def radialprofile_errors(odprofiles, angles, od_prof, od_cutoff, \
+                         showfig=False, savefig_name=None, report=True):
+    """Calculate errors in radial profiles as a function of angle
+
+    **Inputs**
+
+      * odprofiles: 2D array, containing radial OD profiles along angles
+      * angles: 1D array, angles at which radial profiles are taken
+                          (zero is postive x-axis)
+      * od_prof: 1D array, radially averaged optical density
+      * od_cutoff: integer, index of profiles at which maximum fit-OD is reached
+
+    **Outputs**
+
+      * av_err: float, sum of absolute values of errors in errsum
+
+    **Optional inputs**
+
+      * showfig: bool, determines if a figure is shown with density profile
+                 and fit
+      * report: bool, if True print the sums of the mean and rms errors
+      * savefig_name: string, if not None and showfig is True, the figure is
+                      not shown but saved as png with this string as filename.
+
+    """
+
+    err = (odprofiles[od_cutoff:, :].transpose() - \
+           od_prof[od_cutoff:]).sum(axis=1)
+
+    av_err = np.abs(err).mean()
+
+    if report:
+        print 'mean error is ', err.mean()
+        print 'rms error is ', av_err
+
+    if showfig:
+        # angular plot of errors, red for positive, blue for negative values
+        pylab.figure()
+        poserr = pylab.find(err>0)
+        negerr = pylab.find(err<0)
+
+        pylab.polar(angles[negerr], np.abs(err[negerr]), 'ko', \
+                    angles[poserr], np.abs(err[poserr]), 'wo')
+        pylab.title('Angular dependence of fit error')
+        pylab.text(np.pi/2+0.3, np.abs(err).max()*0.85, \
+                   r'$\sum_{\phi}|\sum_r\Delta_{OD}|=%1.1f$'%av_err)
+        if not savefig_name:
+            pylab.show()
+        else:
+            pylab.savefig(''.join([os.path.splitext(savefig_name)[0], '.png']))
+
+    return av_err
+
+
+def bilinear_interpolate(xr, yr, img):
+    """Do a bi-linear interpolation to get the value at image coordinates
+
+    **Inputs**
+      * xr: array-like, the x-coordinates of the point to be interpolated
+      * yr: array-like, the y-coordinates of the point to be interpolated
+      * img: 2d-array, the image data
+
+    **Outputs**
+      * ans: array-like, the result of the interpolation
+
+    """
+
+    ans = ndimage.map_coordinates(img, np.array([xr, yr]), order=1, \
+                                  mode='nearest')
+    return ans
+
+
+def imgslice(img, cpoint, angle=0, width=None):
+    """Take a line profile through the centerpoint
+
+    **Inputs**
+      * img: 2D array, the image data
+      * cpoint: 1D array, the center point coordinates of the required slice
+
+    **Outputs**
+      * lprof_coord: 1D array, the slice indices in units of pixels
+      * lprof: 1D array, the slice data
+
+    **Optional inputs**
+
+      * angle: float, the angle under which the slice is taken in degrees
+      * width: float, the width over which the slice is averaged
+
+    """
+
+    angle = angle*np.pi/180 # deg to rad
+    # determine coefficients a and b of center line y=ax+b
+    a = np.tan(angle)
+    b = cpoint[1] - cpoint[0]*a
+    # max of indices
+    xmax, ymax = img.shape
+    xmax = xmax-1
+    ymax = ymax-1
+    # determine begin and end points of center line
+    if 0 < b < ymax:
+        startpt = (0, b)
+    elif 0 < -b/a < xmax:
+        startpt = (-b/a, 0)
+    else:
+        startpt = ((ymax-b)/a, ymax)
+    if 0 < a*xmax+b < ymax:
+        stoppt = (xmax, a*xmax+b)
+    elif 0 < (ymax-b)/a < xmax:
+        stoppt = ((ymax-b)/a, ymax)
+    else:
+        stoppt = (-b/a, 0)
+
+    def dist(a, b):
+        """Distance between points"""
+        d = a - b
+        return np.sqrt(np.dot(d,d))
+
+    slicelen = min(dist(startpt, cpoint), dist(stoppt, cpoint))*0.8
+
+    # generate the slice coordinates, discard endpoint (safer for interpolation)
+    npts = 3
+    xslice = cpoint[0] + np.arange(-slicelen, slicelen, 1./npts)*np.cos(angle)
+    yslice = cpoint[1] + np.arange(-slicelen, slicelen, 1./npts)*np.sin(angle)
+
+    if width:
+        try:
+            perpstep = np.linspace(-width/2., width/2., num=round(width))
+            lprof = np.zeros((xslice.size, perpstep.size))
+            for i in xrange(perpstep.size):
+                xx_slice = xslice + perpstep[i]*np.cos(angle+np.pi/2)
+                yy_slice = yslice + perpstep[i]*np.sin(angle+np.pi/2)
+                lprof[:, i] = bilinear_interpolate(xx_slice, yy_slice, img)
+            lprof = lprof.mean(axis=1)
+        except IndexError:
+            print 'Index out of bounds, may be an error in the if/else code above'
+            raise IndexError
+    else:
+        xslice = xslice[1:-1]
+        yslice = yslice[1:-1]
+        lprof = bilinear_interpolate(xslice, yslice, img)
+
+    lprof_coord = np.arange(lprof.size)-lprof.size/2.
+
+    return lprof_coord, lprof, npts
+
+
+def mirror_line(linedata, negative_mirror=False):
+    """Mirrors a 1D array around its first element
+
+    **Inputs**
+
+      * linedata: 1D array, the array to be mirrored
+      * negative_mirror: bool, if True the mirrors elements are multiplied by
+                         -1. This is useful to mirror the x-axis of a plot.
+
+    **Outputs**
+
+      * mirrored: 1D array, the output array, which is now symmetric around its
+                  midpoint.
+
+    """
+
+    mir_size = linedata.shape[0] -1
+    mirrored = np.zeros(mir_size*2 + 1)
+    mirror_idx = np.arange(mir_size, 0, -1)
+    mirrored[:mir_size] = linedata[mirror_idx]
+    mirrored[mir_size:] = linedata
+
+    if negative_mirror:
+        mirrored[:mir_size] *= -1
+
+    return mirrored
+
+
+def smooth(x, window_len=10, window='hanning'):
+    """Smooth the data using a window with requested size.
+
+    This method is based on the convolution of a scaled window with the signal.
+    The signal is prepared by introducing reflected copies of the signal
+    (with the window size) in both ends so that transient parts are minimized
+    in the begining and end part of the output signal.
+
+    Adapted from the Scipy Cookbook by Ralf Gommers.
+
+    **Inputs**
+
+      * x: 1D array, data that needs to be smoothed
+
+    **Outputs**
+
+      * x_smooth: 1D array, the smoothed signal
+
+    **Optional inputs**
+
+      * window_len: int, the size of the smoothing window
+      * window: str, the type of window from 'flat', 'hanning', 'hamming',
+                     'bartlett', 'blackman'. A flat window will produce a
+                     moving average smoothing.
+
+    """
+
+    if x.ndim != 1:
+        raise ValueError, "smooth only accepts 1 dimension arrays."
+
+    if x.size < window_len:
+        window_len = round(x.size/2)
+
+    if window_len<3:
+        return x
+
+    if not window in ['flat', 'hanning', 'hamming', 'bartlett', 'blackman']:
+        raise ValueError, \
+              """Window is on of 'flat', 'hanning', 'hamming',
+              'bartlett', 'blackman'"""
+
+    s = np.r_[2*x[0]-x[window_len:1:-1], x, 2*x[-1]-x[-1:-window_len:-1]]
+
+    if window=='flat': # moving average
+        w = np.ones(window_len, 'd')
+    else:
+        w = eval('np.'+window+'(window_len)')
+
+    y = np.convolve(w/w.sum(), s, mode='same')
+    x_smooth = y[window_len-1:-window_len+1]
+
+    return x_smooth
+
+
+def maxod_correct(odimg, odmax):
+    """Corrects calculated OD from an absorption image for finite OD_max
+
+    This idea was taken from Brian DeMarco's thesis, but it does not seem to
+    make much of a difference at low OD. For high-OD images it causes errors
+    because there will be data points with measured OD higher than the maximum
+    observable OD due to noise in the image.
+
+    It is left in here for completeness, but it is recommended to not use this
+    method. Instead, images should be taken in a regime where this correction
+    is negligibly small anyway (i.e. below an OD of 1.5).
+
+    """
+
+    c = np.exp(odmax) - 1
+    realOD = -np.log((c+1.)/c*np.exp(-odimg) - 1./c)
+
+    return realOD
+
+
+def normalize_img(img, com, size):
+    """Mask off the atoms, then fit linear slopes to the image and normalize
+
+    We assume that there are no atoms left outside 1.5 times the size. This
+    seems to be a reasonable assumption, it does not influence the result of
+    the normalization.
+
+    **Inputs**
+
+      * img: 2D array, containing the image
+      * com: tuple, center of mass coordinates
+      * size: float, radial size of the cloud
+
+    **Outputs**
+
+      * normimg: 2D array, the normalized image
+
+    """
+
+    xmax, ymax = img.shape
+
+    # create mask
+    x_ind1 = round(com[0] - 1.5*size)
+    x_ind2 = round(com[0] + 1.5*size)
+    y_ind1 = round(com[1] - 1.5*size)
+    y_ind2 = round(com[1] + 1.5*size)
+
+    # fit first order polynomial along x and y (do not use quadratic terms!!)
+    if x_ind1>0 and x_ind2<xmax and y_ind1>0 and y_ind2<ymax:
+        normx = np.zeros(x_ind1 + xmax - x_ind2, dtype=float)
+        xx = np.ones(normx.shape)
+        xx[:x_ind1] = np.arange(x_ind1)
+        xx[x_ind1:] = np.arange(x_ind2, xmax)
+        normx[:x_ind1] = img[:x_ind1, :].mean(axis=1)
+        normx[x_ind1:] = img[x_ind2:, :].mean(axis=1)
+
+        # fit normx vs xx
+        fitline = np.polyfit(xx, normx, 1)
+
+        divx = np.ones(img.shape, dtype=float).transpose()*\
+             np.polyval(fitline, np.arange(img.shape[0])).transpose()
+        normimg = img/divx.transpose()
+
+        normy = np.zeros(y_ind1 + ymax - y_ind2, dtype=float)
+        yy = np.ones(normy.shape)
+        yy[:y_ind1] = np.arange(y_ind1)
+        yy[y_ind1:] = np.arange(y_ind2, ymax)
+        normy[:y_ind1] = normimg[:, :y_ind1].mean(axis=0)
+        normy[y_ind1:] = normimg[:, y_ind2:].mean(axis=0)
+
+        # fit normx vs yy
+        fitline = np.polyfit(yy, normy, 1)
+
+        divy = np.ones(normimg.shape, dtype=float)*\
+             np.polyval(fitline, np.arange(normimg.shape[1]))
+        normimg = normimg/divy
+    else:
+        print "atom cloud extends to the edge of the image, can't normalize"
+        raise NotImplementedError
+
+    return normimg
+
+
+def normalize_edgestrip(img, normval=1., striplen=5):
+    """Normalizes the image so the average value on the edges is normval.
+
+    This is simply a multiplication of the whole image array by a number
+    so that the average intensity on the edges of the image is `normval`.
+
+    **Inputs**
+
+      * img: 2D array, image data
+      * normval: float, the value to which img is normalized
+      * striplen: int, number of pixels along each edge used for normalization
+
+    **Outputs**
+
+      * normimg: 2D array, the normalized image
+
+    """
+
+    vstrip = (img[:striplen, :] + img[-striplen:, :])*0.5
+    hstrip = (img[:, :striplen] + img[:, -striplen:])*0.5
+    normfactor = (hstrip.sum() + vstrip.sum())/(hstrip.size + vstrip.size)
+    normimg = img*normval/normfactor
+
+    return normimg
diff --git a/filelist/populatedb.py b/filelist/populatedb.py
new file mode 100644
index 0000000..6099553
--- /dev/null
+++ b/filelist/populatedb.py
@@ -0,0 +1,35 @@
+import filetools 
+import os 
+import re 
+import glob
+import models
+import datetime 
+import filesettings
+import scipy as sp
+import numpy as np
+from odysseus.imageio import imgimport_intelligent
+from odysseus.imageprocess import calc_absimage
+import Image
+import collections
+
+def fullupdateimages(): 
+	for ikey, iloc in filesettings.IMG_LOCS.iteritems():
+		for imgpath in filetools.get_files_in_dir(iloc):
+			mod_time_file = os.lstat(imgpath).st_mtime
+			mod_datetime = datetime.datetime.fromtimestamp(mod_time_file)
+			imginfo=models.ImageInfo(path=imgpath, time=mod_datetime, loc_key=ikey)
+			imginfo.save() 
+			imginfo.makeRawFrames()
+			imginfo.getClosestSequence()
+			imginfo.save()
+			imginfo.ProcessImage
+			imginfo.save()
+			
+def getClosestSequence(imginfo):
+	sql = "SELECT * FROM filelist_runloginfo ORDER BY ABS(TIMESTAMPDIFF(SECOND, time,'" + imginfo.time.strftime('%Y-%m-%d %H:%M:%S') + "')) LIMIT 1"
+	for retrunlog in models.RunLogInfo.objects.raw(sql):
+		imginfo.runlog = retrunlog		
+					
+
+	
+	
\ No newline at end of file
diff --git a/filelist/views.py b/filelist/views.py
new file mode 100644
index 0000000..d9c94f3
--- /dev/null
+++ b/filelist/views.py
@@ -0,0 +1,170 @@
+# Create your views here.
+from django.shortcuts import render_to_response, get_list_or_404
+from django.http import HttpResponse
+from clinamen.filelist.models import *
+import datetime 
+import json
+
+def tester(request):
+	return HttpResponse("Test succeeded again")
+
+def imagelist(request, url):
+	img_list = get_list_or_404(ImageInfo)
+	return render_to_response('imglist.html', {'img_list': img_list})
+
+def runloglist(request, url):
+	runlog_list = get_list_or_404(RunLogInfo)
+	return render_to_response('runloglist.html', {'runlog_list': runlog_list})
+
+def render_methodlist(imagetype):
+	activetype, created = ImageType.objects.get_or_create(name=imagetype)
+	activetype.save()
+	active_list = ProcessingMethod.objects.filter(imagetype__name=imagetype)
+	method_list = get_list_or_404(ProcessingMethod)
+	return render_to_response('methodlist.html', {'method_list': method_list, 'active_list': active_list, 'activetype': activetype})
+
+def methodlist(request):
+	return render_methodlist(request.GET['txttype'])
+			
+def addmethod(request):
+	activetype = ImageType.objects.get(name=request.GET['activetype'])
+	selectedmethod = ProcessingMethod.objects.get(modulename = request.GET['modulename'], name=request.GET['methodname'])
+	activetype.methods.add(selectedmethod)
+	
+	return render_methodlist(request.GET['activetype'])
+
+def removemethod(request):
+	activetype = ImageType.objects.get(name=request.GET['activetype'])
+	selectedmethod = ProcessingMethod.objects.get(modulename = request.GET['modulename'], name=request.GET['methodname'])
+	activetype.methods.remove(selectedmethod)
+	
+	return render_methodlist(request.GET['activetype'])
+
+def editparams(request):
+	arg_list = MethodArgument.objects.filter(method__modulename=request.GET['modulename'], method__name=request.GET['methodname'])
+	#arg_list = MethodArgument.objects.filter(method__modulename=request.GET['modulename'], method__name=request.GET['methodname']).exclude(isROI=True)
+	#argROI_list = MethodArgument.objects.filter(method__modulename=request.GET['modulename'], method__name=request.GET['methodname']).filter(isROI=True)
+	
+	activemethod = ProcessingMethod.objects.get(modulename = request.GET['modulename'], name=request.GET['methodname'])
+	activetype = ImageType.objects.get(name=request.GET['activetype'])
+	
+	param_list = TypeParameters.objects.filter(imagetype__name=request.GET['activetype'], methodargument__method__modulename=request.GET['modulename'], methodargument__method__name=request.GET['methodname'])
+	ROI_list = TypeROI.objects.filter(imagetype__name=request.GET['activetype'], methodargument__method__modulename=request.GET['modulename'], methodargument__method__name=request.GET['methodname'])
+	
+	sampleframe = activetype.sample 
+	
+	arg_params = {}
+	arg_rois ={}
+	
+	for arg in arg_list:
+		if arg.isROI:
+			if sampleframe: 
+				ROI=ROI_list.filter(methodargument=arg)
+				if ROI: 
+					arg_rois[arg.name]=json.dumps({"x1": ROI[0].x1, "x2": ROI[0].x2, "y1": ROI[0].y1, "y2": ROI[0].y2})
+				else:
+					arg_rois[arg.name]=''		
+		else:
+			param=param_list.filter(methodargument=arg)
+			if param: 
+				arg_params[arg.name]=param[0].value
+			else:
+				arg_params[arg.name]=''
+	return render_to_response('paramlist.html', {'arg_list': arg_list, 'arg_params': arg_params, 'activemethod': activemethod, 'arg_rois': arg_rois, 'sampleframe': sampleframe})
+
+def updateparams(request):
+	arg_list = MethodArgument.objects.filter(method__modulename=request.GET['activemodulename'], method__name=request.GET['activemethodname'])
+	activetype = ImageType.objects.get(name=request.GET['activetype'])
+	activemethod = ProcessingMethod.objects.get(modulename = request.GET['activemodulename'], name=request.GET['activemethodname'])
+	
+	roi_dict = json.loads(request.GET['rois'])
+	
+	for arg in arg_list:
+		if arg.name in request.GET:
+			if request.GET[arg.name] != '':
+				try:
+					param = TypeParameters.objects.get(imagetype = activetype, methodargument=arg)	
+					param.value=request.GET[arg.name]
+				except TypeParameters.DoesNotExist:
+					param = TypeParameters.objects.create(imagetype = activetype, methodargument=arg, value=request.GET[arg.name])					
+				param.save()	
+		if arg.name in roi_dict:						
+				try:
+					roi = TypeROI.objects.get(imagetype = activetype, methodargument=arg)					
+				except TypeROI.DoesNotExist:
+					roi = TypeROI.objects.create(imagetype = activetype, methodargument=arg)	
+					
+				roi.x1 = roi_dict[arg.name][0]
+				roi.y1 = roi_dict[arg.name][1]
+				roi.x2 = roi_dict[arg.name][2]				
+				roi.y2 = roi_dict[arg.name][3]
+				roi.save()	
+	return HttpResponse("Success.")
+
+def processtype(request):
+	activetype = ImageType.objects.get(name=request.GET['activetype'])
+	activetype.ClearProcessed()
+	activetype.ProcessType()
+	return HttpResponse("Success.")
+
+def isnumber(s):
+	try:
+		float(s)
+		return True
+	except ValueError:
+		return False
+
+def filteredlist(request, url): 
+	q=RunLogInfo.objects.all()
+	
+	if request.GET['name'] != "":
+		q=q.filter(sequencepath__contains=request.GET['name'])
+	if request.GET['description'] != "":
+		q=q.filter(description__contains=request.GET['description'])
+	if request.GET['starttime'] != "":
+		q=q.filter(time__gt=datetime.datetime.strptime(request.GET['starttime'],"%m/%d/%Y %H:%M:%S"))
+	if request.GET['endtime'] != "":
+		q=q.filter(time__lt=datetime.datetime.strptime(request.GET['endtime'],"%m/%d/%Y %H:%M:%S"))
+	if request.GET['varname'] != "":
+		if request.GET['varcomp'] == "ex":
+			q=q.filter(variablevalue__name__contains=request.GET['varname'])
+		elif isnumber(request.GET['varvalue']):
+		        if request.GET['varcomp'] == "lt":
+				q=q.filter(variablevalue__name__contains=request.GET['varname'], variablevalue__value__lt=float(request.GET['varvalue']))
+			elif request.GET['varcomp'] == "eq":
+				q=q.filter(variablevalue__name__contains=request.GET['varname'], variablevalue__value__eq=float(request.GET['varvalue']))
+		        elif request.GET['varcomp'] == "gt":
+				q=q.filter(variablevalue__name__contains=request.GET['varname'], variablevalue__value__gt=float(request.GET['varvalue']))
+	return render_to_response('runloglist.html', {'runlog_list': q})
+
+def countsample(request):	
+	imgcount=ImageInfo.objects.filter(imgtype__name=request.GET['txttype']).count()
+	return HttpResponse(str(imgcount))
+
+def getsample(request):
+	samplecount=int(request.GET['samplecount'])
+	sampleimage=ImageInfo.objects.filter(imgtype__name=request.GET['activetype'])[samplecount-1]
+	return render_to_response('sampleimages.html', {'sampleimage': sampleimage})
+
+def setsample(request):
+	activetype = ImageType.objects.get(name=request.GET['activetype'])
+	src = RawFrame.objects.get(pngurl=request.GET['src'])
+	activetype.sample = src
+	activetype.save()
+	return HttpResponse("Success.")
+
+
+	
+
+	
+	
+	
+
+
+
+
+		
+
+		
+		
+	        
diff --git a/htroot/filter.htm b/htroot/filter.htm
new file mode 100644
index 0000000..214a6c7
--- /dev/null
+++ b/htroot/filter.htm
@@ -0,0 +1,54 @@
+ <html>                                                                  
+ <head>  
+ <link type="text/css" href="css/ui-lightness/jquery-ui-1.8.14.custom.css" rel="stylesheet" />	                                                                
+ <script type="text/javascript" src="./js/jquery.js"></script>   
+ <script type="text/javascript" src="./js/jquery-ui.js"></script>
+ <script type="text/javascript" src="./js/jquery-ui-timepicker.js"></script>        
+ <script type="text/javascript">                                         
+$(function() {
+		$("#starttime" ).datetimepicker();
+		$('#endtime').datetimepicker();		
+});
+
+$(document).ready(function() {	
+	$('#filters').submit(function(event) {
+		event.preventDefault();
+		
+		var values = $('form').serialize();
+		
+		$.get("http://bec2.mit.edu/django/clinamen/filters/filter", values, function(data){
+      		$('#results').html(data);
+   		});
+
+		//alert(values);
+		//$('#results').load('test.html');
+	});
+});
+
+
+</script>                                                             
+ </head>                                                                 
+ <body>                                                                  
+ 	
+<div>
+<form id="filters">
+<p>Start Time: <input name="starttime" id="starttime" type="text"></p>
+<p>End Time: <input name="endtime" id="endtime" type="text"></p>
+<p>Sequence Name Contains: <input name="name" id="name" type="text"></p>
+<p>Description Contains: <input name="description" id="description" type="text"></p>
+<p>Variable Name Contains: <input name="varname" id="varname" type="text"> and 
+	<select name="varcomp" id="varcomp">
+		<option value="ex">exists</option>
+		<option value="gt">is greater than</option>
+		<option value="eq">is equal to</option>
+		<option value="lt">is less than</option>
+	</select>
+<input name="varvalue" id="varvalue" type="text">
+</p>
+<p><input type="submit" value="Search"><input type="reset"></p>
+</form>   
+</div>       
+<hr>   
+<div id="results"><p></p></div>      
+</body>                                                                 
+</html>
\ No newline at end of file
diff --git a/htroot/processing.htm b/htroot/processing.htm
new file mode 100644
index 0000000..0e02d6f
--- /dev/null
+++ b/htroot/processing.htm
@@ -0,0 +1,221 @@
+<html>                                                                  
+<head>  
+<link type="text/css" href="css/ui-lightness/jquery-ui-1.8.14.custom.css" rel="stylesheet" />
+<link rel="stylesheet" type="text/css" href="css/imgareaselect-default.css" />	                                                                
+<script type="text/javascript" src="./js/jquery.js"></script>   
+<script type="text/javascript" src="./js/jquery-ui.js"></script>     
+<script type="text/javascript" src="./scripts/jquery.imgareaselect.pack.js"></script>   
+<script type="text/javascript">                                         
+
+$(document).ready(function(){
+	window.rois = {};
+	window.sample ={};
+	window.sample.count = 1;
+	window.sample.countmin = 1;
+	window.sample.countmax = 10;
+	
+	$('#between').html(window.sample.count);
+	
+	$('#gettype').click(function(event){	
+		event.preventDefault();
+		
+		var values = $('form').serialize();
+	
+		var jqhr=$.get("../django/clinamen/imgproc/countsample", values, function(data){
+     		window.sample.countmax=parseInt(data);
+		})
+	
+		var jqhr=$.get("../django/clinamen/imgproc/methodlist", values, function(data){
+     		$('#methods').html(data);
+		})
+		.complete(function() {
+			loadmethods();
+			updatesamples(); 
+		});
+	});	
+	
+	$('#prevsample').click(function(event){
+		if (window.sample.count - 1 >= window.sample.countmin)
+		{
+		window.sample.count = window.sample.count - 1;
+		}
+		$('#between').html(window.sample.count);
+		updatesamples();
+	});		
+	
+	$('#nextsample').click(function(event){
+		if (window.sample.count +1 <= window.sample.countmax)
+		{
+		window.sample.count = window.sample.count + 1;
+		}
+		$('#between').html(window.sample.count);
+		updatesamples();
+	});
+});
+
+function updatesamples() 
+{
+	var jqhr=$.get("../django/clinamen/imgproc/getsample.html",
+	{activetype: $('#activetype').attr('data-activetype'), samplecount: window.sample.count}, function(data){
+    	$('#sample').html(data);
+   	})
+   	.complete(function() {loadsamples();});
+}
+
+function updaterois()
+{
+	$('$img[name|="roi"]').each(function(index) {
+		if (this.getAttribute('data-roi') != '') {	
+			var this_roi = JSON.parse(this.getAttribute('data-roi'));
+			$(this).imgAreaSelect({handles: true, x1: this_roi.x1, y1: this_roi.y1, x2: this_roi.x2, y2: this_roi.y2, 
+				onSelectEnd: function (img, selection) { 
+					window['rois'][img.getAttribute('data-arg')] = new Array(selection.x1, selection.y1, selection.x2, selection.y2);
+				}
+			});
+		} else {
+			$(this).imgAreaSelect({handles: true, 
+				onSelectEnd: function (img, selection) { 
+					window['rois'][img.getAttribute('data-arg')] = new Array(selection.x1, selection.y1, selection.x2, selection.y2);
+				}
+			});
+		}		  
+  	});
+}
+
+function loadmethods()
+{
+	$('#addmethod').click(function(event) {		
+		var jqhr=$.get("../django/clinamen/imgproc/add.html",
+		{activetype: $('#activetype').attr('data-activetype'), modulename:$('#methodlist option:selected').attr('data-modulename'),
+		methodname:$('#methodlist option:selected').attr('data-methodname')}, function(data){
+     		$('#methods').html(data);
+   		})
+   		.complete(function() {loadmethods();});
+	});
+	
+	$('$button[name|="remove"]').click(function(event) {
+		var jqhr=$.get("../django/clinamen/imgproc/remove.html",
+		{activetype: $('#activetype').attr('data-activetype'), modulename: this.getAttribute('data-modulename'),
+		 methodname: this.getAttribute('data-methodname')}, function(data){
+      		$('#methods').html(data);
+      		$('#parameters').html("");
+   		})
+   		.complete(function() {loadmethods();});
+	});
+	
+	$('$button[name|="edit"]').click(function(event) {
+		var jqhr=$.get("../django/clinamen/imgproc/edit.html", 
+		{activetype: $('#activetype').attr('data-activetype'), modulename: this.getAttribute('data-modulename'), 
+		methodname: this.getAttribute('data-methodname')}, function(data){
+    		$('#parameters').html(data);
+		})
+		.complete(function() {
+			loadparams();
+		});
+	});
+	
+	$('#processtype').click(function(event) {		
+		var jqhr=$.get("../django/clinamen/imgproc/process.html",
+		{activetype: $('#activetype').attr('data-activetype')}, function(data){})
+   		.complete(function() {});
+	});
+	
+}
+
+function loadparams()
+{
+	$('#update').click(function(event) {
+		var values = $('form').serialize(); 
+		values = values + '&' + $.param({activetype: $('#activetype').attr('data-activetype'),
+		activemodulename:$('#activemethod').attr('data-modulename'), activemethodname:$('#activemethod').attr('data-methodname')}) +
+		'&rois=' + JSON.stringify(window['rois']);		
+		var jqhr=$.get("../django/clinamen/imgproc/update.html", values, function(data){		
+		})
+		.complete(function() {});
+	});
+	
+	updaterois();
+}
+
+function loadsamples()
+{
+	$('$img[name|="sample"]').click(function(event) {
+		var jqhr=$.get("../django/clinamen/imgproc/setsample.html", 
+		{activetype: $('#activetype').attr('data-activetype'), src: this.getAttribute('src')}, function(data){})
+		.complete(function() {});
+	});			
+}
+
+function loaditems()
+{
+	$('#addmethod').click(function(event) {		
+		var jqhr=$.get("../django/clinamen/imgproc/add.html",
+		{activetype: $('#activetype').attr('data-activetype'), modulename:$('#methodlist option:selected').attr('data-modulename'),
+		methodname:$('#methodlist option:selected').attr('data-methodname')}, function(data){
+     		$('#methods').html(data);
+   		})
+   		.complete(function() {loaditems();});
+	});
+	
+	$('#update').click(function(event) {
+		var values = $('form').serialize(); 
+		values = values + '&' + $.param({activetype: $('#activetype').attr('data-activetype'),
+		activemodulename:$('#activemethod').attr('data-modulename'), activemethodname:$('#activemethod').attr('data-methodname')}) +
+		'&rois=' + JSON.stringify(window['rois']);		
+		var jqhr=$.get("../django/clinamen/imgproc/update.html", values, function(data){		
+		})
+		.complete(function() {loaditems();});
+	});
+	
+	$('$button[name|="remove"]').click(function(event) {
+		var jqhr=$.get("../django/clinamen/imgproc/remove.html",
+		{activetype: $('#activetype').attr('data-activetype'), modulename: this.getAttribute('data-modulename'),
+		 methodname: this.getAttribute('data-methodname')}, function(data){
+      		$('#methods').html(data);
+      		$('#parameters').html("");
+   		})
+   		.complete(function() {loaditems();});
+	});
+	
+	$('$button[name|="edit"]').click(function(event) {
+		var jqhr=$.get("../django/clinamen/imgproc/edit.html", 
+		{activetype: $('#activetype').attr('data-activetype'), modulename: this.getAttribute('data-modulename'), 
+		methodname: this.getAttribute('data-methodname')}, function(data){
+    		$('#parameters').html(data);
+		})
+		.complete(function() {
+			loaditems();
+			updaterois();
+		});
+	});
+	
+	$('$img[name|="sample"]').click(function(event) {
+		var jqhr=$.get("../django/clinamen/imgproc/setsample.html", 
+		{activetype: $('#activetype').attr('data-activetype'), src: this.getAttribute('src')}, function(data){})
+		.complete(function() {loaditems();});
+	});		
+}
+</script>                                                             
+</head>                                                                 
+<body>                                                                  
+ 	
+<div>
+<form id="imagetypeform">
+	<p><b>Image Type:</b> <input name="txttype" id="txttype" type="text"></p>
+	<p><input type="button" name="gettype" id="gettype" value="Find Type"></p>	
+	
+	<hr>
+	<div id="methods"><p></p></div>
+	
+	<hr>
+	<div id="parameters"><p></p></div>
+	
+	<hr> 
+	<div id="sampleform"> </div>
+	<input type="button" id="prevsample" value="<"><span id='between'></span><input type="button" id="nextsample" value=">">
+	
+	<div id="sample"></div>
+	
+</form>        
+</body>                                                            
+</html>
\ No newline at end of file
diff --git a/settings.py b/settings.py
new file mode 100644
index 0000000..ad1c082
--- /dev/null
+++ b/settings.py
@@ -0,0 +1,98 @@
+# Django settings for clinamen project.
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+    # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+        'NAME': 'filelist',                      # Or path to database file if using sqlite3.
+        'USER': 'root',                      # Not used with sqlite3.
+        'PASSWORD': 'w0lfg4ng',                  # Not used with sqlite3.
+        'HOST': 'localhost',                      # Set to empty string for localhost. Not used with sqlite3.
+        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
+    }
+}
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# On Unix systems, a value of None will cause Django to use the same
+# timezone as the operating system.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'America/Chicago'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# If you set this to False, Django will not format dates, numbers and
+# calendars according to the current locale
+USE_L10N = True
+
+# Absolute filesystem path to the directory that will hold user-uploaded files.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = './static/'
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+MEDIA_URL = 'static/'
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/media/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = '81_-&kt2=s7*u!xs40vgxp%rv^7k=*a(z23g5a6w)%n0%_-sg^'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.Loader',
+    'django.template.loaders.app_directories.Loader',
+#     'django.template.loaders.eggs.Loader',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+)
+
+ROOT_URLCONF = 'clinamen.urls'
+
+TEMPLATE_DIRS = (
+    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+    # Always use forward slashes, even on Windows.
+    # Don't forget to use absolute paths, not relative paths.
+    "C:/django/django/clinamen/templates"
+)
+
+INSTALLED_APPS = (
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'django.contrib.messages',
+    'clinamen.filelist',
+    # Uncomment the next line to enable the admin:
+    # 'django.contrib.admin',
+    # Uncomment the next line to enable admin documentation:
+    # 'django.contrib.admindocs',
+)
diff --git a/templates/imglist.html b/templates/imglist.html
new file mode 100644
index 0000000..689ca2d
--- /dev/null
+++ b/templates/imglist.html
@@ -0,0 +1,24 @@
+<table border=1>
+<tr>
+<th>Image time
+<th>Processed frames
+<th>Raw frames
+</tr>
+{% for imginfo in img_list %}
+<tr>
+<td>{{imginfo.time|date:"M-d-Y H:i:s"}}
+<td>
+{% for thumbinfo in imginfo.thumbinfo_set.all %}
+{% if thumbinfo.framenumber < 0 %}
+<img src="{{thumbinfo.url}}" height=64 width=64>
+{% endif %}
+{% endfor %}  
+<td>
+{% for thumbinfo in imginfo.thumbinfo_set.all %}
+{% if thumbinfo.framenumber >= 0 %}
+<img src="{{thumbinfo.url}}" height=64 width=64>
+{% endif %}
+{% endfor %}  
+</tr>
+{% endfor %}
+</table>
\ No newline at end of file
diff --git a/templates/methodlist.html b/templates/methodlist.html
new file mode 100644
index 0000000..ba0907e
--- /dev/null
+++ b/templates/methodlist.html
@@ -0,0 +1,18 @@
+<div id="activetype" data-activetype={{activetype.name}}><b>Image type:</b> {{activetype.name}}</div>
+
+<p>Add a processing method: 
+<select id="methodlist">
+	{% for method in method_list %}
+		<option data-modulename="{{method.modulename}}" data-methodname="{{method.name}}" value="{{method.modulename}}___{{method.name}}">{{method.modulename}}::{{method.name}}</option>
+	{% endfor %}
+</select>	
+</p>
+<p><input type="button" name="addmethod" id="addmethod" value="Add this method"></p>
+
+<p>Active methods:</p>
+{% for method in active_list %}
+<p><b>Module name:</b> {{method.modulename}} <b>Function name:</b> {{method.name}} <input type="button" name="edit" data-modulename="{{method.modulename}}" data-methodname="{{method.name}}" value="Edit Parameters"><input type="button" name="remove" data-modulename="{{method.modulename}}" data-methodname="{{method.name}}" value="Remove method"></p>
+{% endfor %}
+
+<p><input type="button" name="processtype" id="processtype" value="Process this type"></p>
+
diff --git a/templates/paramlist.html b/templates/paramlist.html
new file mode 100644
index 0000000..5389631
--- /dev/null
+++ b/templates/paramlist.html
@@ -0,0 +1,15 @@
+<div id="activemethod" data-modulename={{activemethod.modulename}} data-methodname={{activemethod.name}}><b>Parameters for method:</b> {{activemethod.modulename}}.{{activemethod.name}}</div>
+
+{% for arg, value in arg_params.items %}
+<p>{{arg}}: <input type="text" name={{arg}} value={{value}}> 
+{% endfor %}
+
+{% for arg, value in arg_rois.items %}
+<p>{{arg}}: <img name="roi" data-arg="{{arg}}" data-roi="{{value}}" src={{sampleframe.pngurl}}> 
+{% endfor %}
+
+<p><input type="button" id="update" value="Update Values" name="update"></p>
+
+
+
+
diff --git a/templates/runloglist.html b/templates/runloglist.html
new file mode 100644
index 0000000..33d7469
--- /dev/null
+++ b/templates/runloglist.html
@@ -0,0 +1,47 @@
+<table border=1>
+<tr>
+<th>Run time
+<th>Sequence path
+<th>Duration
+<th>Description
+<th>Variables
+<th>Image time
+<th>Image type
+<th>Raw frames
+<th>Processed frames
+</tr>
+{% for runloginfo in runlog_list %}
+<tr>
+<td>{{runloginfo.time|date:"M-d-Y H:i:s"}}
+<td>{{runloginfo.sequencepath}}
+<td>{{runloginfo.sequenceduration}}
+<td>{{runloginfo.description}}
+<td>
+{% for varvalue in runloginfo.variablevalue_set.all %}
+{{varvalue.name}} = {{varvalue.value}} <BR>
+{% endfor %}
+<td>
+{% for imginfo in runloginfo.imageinfo_set.all|slice:":2" %}
+{{imginfo.time}}<BR>
+{% endfor %}  
+<td>
+{% for imginfo in runloginfo.imageinfo_set.all|slice:":2" %}
+{{imginfo.imgtype.name}}<BR>
+{% endfor %}  
+<td>
+{% for imginfo in runloginfo.imageinfo_set.all|slice:":2" %}
+{% for frameinfo in imginfo.rawframe_set.all %}
+<a href="{{frameinfo.pngurl}}"><img src="{{frameinfo.thumburl}}" height=64 width=64></a>
+{% endfor %}
+<BR>
+{% endfor %}  
+<td>
+{% for imginfo in runloginfo.imageinfo_set.all|slice:":2" %}
+{% for frameinfo in imginfo.processedframe_set.all %}
+<a href="{{frameinfo.pngurl}}"><img src="{{frameinfo.thumburl}}" height=64 width=64></a>
+{% endfor %}
+<BR>
+{% endfor %}  
+</tr>
+{% endfor %}
+</table>
\ No newline at end of file
diff --git a/templates/sampleimages.html b/templates/sampleimages.html
new file mode 100644
index 0000000..3d4d9a2
--- /dev/null
+++ b/templates/sampleimages.html
@@ -0,0 +1,3 @@
+{% for frameinfo in sampleimage.rawframe_set.all %}
+<img name="sample" src="{{frameinfo.pngurl}}">
+{% endfor %}
\ No newline at end of file
diff --git a/urls.py b/urls.py
new file mode 100644
index 0000000..7c42b64
--- /dev/null
+++ b/urls.py
@@ -0,0 +1,31 @@
+from django.conf.urls.defaults import *
+
+# Uncomment the next two lines to enable the admin:
+# from django.contrib import admin
+# admin.autodiscover()
+
+urlpatterns = patterns('',
+    (r'^clinamen/images/([A-Za-z]+)', 'clinamen.filelist.views.imagelist'),
+    (r'^clinamen/runlogs/([A-Za-z]+)', 'clinamen.filelist.views.runloglist'),
+    (r'^clinamen/filters/([A-Za-z]+)', 'clinamen.filelist.views.filteredlist'),
+    # Example:
+    # (r'^clinamen/', include('clinamen.foo.urls')),
+    
+    (r'^clinamen/imgproc/methodlist', 'clinamen.filelist.views.methodlist'),
+    (r'^clinamen/imgproc/remove', 'clinamen.filelist.views.removemethod'),
+    (r'^clinamen/imgproc/add', 'clinamen.filelist.views.addmethod'),
+    (r'^clinamen/imgproc/edit', 'clinamen.filelist.views.editparams'),
+    (r'^clinamen/imgproc/update', 'clinamen.filelist.views.updateparams'),
+    (r'^clinamen/imgproc/process', 'clinamen.filelist.views.processtype'),    
+    
+    (r'^clinamen/imgproc/countsample', 'clinamen.filelist.views.countsample'),
+    (r'^clinamen/imgproc/getsample', 'clinamen.filelist.views.getsample'),
+    (r'^clinamen/imgproc/setsample', 'clinamen.filelist.views.setsample'),
+
+    # Uncomment the admin/doc line below to enable admin documentation:
+    # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
+    # Uncomment the next line to enable the admin:
+    # (r'^admin/', include(admin.site.urls)),
+    (r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': 'static'}),
+)
\ No newline at end of file