Skip to content

Commit

Permalink
Merge pull request #11 from sightmachine/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
chaithuzz2 committed May 3, 2013
2 parents 15c24b4 + f8a175b commit bc7adf3
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
public/*

node_modules/*
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@

Currently a Skeleton

[***CHECK OUT THE LIVE DEMO (Chrome only!)***](http://demo.simplecv.org/)
[**CHECK OUT THE LIVE DEMO (Chrome only!)**](http://demo.simplecv.org/)

***Quick Start Guide***
## Requirements

_Note that this quickstart guide is tested and works for Ubuntu 12.4 LTS_
[Coffee Script](http://coffeescript.org/)
[Node.js](http://nodejs.org) ~ v0.6.10
[Node Package Manager](https://npmjs.org/)

* Install [brunch](https://github.com/brunch/coffee-script-brunch).
## Quick Start Guide

_Note that this quickstart guide is tested and works for Ubuntu 12.04 LTS_

* Install [brunch](http://brunch.io/).
* Install [coffe-script-brunch](https://github.com/brunch/coffee-script-brunch) which adds support for Coffee Script.
* Install a [coffee script](http://coffeescript.org/) build environment.
* _Optional_ Install [SimpleCV](https://github.com/ingenuitas/simplecv#installation) and its dependencies.
* _Optional_ Install [SimpleCV](https://github.com/sightmachine/simplecv#installation) and its dependencies.
* Run `npm install` to install missing dependencies
* Add the following command to your .bashrc file and source the file:
alias http "python -m SimpleHTTPServer"
* Run the following commands in the shell
Expand Down
245 changes: 218 additions & 27 deletions app/models/Image.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ module.exports = class Image extends Model
# Deletes a drawing layer from the image. Will
# shift the indices of subsequent drawing layers
# if they exist.
removeDrawingLayer:(layer=@layers.lenth-1) =>
removeDrawingLayer:(layer=@layers.length-1) =>
delete @layers[layer]
@layers.splice(layer, 1)

Expand Down Expand Up @@ -269,14 +269,14 @@ module.exports = class Image extends Model
return new Image(matrix)

# Return a gray matrix suitable for grayscale cv operations.
# getGrayArray:() =>
# matrix = @getArray();
# i = 0;
# while i < matrix.data.length
# avg = (matrix.data[i] + matrix.data[i+1] + matrix.data[i+2]) / 3
# matrix.data[i] = matrix.data[i+1] = matrix.data[i+2] = avg
# i += 4
# return matrix
getGrayArray:() =>
matrix = @getArray(); out = []
i = 0;
while i < matrix.data.length
avg = (matrix.data[i] + matrix.data[i+1] + matrix.data[i+2]) / 3
out.push avg
i += 4
return out

getGrayMatrix:() =>
result = []; x = [];
Expand Down Expand Up @@ -394,9 +394,9 @@ module.exports = class Image extends Model

merge:(r,g,b) =>
# Merge rgb images of the channels into one image
if( r.width is not @width and r.height is not @height and \
g.width is not @width and g.height is not @height and \
b.width is not @width and b.height is not @height )
if( r.width isnt @width or r.height isnt @height or \
g.width isnt @width or g.height isnt @height or \
b.width isnt @width or b.height isnt @height )
throw 'Sorry - I can\'t merge images of different sizes'

retVal = @getArray()
Expand Down Expand Up @@ -562,6 +562,19 @@ module.exports = class Image extends Model
d = Math.sqrt((xv.data[i]*xv.data[i])+(yv.data[i]*yv.data[i]))
out.data[i] = @clamp(d) # we reall should scale versus clamp
return new Image(out)

# Returns an object with both magnitudes and directions of its edges.
# More info at http://en.wikipedia.org/wiki/Sobel_operator#Formulation
getEdgesInfo:()=>
x = @sobelX().getArray()
y = @sobelY().getArray()
result = {}
result.magnitudes = []
result.directions = []
for i in [0..x.data.length]
result.magnitudes.push(Math.sqrt(Math.pow(x.data[i],2)+Math.pow(y.data[i],2)))
result.directions.push(Math.atan(y.data[i]/x.data[i]))
return result

sobelY:(grayscale=false)=>
kernel = [[-1.0,0.0,1.0],[-2.0,0.0,2.0],[-1.0,0.0,1.0]]
Expand Down Expand Up @@ -628,9 +641,8 @@ module.exports = class Image extends Model
clamp:(x,max=255,min=0) =>
return Math.max(min, Math.min(max, x))

cloneWithBorder:(borderSz) =>
#Add a border to the image for convoltuions etc
# this should be private
# Adds a border to the image for convolutions, etc
cloneWithBorder:(borderSz) ->
bpp = 4
oldSz = @width*@height*bpp
rgbBorderSz = bpp*borderSz
Expand All @@ -656,9 +668,8 @@ module.exports = class Image extends Model
rowStop = rowStop+update
return temp

cloneGrayWithBorder:(borderSz) =>
#Add a border to the image for convoltuions etc
# this should be private
# Adds a border to the image for convolutions, etc (grayscale)
cloneGrayWithBorder:(borderSz) ->
bpp = 4
oldSz = @width*@height*bpp
rgbBorderSz = bpp*borderSz
Expand All @@ -682,10 +693,8 @@ module.exports = class Image extends Model
rowStop = rowStop+update
return temp

cropBorderCopyGray:(img,borderSz) =>
# take a border image, crop out the border
# and return the image
# this should be a private function.
# Takes a border image, crops out the border and returns the image (grayscale)
cropBorderCopyGray:(img,borderSz) ->
bpp = 4
oldSz = @width*@height*bpp
rgbBorderSz = bpp*borderSz
Expand All @@ -711,11 +720,9 @@ module.exports = class Image extends Model
i = i + (2*borderSz)
rowStop = rowStop+update
return new Image(output)


# Takes a border image, crops out the border and returns the image
cropBorderCopy:(img,borderSz) =>
# take a border image, crop out the border
# and return the image
# this should be a private function.
bpp = 4
oldSz = @height*@width*bpp
rgbBorderSz = bpp*borderSz
Expand Down Expand Up @@ -849,5 +856,189 @@ module.exports = class Image extends Model
idx += 4
i += 4
retVal = new Image(dst)
return retVal
return retVal

canny:(highThreshold = 60, lowThreshold = 30, kernel_size = 5)=>
######################################################################################################################################
#The Canny edge detector is an edge detection operator that uses a multi-stage algorithm to detect a wide range of edges in images.
#The Algorithm is as follows
#1. Smooth the image with gaussian blur
#2. Obtain gradients in x and y directions by convoluting with sobel kernels
#3. Obtain edgestrengths G = ((G(x)^2+G(y)^2))^1/2 and edge directions theta = arctan(G(y)/G(x))
#4. After the above step we do something called non maximum suppression . i.e looking for peaks by comparing the edge strengths
# of the corresponding pixels in the 8-pixel neighbourhood.
#5. Now we have possible edge points and we also have false edge points that we dont really need. so as to obtain true edges
# we do double thresholding. we choose two threshold values highThreshold and lowThreshold. the peaks which are true and
# have corresponding edge strengths greater than highThreshold . they are marked true in the final edge matrix. the peaks which have
# edge strengths lower than lowThreshold are marked false and they are not included in the final edge matrix.
#6. The remaining peaks whose edge strengths are in betweeen highThreshold and lowThreshold we check the 8-pixel neighbourhood and if it has
# a true edge point in that area then we make it true. this is also known as edge linking.
#7. Finally we printout black pixel where final edge points dont exist (or false) and white pixel if they are true
#
#The arguments to this method are given below:
#
# highThreshold = the higher threshold value for high thresholding
#
# lowThreshold = the low threshold value for low thresholding
#
# kernel_size = the specified size for gaussian smoothing kernel , it must be odd.
######################################################################################################################################

blurIm = @blur(kernel_size,false)#smoothing the image to reduce noise
gradientX = blurIm.getGrayArray()#initializing gradient matrices for both x and y directions and temp matrices for convolution
tempX = blurIm.getGrayArray()
gradientY = blurIm.getGrayArray()
tempY = blurIm.getGrayArray()
kernelX = [[-1.0,0.0,1.0],[-2.0,0.0,2.0],[-1.0,0.0,1.0]]#the sobel kernels
kernelY = [[1.0,2.0,1.0],[0.0,0.0,0.0],[-1.0,-2.0,-1.0]]
for j in [1..@width-2] # convolution to obtain the gradients
for i in [1..@width-2] #
valsX = []
valsX.push(tempX[((j-1)*(@width))+((i+1))]*kernelX[2][0])
valsX.push(tempX[((j-1)*(@width))+((i ))]*kernelX[1][0])
valsX.push(tempX[((j-1)*(@width))+((i-1))]*kernelX[0][0])
valsX.push(tempX[((j)*(@width ))+ ((i+1))]*kernelX[2][1])
valsX.push(tempX[((j)*(@width ))+ ((i ))]*kernelX[1][1])
valsX.push(tempX[((j)*(@width ))+ ((i-1))]*kernelX[0][1])
valsX.push(tempX[((j+1)*(@width))+((i+1))]*kernelX[2][2])
valsX.push(tempX[((j+1)*(@width))+((i ))]*kernelX[1][2])
valsX.push(tempX[((j+1)*(@width))+((i-1))]*kernelX[0][2])
accX = 0
for v in valsX
accX += v
gradientX[(j*(@width))+(i)] = accX

valsY = []
valsY.push(tempY[((j-1)*(@width))+((i+1))]*kernelY[2][0])
valsY.push(tempY[((j-1)*(@width))+((i ))]*kernelY[1][0])
valsY.push(tempY[((j-1)*(@width))+((i-1))]*kernelY[0][0])
valsY.push(tempY[((j)*(@width ))+ ((i+1))]*kernelY[2][1])
valsY.push(tempY[((j)*(@width ))+ ((i ))]*kernelY[1][1])
valsY.push(tempY[((j)*(@width ))+ ((i-1))]*kernelY[0][1])
valsY.push(tempY[((j+1)*(@width ))+((i+1))]*kernelY[2][2])
valsY.push(tempY[((j+1)*(@width ))+((i ))]*kernelY[1][2])
valsY.push(tempY[((j+1)*(@width ))+((i-1))]*kernelY[0][2])
accY = 0
for v in valsY
accY += v
gradientY[(j*(@width))+(i)] = accY
edge_strength = []# initializing local matrices for use in the algorithm , edge_strength for calculationg edgestrengths
peaks = []# peaks for calculating the local maxima(possible edge points)
angle = []# angle for calculating the edge directions
x = [] #temporary arrays
inter = []
inter1 = []
for i in [0..@height-1]#pushing zeroes into peaks
for j in [0..@width-1]
x.push 0
peaks.push x
x = []
out = @getArray()#the original image characteistic array used for output
b = 0
for i in [0..@height-1]# calculation of edge strengths and pushing them into a temporary array and then pushing temp to edge_strength
for j in [0..@width-1]# calculation of edge directions and pushing them into a temp array and then pushing temp to angle
d = Math.sqrt((gradientX[b]*gradientX[b] + gradientY[b]*gradientY[b]))
s = Math.round(d)
inter.push s
if (gradientX[b] == 0)
if (gradientY[b] >= 0)
inter1.push 90
else
inter1.push -90
else
k = Math.atan((gradientY[b])/(gradientX[b]))*57.295
inter1.push k
b+= 1
edge_strength.push inter
angle.push inter1
inter = []
inter1 = []
for i in [1..@height-2]# non maximum suppression , we basically look for the pixels in the edge direction and compare with them
for j in [1..@width-2]#to obtain peaks
if(angle[i][j] < 22.5 and angle[i][j] >= -22.5)
if(edge_strength[i][j] > Math.max(edge_strength[i][j-1],edge_strength[i][j+1]))
peaks[i][j] = 1
else
peaks[i][j] = 0
if(angle[i][j] < 67.5 and angle[i][j] >= 22.5)
if(edge_strength[i][j] > Math.max(edge_strength[i+1][j-1],edge_strength[i-1][j+1]))
peaks[i][j] = 1
else
peaks[i][j] = 0
if(angle[i][j] < -22.5 and angle[i][j] >= -67.5)
if(edge_strength[i][j] > Math.max(edge_strength[i-1][j-1],edge_strength[i+1][j+1]))
peaks[i][j] = 1
else
peaks[i][j] = 0
else
if(edge_strength[i][j] > Math.max(edge_strength[i-1][j],edge_strength[i+1][j]))
peaks[i][j] = 1
else
peaks[i][j] = 0
y = []
final = [] #final array , used for final peaks after hysterisis thresholding
for i in [0..@height-1]
for j in [0..@width-1]
y.push 0
final.push y
y = []
for i in [1..@height-2]# high thresholding , marking all existing peaks in final false if they are lower than highThreshold
for j in [1..@width-2]# and true if they are higher than it
if(peaks[i][j] == 1 and edge_strength[i][j] > highThreshold)
peaks[i][j] = 0
final[i][j] = 1
if(peaks[i][j] == 0 and edge_strength[i][j] < lowThreshold)
peaks[i][j] = 0
final[i][j] = 0
flag = 1
while(flag == 1)# a simple way of low thresholding i.e for the values less than high threshold and greater than low threshold
flag = 0 # also known as edge linking
for i in [1..@height-2]
for j in [1..@width-2]
if (peaks[i][j] == 1)
for p in [-1..1]
for q in [-1..1]
if(final[i+p][j+q] == 1)
final[i][j] = 1
peaks[i][j] = 0
flag = 1
a = 0
for i in [0..@height-1]# if in final , it is true print white pixel there
for j in [0..@width-1]# and if its not true print black pixel
if (final[i][j] == 1)
out.data[a] = 255
out.data[a+1] = 255
out.data[a+2] = 255
else
out.data[a] = 0
out.data[a+1] = 0
out.data[a+2] = 0
a+= 4
return new Image(out)

#posterize effect(cartooning effect) http://en.wikipedia.org/wiki/Posterization
posterize:(adjust = 5)=>
numOfAreas = 256 / adjust
numOfValues = 255 / (adjust - 1)
out = @getArray()
posterize_LUT = @posterizeLUT(numOfAreas,numOfValues)
i = 0
while i < out.data.length
r = out.data[i]
g = out.data[i+1]
b = out.data[i+2]
out.data[i] = posterize_LUT[r]
out.data[i+1] = posterize_LUT[g]
out.data[i+2] = posterize_LUT[b]
i+=4
return new Image(out)

#look up table for posterize
posterizeLUT:(numOfAreas,numOfValues)=>
result = []
for i in [0..255]
k = Math.floor Math.floor(i / numOfAreas) * numOfValues
result.push k
return result


2 changes: 1 addition & 1 deletion app/views/templates/home.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<link href='http://fonts.googleapis.com/css?family=Montserrat+Alternates' rel='stylesheet' type='text/css'>

<a href="https://github.com/ingenuitas/simplecv-js"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"></a>
<a href="https://github.com/sightmachine/simplecv-js"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"></a>

<h1>SimpleCV.js</h1>
<h2>Computer Vision on the Web</h2>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"homepage": "http://simplecv.org",
"repository": {
"type": "git",
"url": "http://github.com/ingenuitas/simplecvjs"
"url": "http://github.com/sightmachine/simplecvjs"
},
"engines": {
"node": "~0.6.10"
Expand Down

0 comments on commit bc7adf3

Please sign in to comment.