{
"metadata": {
"name": "",
"signature": "sha256:4f8b5f43ecf881a5b8d923bb6df0a2d04857cbded4520e96972822dd3bcc1c63"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"-- **Adam Hughes** \n",
"\n",
"-- **2/27/14** \n",
"\n",
"-- **The George Washington University** "
]
},
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"Artificial SEM Images: Basic Operations and Noise"
]
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Objective"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Our task is to generate some test data for SEM images that can be used to test segmentation algorithm performance. "
]
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Environment Setup"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Configure notebook style (see NBCONFIG.ipynb), add imports and paths. The **%run** magic used below **requires IPython 2.0 or higher.**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%run NBCONFIG.ipynb\n",
"\n",
"from pyparty import Grid \n",
"from pyparty.utils import any2rgb"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Populating the interactive namespace from numpy and matplotlib\n"
]
},
{
"html": [
""
],
"metadata": {},
"output_type": "display_data",
"text": [
""
]
}
],
"prompt_number": 6
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, let's define several parameters to facilitate easy reuse:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"RESOLUTION = (1024, 1024) #Image resolution\n",
"DIAM_SINGLE = 30 #Particle Diameter in Pixels \n",
"BGGRAY = 128 #Light gray background\n",
"PCOLOR = 255 #White particles\n",
"NOISE_DENSITY = 0.15 #Percent noise"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 7
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"Step 1: Create a light-gray background; add particles"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"c = Canvas(rez=RESOLUTION, background=BGGRAY)\n",
"c.grid.xdiv = c.grid.ydiv=25 \n",
"\n",
"for (cx, cy) in c.gpairs('centers'):\n",
" c.add('circle', radius=DIAM_SINGLE/2, center=(cx,cy), color=PCOLOR)\n",
" \n",
"c.show(annotate=True);"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"\n",
"\n",
"\n",
"\n"
],
"text": [
""
]
}
],
"prompt_number": 8
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"Step 3: Add a constant and uneven contrast gradient using \"Grid\"."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Note**: We use any2rgb() to RGB-convert the background so that plotting doesn't try to normalize the colors."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def warped(xx, yy, power=1.0):\n",
" \"\"\" 2d function to generate uneven contrasts \"\"\"\n",
" return abs(np.cos(xx**power) + np.sin(yy**power))\n",
"\n",
"g1 = Grid(style='h', rez=RESOLUTION)\n",
"gradientbg = g1.blend_bg(c.image, weight=0.35)\n",
"gradientbg = any2rgb(gradientbg)\n",
"\n",
"g2 = Grid(rez=RESOLUTION)\n",
"g2.set_zfcn(warped)\n",
"warpedbg = g2.blend_bg(c.image, weight=0.25)\n",
"warpedbg = any2rgb(warpedbg)\n",
"\n",
"axes = splot(1,3, figsize=(9,6))\n",
"\n",
"IMAGES = [c.image, gradientbg, warpedbg]\n",
"\n",
"for (idx, img) in enumerate(IMAGES):\n",
" showim(img, 'gray', axes[idx]);"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stderr",
"text": [
"WARNING:pyparty.tools.grids:3-channel image convert to 8-bit uint\n"
]
},
{
"output_type": "stream",
"stream": "stderr",
"text": [
"WARNING:pyparty.utils: color has been converted (1-channel to 3-channel RGB)\n"
]
},
{
"output_type": "stream",
"stream": "stderr",
"text": [
"WARNING:pyparty.tools.grids:3-channel image convert to 8-bit uint\n"
]
},
{
"output_type": "stream",
"stream": "stderr",
"text": [
"WARNING:pyparty.utils: color has been converted (1-channel to 3-channel RGB)\n"
]
},
{
"metadata": {},
"output_type": "display_data",
"svg": [
"\n",
"\n",
"\n",
"\n"
],
"text": [
""
]
}
],
"prompt_number": 9
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"Step 4: Add some noise"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from pyparty.noise import salt, pepper, saltpepper, color, multicolor\n",
"\n",
"axes = splot(1,3, figsize=(9,6))\n",
"\n",
"for idx, img in enumerate(IMAGES):\n",
" noisyimg = salt(img, coverage=NOISE_DENSITY)\n",
" showim(noisyimg, 'gray', axes[idx])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"\n",
"\n",
"\n",
"\n"
],
"text": [
""
]
}
],
"prompt_number": 10
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Valid pyparty noise types are: \n",
"\n",
"- *salt* \n",
"- *pepper*\n",
"- *saltpepper*\n",
"- *color* (default = yellow)\n",
"- *multicolor*\n",
"- *normal*\n",
"\n",
"Where one color takes valid pyparty color (eg 'red', #0000FF, 230, (.5, .5, .5) ). Noise is always randomly distributed across the image. Multicolor noise is random 3-channel (r,g,b), where each channel is randomly chosen on 0-1 interval."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# Function that adds no noise: for plot 1\n",
"def nonoise(img, coverage): return img\n",
"\n",
"noisefcns = (nonoise, salt, pepper, saltpepper, color, multicolor)\n",
"axes = splot(2,3, figsize=(9,6))\n",
"\n",
"for idx, noisefcn in enumerate(noisefcns):\n",
" ax, title = axes[idx], noisefcn.__name__\n",
" showim(noisefcn(warpedbg, NOISE_DENSITY), ax, title=title);"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"\n",
"\n",
"\n",
"\n"
],
"text": [
""
]
}
],
"prompt_number": 11
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Part 2: Multi-particle species"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Some of the code below is a bit messy, but basically it's a lot of hoopla to randomly sample particles of normally-distributed diameters, at random orientation and ranging from singles, dimers, trimers and clusters."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"STD_DEV = 3 # pixels\n",
"PCOLOR = 200 #Single color"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 12
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import random\n",
"from random import choice\n",
"\n",
"COUNT = len(c.gpairs('centers'))\n",
"RAND_DIAM = np.random.normal(loc=DIAM_SINGLE, \n",
" scale=STD_DEV, size=2000)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 13
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def rint(x):\n",
" return int(round(x, 0))\n",
"\n",
"def rran(samples=1):\n",
" \"\"\" Pick a random radius from distribution. \"\"\"\n",
" out = [rint(choice(RAND_DIAM)/2.0) for i in range(samples)]\n",
" if len(out) == 1:\n",
" out = out[0]\n",
" return out\n",
"\n",
"def rphi():\n",
" return rint(random.random() * 360.0)\n",
"\n",
"def roverlap():\n",
" return 0 + (random.random() * .2 ) \n",
"\n",
"def populate_canvas(c):\n",
" for (cx, cy) in c.gpairs('centers'):\n",
" idx, pcolor = choice([(1, PCOLOR), (2, PCOLOR+15), (3, PCOLOR+35),(4, PCOLOR+55)])\n",
" shared = {'color':pcolor, 'center':(cx,cy), \n",
" 'phi':rphi(), 'overlap':roverlap()}\n",
"\n",
" if idx == 1:\n",
" c.add('circle', radius=rran(), **shared)\n",
" elif idx == 2:\n",
" c.add('dimer', *rran(2), **shared)\n",
" elif idx == 3:\n",
" c.add('trimer', *rran(3),**shared) \n",
" elif idx == 4:\n",
" c.add('tetramer', *rran(4), **shared) "
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 14
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"c.clear_particles()\n",
"c.grid.xdiv = c.grid.ydiv = 20\n",
"populate_canvas(c)\n",
"c.show();"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"\n",
"\n",
"\n",
"\n"
],
"text": [
""
]
}
],
"prompt_number": 15
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"MultiCanvas to manipulate the groups"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from pyparty import MultiCanvas\n",
"\n",
"mc = MultiCanvas.from_canvas(c)\n",
"mc.set_names('singles', 'dimers', 'trimers', 'tetramers')\n",
"mc.set_colors('r', 'g', 'y', 'magenta')\n",
"mc"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 16,
"text": [
"MultiCanvas (0x4da8050) 380: \n",
" singles - Canvas (0x1cd60890) : 1024 X 1024 : 94 particles \n",
" dimers - Canvas (0x9b25530) : 1024 X 1024 : 91 particles \n",
" trimers - Canvas (0x12533ef0) : 1024 X 1024 : 80 particles \n",
" tetramers - Canvas (0x12a90a10) : 1024 X 1024 : 115 particles"
]
}
],
"prompt_number": 16
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"ax1, ax2 = splot(1,2)\n",
"\n",
"mc.pie(ax1, autopct='both')\n",
"mc.hist(ax2, xlim='auto', bins=20);"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"\n",
"\n",
"\n",
"\n"
],
"text": [
""
]
}
],
"prompt_number": 17
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"clabeled = mc.to_canvas(mapcolors=True)\n",
"clabeled.background = 'black'\n",
"clabeled.show();"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"\n",
"\n",
"\n",
"\n"
],
"text": [
""
]
}
],
"prompt_number": 18
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"
\n",
"
\n",
"\n",
"\n",
"\n",
"

