Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
20733f0
Updated to opencv 3
Mamie Feb 15, 2016
912c8f9
Merge branch 'master' of https://github.com/bgrim/IPRO-Spring2016
Mamie Feb 15, 2016
0adc44f
display the SMILES string using pymol
Mamie Feb 15, 2016
0063d9b
add .gitignore file
Mamie Feb 15, 2016
ad5b829
untrack mol file
Mamie Feb 15, 2016
9d18b13
correct for ndarray index
Mamie Feb 25, 2016
1038791
Merge https://github.com/bgrim/IPRO-Spring2016
Mamie Feb 25, 2016
539699f
prototype for the front end web application
Mamie Mar 20, 2016
2aba9ef
uploaded detection code API and AngularJS front end application
Mamie Apr 5, 2016
4111cb4
Cleaned up unnecessary files
Mamie Apr 5, 2016
c4dacd8
Added files via upload
Aczopek Apr 5, 2016
8b540fd
Added files via upload
Aczopek Apr 6, 2016
9a67486
Added files via upload
Aczopek Apr 6, 2016
94dd2cb
Merge pull request #1 from Aczopek/master
Mamie Apr 6, 2016
2df6e7b
Delete template3.html
Aczopek Apr 12, 2016
a848206
Delete template4.html
Aczopek Apr 12, 2016
cbf6da2
Delete template22.html
Aczopek Apr 12, 2016
8a44758
Delete template2.html
Aczopek Apr 12, 2016
7bdbdd1
Delete index.html
Aczopek Apr 12, 2016
972709b
Delete template.html
Aczopek Apr 12, 2016
fa6fbe1
Delete app.js
Aczopek Apr 12, 2016
09d0a78
Added files via upload
Aczopek Apr 12, 2016
5939a00
Added files via upload
Aczopek Apr 12, 2016
83da5e7
Merge pull request #2 from Aczopek/master
Mamie Apr 12, 2016
e755927
feat: Add Procfile for Heroku deployment
Mamie Apr 17, 2016
c20bc89
fix: Include image location for rebuilding app
Mamie Apr 17, 2016
1e44593
feat: Include more problems for the app
Mamie Apr 17, 2016
585cc7b
fix: Correct the image path in script.js
Mamie Apr 18, 2016
2c98138
feat: Add Django1.3 API for detection
Mamie Apr 18, 2016
95a8b67
feat: Add user instructions
Mamie Apr 18, 2016
fe25014
chore: recompile the application
Mamie Apr 20, 2016
466f2d1
Merge branch 'master' of https://github.com/bgrim/IPRO-Spring2016
Mamie Apr 20, 2016
59cfdf3
fix: Separate SMILES display from pymol visualization
Mamie Apr 20, 2016
e561afc
fix: Separate SMILES display from pymol visualization
Mamie Apr 20, 2016
85a68fc
fix: Adapt the canvas size to frame size
Mamie Apr 21, 2016
8419a9e
Merge branch 'master' of https://github.com/Mamie/IPRO-Spring2016
Mamie Apr 21, 2016
ffd4342
Merge branch 'master' of https://github.com/bgrim/IPRO-Spring2016
Mamie Apr 21, 2016
25d0d93
Remove unnecessary files
Mamie May 2, 2016
b6bbcb7
doc: Add documentation
Mamie May 2, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.mol
32 changes: 27 additions & 5 deletions Live-LeastWorkingModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
import numpy as np
import sys
import math
import cirpy
import Visualization.query as query

def printHelpText():
print 'Welcome to our Least Working Program for IPRO 207 in Spring 2016'
#End Function printHelpText()

def distance3D(x,y):
def distance3D(x,y):
return ((1.0*x[0]-y[0])**2+(1.0*x[1]-y[1])**2+(1.0*x[2]-y[2])**2)**(0.5)
#End Function distance()
def distance2D(x,y):
Expand Down Expand Up @@ -41,7 +43,7 @@ def nearestNeighbor(colors, pixel):
d=distance3D(pixel, c)
if dist==-1 or d<dist:
dist = d
index = i
index = i
i=i+1
return index
#End Function nearestNeighbor()
Expand Down Expand Up @@ -76,7 +78,7 @@ def DFS(graph, vertexNames):
EDGE_REMOVAL_COUNTER=0
removeCycles(graph,vertexNames,seen,start,None)
ret=''
seen = [False]*len(graph)
seen = [False]*len(graph)
return recursiveDFS(graph, vertexNames, seen, start, None)
#End Function DFS(graph, vertexNames)

Expand Down Expand Up @@ -164,7 +166,7 @@ def recursiveDFS(graph, vertexNames, seen, cur, parent):
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2.putText(cimg, atomNames[color_index], (i[0],i[1]), cv2.FONT_HERSHEY_SIMPLEX,0.6,(255,255,255),2)
cv2.putText(cimg, atomNames[color_index], (i[0],i[1]), cv2.FONT_HERSHEY_SIMPLEX,0.6,(255,255,255),2)
#End for

