From 7d0129d961e4574c708756290f959a56eaaa1ada Mon Sep 17 00:00:00 2001 From: kkangle Date: Thu, 16 Nov 2017 11:36:12 -0600 Subject: [PATCH] Add several missing introductions Added convolution, deconvolution and FFT to ops notebook. Added randomaccess overview to n-d image notebook. --- .../2_-_Introduction_to_ImageJ_Ops.ipynb | 424 ++++++++++++------ .../3_-_N-dimensional_image_processing.ipynb | 168 ++++--- 2 files changed, 381 insertions(+), 211 deletions(-) diff --git a/notebooks/1_-_Using_ImageJ/2_-_Introduction_to_ImageJ_Ops.ipynb b/notebooks/1_-_Using_ImageJ/2_-_Introduction_to_ImageJ_Ops.ipynb index ff357f12..d56f3c95 100644 --- a/notebooks/1_-_Using_ImageJ/2_-_Introduction_to_ImageJ_Ops.ipynb +++ b/notebooks/1_-_Using_ImageJ/2_-_Introduction_to_ImageJ_Ops.ipynb @@ -30,9 +30,7 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -75,9 +73,7 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -106,9 +102,7 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -138,9 +132,7 @@ { "cell_type": "code", "execution_count": 4, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -176,9 +168,7 @@ { "cell_type": "code", "execution_count": 5, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -214,9 +204,7 @@ { "cell_type": "code", "execution_count": 6, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -265,9 +253,7 @@ { "cell_type": "code", "execution_count": 8, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -354,9 +340,7 @@ { "cell_type": "code", "execution_count": 8, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -393,9 +377,7 @@ { "cell_type": "code", "execution_count": 9, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -459,9 +441,7 @@ { "cell_type": "code", "execution_count": 10, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -485,9 +465,7 @@ { "cell_type": "code", "execution_count": 10, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -521,9 +499,7 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -547,9 +523,7 @@ { "cell_type": "code", "execution_count": 11, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -584,9 +558,7 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -631,9 +603,7 @@ { "cell_type": "code", "execution_count": 16, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -702,9 +672,7 @@ { "cell_type": "code", "execution_count": 17, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -754,9 +722,7 @@ { "cell_type": "code", "execution_count": 18, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -789,9 +755,7 @@ { "cell_type": "code", "execution_count": 19, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -818,9 +782,7 @@ { "cell_type": "code", "execution_count": 20, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -845,9 +807,7 @@ { "cell_type": "code", "execution_count": 21, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -879,9 +839,7 @@ { "cell_type": "code", "execution_count": 21, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -912,9 +870,7 @@ { "cell_type": "code", "execution_count": 23, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -944,9 +900,7 @@ { "cell_type": "code", "execution_count": 24, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -980,9 +934,7 @@ { "cell_type": "code", "execution_count": 25, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1039,9 +991,7 @@ { "cell_type": "code", "execution_count": 29, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1102,9 +1052,7 @@ { "cell_type": "code", "execution_count": 30, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1148,9 +1096,7 @@ { "cell_type": "code", "execution_count": 31, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1232,9 +1178,7 @@ { "cell_type": "code", "execution_count": 32, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1263,9 +1207,7 @@ { "cell_type": "code", "execution_count": 29, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1294,9 +1236,7 @@ { "cell_type": "code", "execution_count": 35, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1350,12 +1290,17 @@ "Finally, let's take a special look at the Difference of Gaussians op, `filter.dog`:" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Image features" + ] + }, { "cell_type": "code", "execution_count": 36, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1387,6 +1332,239 @@ "[[\"dog\":dog, \"evalDoG\":evalDoG]]" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Convolution, deconvolution and Fourier transforms" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Convolution" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Convolution is a very helpful filter for many circumstances. Below is an example of how to use the convolution filter. " + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The method for the convolution\n" + ] + }, + { + "data": { + "text/html": [ + "
" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import net.imglib2.type.numeric.real.FloatType;\n", + "import net.imagej.ops.Op\n", + "\n", + "// create the sample image\n", + "base = ij.op().run(\"create.img\", [150, 100], new FloatType())\n", + "formula = \"p[0]^2 * p[1]\"\n", + "ij.op().image().equation(base, formula)\n", + "\n", + "// create kernel\n", + "kernel_small = ij.op().run(\"create.img\", [3,3], new FloatType())\n", + "kernel_big = ij.op().run(\"create.img\", [20,20], new FloatType())\n", + "\n", + "ij.op().image().equation(kernel_small, \"p[0]\")\n", + "ij.op().image().equation(kernel_big, \"p[0]\")\n", + "\n", + "// convolved\n", + "convolved_small = ij.op().filter().convolve(base, kernel_small)\n", + "convolved_big = ij.op().filter().convolve(base, kernel_big)\n", + "\n", + "println(\"The method for the convolution\" )\n", + "[base, kernel_small,kernel_big, convolved_small, convolved_big]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "ImageJ can automatically select which filter to use according to the size of kernel. If kernel is small enough, then NaiveF (brute force way, not efficent at all, but useful when kernel is small) is used, otherwise, fast fourier transforms is used." + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
net​.imagej​.ops​.filter​.convolve​.ConvolveNaiveF
net​.imagej​.ops​.filter​.convolve​.ConvolveFFTF
" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "op = ij.op().op(\"filter.convolve\", image, kernel_small)\n", + "op2 = ij.op().op(\"filter.convolve\", image, kernel_big)\n", + "\n", + "[op.getClass().getName(), op2.getClass().getName()]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Deconvolution" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Deconvolution in ImageJ is implemented using RichardsonLucy algorithm. (Link to wiki https://en.wikipedia.org/wiki/Richardson%E2%80%93Lucy_deconvolution)" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import net.imagej.ops.Op\n", + "import net.imglib2.RandomAccessibleInterval\n", + "import net.imglib2.type.numeric.real.FloatType\n", + "import net.imglib2.util.Util\n", + "import net.imglib2.outofbounds.OutOfBoundsConstantValueFactory\n", + "import net.imglib2.RandomAccessibleInterval\n", + "import net.imagej.ops.deconvolve.RichardsonLucyF\n", + "\n", + "base_deconvolved = ij.op().run(RichardsonLucyF.class, convolved_small, kernel_small, null, new OutOfBoundsConstantValueFactory<>(Util.getTypeFromInterval(kernel_small).createVariable()), 10)\n", + "base_deconvolved_big = ij.op().run(RichardsonLucyF.class, convolved_big, kernel_big, null, new OutOfBoundsConstantValueFactory<>(Util.getTypeFromInterval(kernel_small).createVariable()), 10)\n", + "\n", + "[base_deconvolved, base_deconvolved_big]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fourier transforms" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fourier transform is very easy to use in ImageJ. With FFT ops, one can easily take an image as input and get result instantly." + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
original image \n", + "
" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import net.imglib2.RandomAccessibleInterval\n", + "import net.imglib2.type.numeric.real.FloatType\n", + "import net.imglib2.type.numeric.complex.ComplexFloatType\n", + "\n", + "// create image\n", + "fft_in = ij.op().run(\"create.img\", [150, 100], new FloatType())\n", + "formula = \"p[0]^2 + p[1]\"\n", + "ij.op().image().equation(fft_in, formula)\n", + "\n", + "// apply fft\n", + "fft_out = ij.op().run(\"filter.fft\", fft_in)\n", + "[\"original image \\n\" , fft_in]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The usage of Inverse FFT is very similar to FFT. Here we are going to invert the result we got from the above example." + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The result is the same as the orginal image\n" + ] + }, + { + "data": { + "text/html": [ + "
Inversed image
" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import net.imglib2.RandomAccessibleInterval\n", + "import net.imglib2.type.numeric.real.FloatType\n", + "\n", + "inverted = ij.op().run(\"create.img\", [150,100], new FloatType())\n", + "ij.op().filter().ifft(inverse, fft_out)\n", + "println(\"The result is the same as the original image\")\n", + "[\"Inverted image\", inverse]" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -1406,9 +1584,7 @@ { "cell_type": "code", "execution_count": 37, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1444,9 +1620,7 @@ { "cell_type": "code", "execution_count": 33, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1480,9 +1654,7 @@ { "cell_type": "code", "execution_count": 38, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1557,9 +1729,7 @@ { "cell_type": "code", "execution_count": 35, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1596,9 +1766,7 @@ { "cell_type": "code", "execution_count": 39, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1640,9 +1808,7 @@ { "cell_type": "code", "execution_count": 41, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1695,9 +1861,7 @@ { "cell_type": "code", "execution_count": 42, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1726,9 +1890,7 @@ { "cell_type": "code", "execution_count": 46, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1802,9 +1964,7 @@ { "cell_type": "code", "execution_count": 47, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1833,9 +1993,7 @@ { "cell_type": "code", "execution_count": 48, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1887,9 +2045,7 @@ { "cell_type": "code", "execution_count": 42, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1917,9 +2073,7 @@ { "cell_type": "code", "execution_count": 55, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -1988,9 +2142,7 @@ { "cell_type": "code", "execution_count": 56, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -2034,9 +2186,7 @@ { "cell_type": "code", "execution_count": 57, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -2083,9 +2233,7 @@ { "cell_type": "code", "execution_count": 58, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { diff --git a/notebooks/1_-_Using_ImageJ/3_-_N-dimensional_image_processing.ipynb b/notebooks/1_-_Using_ImageJ/3_-_N-dimensional_image_processing.ipynb index e5210c0e..cc3334d6 100644 --- a/notebooks/1_-_Using_ImageJ/3_-_N-dimensional_image_processing.ipynb +++ b/notebooks/1_-_Using_ImageJ/3_-_N-dimensional_image_processing.ipynb @@ -14,9 +14,9 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 54, "metadata": { - "collapsed": false + "scrolled": true }, "outputs": [ { @@ -25,7 +25,7 @@ "ImageJ is ready to go." ] }, - "execution_count": 19, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } @@ -82,10 +82,8 @@ }, { "cell_type": "code", - "execution_count": 20, - "metadata": { - "collapsed": false - }, + "execution_count": 55, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -103,7 +101,7 @@ "No Outputs" ] }, - "execution_count": 20, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } @@ -140,10 +138,8 @@ }, { "cell_type": "code", - "execution_count": 21, - "metadata": { - "collapsed": false - }, + "execution_count": 56, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -160,7 +156,7 @@ "No Outputs" ] }, - "execution_count": 21, + "execution_count": 56, "metadata": {}, "output_type": "execute_result" } @@ -202,10 +198,8 @@ }, { "cell_type": "code", - "execution_count": 22, - "metadata": { - "collapsed": false - }, + "execution_count": 57, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -232,7 +226,7 @@ "No Outputs" ] }, - "execution_count": 22, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } @@ -276,77 +270,105 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Accessing image samples directly" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "TODO `RandomAccessibleInterval`" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Convolution, deconvolution and Fourier transforms" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Convolution" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "TODO" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Deconvolution" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Fourier transforms" + "## Random Access Images" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Regions of interest (ROIs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Computational geometry" + "### Accessing image samples directly" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Machine learning with images" + "Sometimes you need to access samples in an order other than the natural one. This is possible as long as the image implements the `RandomAccessible` interface.\n", + "\n", + "By Using RandomAccessible, we can get access to any pixel of the image in any order.\n", + "\n", + "Here is an example of using randomaccess method." ] }, { - "cell_type": "markdown", - "metadata": {}, + "cell_type": "code", + "execution_count": 58, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Array image instanceof RandomAccessible? true\n", + "Cell image instanceof RandomAccessible? true\n" + ] + }, + { + "data": { + "text/html": [ + "
" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "### Image features" + "import net.imglib2.RandomAccessibleInterval\n", + "import net.imglib2.img.array.ArrayImgs\n", + "import net.imglib2.img.cell.CellImgFactory\n", + "import net.imglib2.type.numeric.integer.UnsignedByteType;\n", + "import net.imglib2.type.numeric.real.DoubleType;\n", + "\n", + "// create array image and cell image\n", + "long[] dims = [128,96]\n", + "arrayImg = ArrayImgs.unsignedBytes(dims);\n", + "cellImg = new CellImgFactory(1).create(dims, arrayImg.firstElement())\n", + "\n", + "// is the image RandomAccessible\n", + "println(\"Array image instanceof RandomAccessible? \" + (arrayImg instanceof RandomAccessibleInterval))\n", + "println(\"Cell image instanceof RandomAccessible? \" + (cellImg instanceof RandomAccessibleInterval))\n", + "\n", + "// start drawing\n", + "def drawimage(image){\n", + " ra = image.randomAccess()\n", + " ra.setPosition(15,0)\n", + " for (y in 15..45) {\n", + " ra.setPosition(y, 1)\n", + " UnsignedByteType t = ra.get()\n", + " t.set(255)\n", + " }\n", + "\n", + "\n", + " ra.setPosition(15,1)\n", + " for (x in 0..cellImg.dimension(0) - 1){\n", + " ra.setPosition(x, 0)\n", + " UnsignedByteType t = ra.get()\n", + " t.set(255)\n", + " }\n", + "\n", + " ra.setPosition(112, 0)\n", + " for (y in 15..45) {\n", + " ra.setPosition(y, 1)\n", + " UnsignedByteType t = ra.get()\n", + " t.set(255)\n", + " }\n", + "\n", + " ra.setPosition(80, 1)\n", + " for (x in 57..71){\n", + " ra.setPosition(x, 0)\n", + " UnsignedByteType t = ra.get()\n", + " t.set(255)\n", + " }\n", + "}\n", + "\n", + "drawimage(arrayImg)\n", + "drawimage(cellImg)\n", + "[arrayImg,cellImg]" ] } ],