\n",
"
\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
" This notebook is free for redistribution. If citing, please reference as:
\n",
"- *Hughes, A. (2012). [A Computational Framework for Plasmonic Nanobiosensing](https://www.researchgate.net/publication/236672995_A_Computational_Framework_for_Plasmonic_Nanobiosensing). Python in Science Conference [SCIPY].* \n",
"\n",
"\n",
" Questions or Feedback?
\n",
"\n",
"* hugadams@gwmail.gwu.edu \n",
"* twitter: @hughesadam87\n",
"* Mark Reeves Biophysics Group\n",
"\n",
"\n",
"\n",
"\n",
" References:
\n",
"\n",
"* [1] : **REF 1**\n",
"* [2] : **REF 2**\n",
"\n",
"\n",
"\n",
"\n",
"\n",
" Related:
\n",
"\n",
" * pyuvvis: Exploratory Spectral Data Analysis\n",
" * pyparty: Image Analysis of Particles\n",
" * Lorena A. Barba (GWU Engineering)\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"Notebook styling ideas:
\n",
"\n",
"* Louic's web blog\n",
"* Plotly\n",
"* Publication-ready the first time: Beautiful, reproducible plots with Matplotlib\n",
"\n",
"
\n",
"
"
]
}
],
"metadata": {}
}
]
}