#Mark Connections
Expand All @@ -191,7 +193,7 @@ def recursiveDFS(graph, vertexNames, seen, cur, parent):
cv2.imshow('Ball And Stick Tracker', cimg)
key = cv2.waitKey(50)
if key==-1: continue
if chr(key)=='q':
if chr(key)=='q':
quit=True
break
elif chr(key)=='s':
Expand All @@ -201,6 +203,26 @@ def recursiveDFS(graph, vertexNames, seen, cur, parent):
smile = DFS(graph, vertexNames)
print smile
print ''
elif chr(key)=='v': # visualization
print 'v was pressed'
print vertexNames
print graph
smile = DFS(graph, vertexNames)
print smile
print ''
if smile==None:
continue
molfile = query.MOL( smile )
if not molfile == None:
name = query.iupac( smile )
filename = name + '.mol' if not name==None else smile+'.mol'
print molfile
with open( filename, 'w') as infile:
infile.write( molfile )
quit=True

query.pymol_show( filename )
break
elif chr(key)=='x':
cv2.imwrite("out"+str(COUNTER)+".jpg",image)
COUNTER=COUNTER+1
Expand Down
Empty file added Visualization/__init__.py
Empty file.
Binary file added Visualization/__init__.pyc
Binary file not shown.
7 changes: 4 additions & 3 deletions Visualization/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ def pymol_show( infile ):
if not molfile == None:
name = iupac( args.SMILES )
filename = name + '.mol' if not name==None else args.SMILES+'.mol'
with open( filename, 'w+' ) as infile:
infile.write( molfile )
pymol_show( filename )
print molfile
#with open( filename, 'w+' ) as infile:
# infile.write( molfile )
#pymol_show( filename )
else:
print 'SMILES string cannot be resolved'

Expand Down
Binary file added Visualization/query.pyc
Binary file not shown.
3 changes: 3 additions & 0 deletions django13api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Django 1.3 Implementation of the OpenCV detection code

Deployed on pythonanywhere at this [url](https://brumebleu.pythonanywhere.com/detect/)
Empty file added django13api/__init__.py
Empty file.
Binary file added django13api/__init__.pyc
Binary file not shown.
Empty file added django13api/detect/__init__.py
Empty file.
Binary file added django13api/detect/__init__.pyc
Binary file not shown.
3 changes: 3 additions & 0 deletions django13api/detect/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.db import models

# Create your models here.
16 changes: 16 additions & 0 deletions django13api/detect/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".

Replace this with more appropriate tests for your application.
"""

from django.test import TestCase


class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
237 changes: 237 additions & 0 deletions django13api/detect/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
# Create your views here.
import json
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
import numpy as np
import urllib
import cv2
import math


class Detection(object):
def __init__(self, image):
self.image = image
self.array = np.array(image)
self.shape = image.shape
self.SMILES = None

self._circles = None
self._graph = []
self._vertexNames = []
self._atomNames = ['C', 'O', 'N', 'P', 'H']
self._colorNames = ['Black', 'Red', 'Blue','Purple','White']
self._colorsBGR = [[34,27,25], [70,25,155], [210,125,75], [165,80,95], [245,175,185]]
self._count = [0, 0, 0, 0, 0]
self._edgeRemovalCounter = 1

def resize(self, ratio):
self.image = cv2.resize(self.image, (0, 0), fx=ratio, fy=ratio)
self.shape = self.image.shape
self.array = np.array(self.image)
print 'Resized Image: ', self.shape

def detectModel(self):
#image = cv2.medianBlur(self.image, 3)
grayImg = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
self._circles = cv2.HoughCircles(grayImg, cv2.cv.CV_HOUGH_GRADIENT, 1, 30, param1=45, param2=25, minRadius=15, maxRadius=40)
print 'circles: ' + str(self._circles)
self._drawAtoms()
self._drawBonds()
print 'graph: ' + str(self._graph)
self.SMILES = self._DFS()

def writeImage(self, filename):
cv2.imwrite(filename, self.image)

def _drawAtoms(self):
if type(self._circles)=='NoneType':
return
else:
for circle in self._circles[0]:
circleColor = self._averageColor(int(circle[1]), int(circle[0]), 1)
colorIdx = self._nearestNeighbor(circleColor)
self._count[colorIdx] += 1
self._vertexNames.append(self._atomNames[colorIdx])
center = (int(round(circle[0])), int(round(circle[1])))
self.image = cv2.circle(self.image, center, int(round(circle[2])), (0, 255, 0), 2)
cv2.putText(self.image, self._colorNames[colorIdx], center, cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)

def _drawBonds(self):
if type(self._circles)=='NoneType':
return
for i in self._circles[0]:
adjList = []
counter = 0
for j in self._circles[0]:
if (i==j).all():
counter += 1
continue
if self._detectSingleBond(i, j):
adjList.append(counter)
self.image = cv2.line(self.image, (int(round(i[0])), int(round(i[1]))), (int(round(j[0])), int(round(j[1]))), (255, 0, 0), 3)
counter += 1
self._graph.append(adjList)

def _distance3D(self, x, y):
return ((1.0*x[0]-y[0])**2+(1.0*x[1]-y[1])**2+(1.0*x[2]-y[2])**2)**(0.5)

def _distance2D(self, x, y):
return ((1.0*x[0]-y[0])**2+(1.0*x[1]-y[1])**2)**(0.5)

def _averageColor(self, x, y, r):
total = [0,0,0]
count = 0
for dx in [-1*r, r]:
for dy in [-1*r, r]:
if x+dx <0: continue
if x+dx >= self.shape[0]: continue
if y+dy <0: continue
if y+dy >= self.shape[1]: continue
total[0] = total[0]+self.array[x+dx][y+dy][0]
total[1] = total[1]+self.array[x+dx][y+dy][1]
total[2] = total[2]+self.array[x+dx][y+dy][2]
count=count+1
total[0]=total[0]/count
total[1]=total[1]/count
total[2]=total[2]/count
return total

def _nearestNeighbor(self, pixel):
dist = -1
index=-1
i=0
for c in self._colorsBGR:
d = self._distance3D(pixel, c)
if dist==-1 or d<dist:
dist = d
index = i
i=i+1
return index

def _detectSingleBond(self, c1, c2):
distance = self._distance2D(c1,c2)
if distance>5*c1[2] or distance>5*c2[2]: return False
STEPS =25
PERCENT_SKIP=0.3
THRESHOLD=0.85
p1 = c1*PERCENT_SKIP + c2*(1-PERCENT_SKIP)
p2 = c2*PERCENT_SKIP + c1*(1-PERCENT_SKIP)
direction = p2-p1
count=0
for i in range(STEPS):
step = direction*i/STEPS
test = p1 + step
if abs(self._distance3D(self.array[int(math.floor(test[1]))][int(math.floor(test[0]))], [185,135,135]))<45:
count = count+1
return count>THRESHOLD

def _DFS(self):
if self._graph==None or self._graph==[]: return None
start = 0
while len(self._graph[start])==0:
start+=1
if start==len(self._graph): return None
seen = [False]*len(self._graph)
self._edgeRemovalCounter=0
self._removeCycles(seen,start,None)
ret=''
seen = [False]*len(self._graph)
return self._recursiveDFS(seen, start, None)

def _removeCycles(self, seen, cur, parent):
seen[cur] = True
for j in self._graph[cur]:
if j==parent:
continue
if seen[j]:
self._graph[cur].remove(j)
self._vertexNames[cur] += self._numberString(self._edgeRemovalCounter)
self._graph[j].remove(cur)
self._vertexNames[j] += self._numberString(self._edgeRemovalCounter)
self._edgeRemovalCounter += 1
continue
self._removeCycles(seen, j, cur)

def _numberString(self, i):
if i<10: return str(i)
return '%'+str(i)

def _recursiveDFS(self, seen, cur, parent):
#Assuming graph is acyclic
seen[cur] = True
ret = self._vertexNames[cur]
count=0
if parent==None: count=-1
for j in self._graph[cur]:
if j==parent:
continue
if seen[j]:
continue
count=count+1
if not count==len(self._graph[cur])-1:
ret=ret+'('
ret=ret+self._recursiveDFS(seen, j, cur)
if not count==len(self._graph[cur])-1:
ret=ret+')'
return ret


def macro(image, ratio):
model = Detection(image)
model.resize(ratio)
model.detectModel()
#model.writeImage("detected.jpg")
return model.SMILES

@csrf_exempt
def detect(request):
data = {"success": False}
if request.method == "POST":
print "POST method!"
if request.FILES.get("image", None) is not None:
print 'get image from stream'
image = _grab_image(stream=request.FILES["image"])
else:
print 'Not stream'
url = request.POST.get("url", None)
if url is None:
print 'No URL'
data["error"] = "No URL provided."
return HttpResponse(json.dumps(data), content_type='application/json')
image = _grab_image(url=url)
model = Detection(image)
model.resize(1.0)
print model.image
model.detectModel()
SMILES = model.SMILES
#SMILES = macro(image, 1.0)
if (not SMILES):
SMILES = 'None'
data.update({"SMILES": SMILES, "success": True})
return HttpResponse(json.dumps(data), content_type='application/json')


def _grab_image(path=None, stream=None, url=None):
# if the path is not None, then load the image from disk
if path is not None:
image = cv2.imread(path)

# otherwise, the image does not reside on disk
else:
# if the URL is not None, then download the image
if url is not None:
resp = urllib.urlopen(url)
data = resp.read()

# if the stream is not None, then the image has been uploaded
elif stream is not None:
data = stream.read()

# convert the image to a NumPy array and then read it into
# OpenCV format
image = np.asarray(bytearray(data), dtype="uint8")
image = cv2.imdecode(image, cv2.IMREAD_COLOR)

# return the image
return image

Binary file added django13api/detect/views.pyc
Binary file not shown.
14 changes: 14 additions & 0 deletions django13api/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env python2.7
from django.core.management import execute_manager
import imp
try:
imp.find_module('settings') # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
sys.exit(1)

import settings

if __name__ == "__main__":
execute_manager(settings)
Loading