|
3 | 3 | {
|
4 | 4 | "cell_type": "code",
|
5 | 5 | "execution_count": null,
|
6 |
| - "metadata": { |
7 |
| - "collapsed": true |
8 |
| - }, |
| 6 | + "metadata": {}, |
9 | 7 | "outputs": [],
|
10 | 8 | "source": [
|
11 | 9 | "%matplotlib inline\n",
|
|
212 | 210 | "source": [
|
213 | 211 | "# Same as above, using a convolution kernel\n",
|
214 | 212 | "# Neighboring pixels multiplied by 1/3 and summed\n",
|
215 |
| - "mean_kernel3 = np.full(3, 1/3)\n", |
| 213 | + "mean_kernel3 = np.full((3,), 1/3)\n", |
216 | 214 | "smooth_signal3p = np.convolve(noisy_signal, mean_kernel3,\n",
|
217 | 215 | " mode='valid')\n",
|
218 | 216 | "fig, ax = plt.subplots()\n",
|
|
222 | 220 | " np.allclose(smooth_signal3, smooth_signal3p))"
|
223 | 221 | ]
|
224 | 222 | },
|
| 223 | + { |
| 224 | + "cell_type": "code", |
| 225 | + "execution_count": null, |
| 226 | + "metadata": {}, |
| 227 | + "outputs": [], |
| 228 | + "source": [ |
| 229 | + "def convolve_demo(signal, kernel):\n", |
| 230 | + " ksize = len(kernel)\n", |
| 231 | + " convolved = np.correlate(signal, kernel)\n", |
| 232 | + " def filter_step(i):\n", |
| 233 | + " fig, ax = plt.subplots()\n", |
| 234 | + " ax.plot(signal, label='signal')\n", |
| 235 | + " ax.plot(convolved[:i+1], label='convolved')\n", |
| 236 | + " ax.legend()\n", |
| 237 | + " ax.scatter(np.arange(i, i+ksize),\n", |
| 238 | + " signal[i : i+ksize])\n", |
| 239 | + " ax.scatter(i, convolved[i])\n", |
| 240 | + " return filter_step\n", |
| 241 | + "\n", |
| 242 | + "from ipywidgets import interact, widgets\n", |
| 243 | + "\n", |
| 244 | + "i_slider = widgets.IntSlider(min=0, max=len(noisy_signal) - 3,\n", |
| 245 | + " value=0)\n", |
| 246 | + "\n", |
| 247 | + "interact(convolve_demo(noisy_signal, mean_kernel3),\n", |
| 248 | + " i=i_slider);" |
| 249 | + ] |
| 250 | + }, |
225 | 251 | {
|
226 | 252 | "cell_type": "markdown",
|
227 | 253 | "metadata": {},
|
|
235 | 261 | "metadata": {},
|
236 | 262 | "outputs": [],
|
237 | 263 | "source": [
|
238 |
| - "mean_kernel11 = np.full(11, 1/11)\n", |
| 264 | + "mean_kernel11 = np.full((11,), 1/11)\n", |
239 | 265 | "smooth_signal11 = np.convolve(noisy_signal, mean_kernel11,\n",
|
240 | 266 | " mode='valid')\n",
|
241 | 267 | "fig, ax = plt.subplots()\n",
|
242 | 268 | "ax.plot(smooth_signal11);"
|
243 | 269 | ]
|
244 | 270 | },
|
| 271 | + { |
| 272 | + "cell_type": "code", |
| 273 | + "execution_count": null, |
| 274 | + "metadata": {}, |
| 275 | + "outputs": [], |
| 276 | + "source": [ |
| 277 | + "i_slider = widgets.IntSlider(min=0, max=len(noisy_signal) - 11,\n", |
| 278 | + " value=0)\n", |
| 279 | + "\n", |
| 280 | + "interact(convolve_demo(noisy_signal, mean_kernel11),\n", |
| 281 | + " i=i_slider);" |
| 282 | + ] |
| 283 | + }, |
245 | 284 | {
|
246 | 285 | "cell_type": "markdown",
|
247 | 286 | "metadata": {},
|
|
275 | 314 | "source": [
|
276 | 315 | "But now we see edge effects on the ends of the signal...\n",
|
277 | 316 | "\n",
|
| 317 | + "This is because `mode='same'` actually pads the signal with 0s and then applies `mode='valid'` as before." |
| 318 | + ] |
| 319 | + }, |
| 320 | + { |
| 321 | + "cell_type": "code", |
| 322 | + "execution_count": null, |
| 323 | + "metadata": {}, |
| 324 | + "outputs": [], |
| 325 | + "source": [ |
| 326 | + "def convolve_demo_same(signal, kernel):\n", |
| 327 | + " ksize = len(kernel)\n", |
| 328 | + " padded_signal = np.pad(signal, ksize // 2,\n", |
| 329 | + " mode='constant')\n", |
| 330 | + " convolved = np.correlate(padded_signal, kernel)\n", |
| 331 | + " def filter_step(i):\n", |
| 332 | + " fig, ax = plt.subplots()\n", |
| 333 | + " x = np.arange(-ksize // 2,\n", |
| 334 | + " len(signal) + ksize // 2)\n", |
| 335 | + " ax.plot(signal, label='signal')\n", |
| 336 | + " ax.plot(convolved[:i+1], label='convolved')\n", |
| 337 | + " ax.legend()\n", |
| 338 | + " start, stop = i, i + ksize\n", |
| 339 | + " ax.scatter(x[start:stop]+1,\n", |
| 340 | + " padded_signal[start : stop])\n", |
| 341 | + " ax.scatter(i, convolved[i])\n", |
| 342 | + " ax.set_xlim(-ksize // 2,\n", |
| 343 | + " len(signal) + ksize // 2)\n", |
| 344 | + " return filter_step\n", |
| 345 | + "\n", |
| 346 | + "\n", |
| 347 | + "i_slider = widgets.IntSlider(min=0, max=len(noisy_signal)-1,\n", |
| 348 | + " value=0)\n", |
| 349 | + "\n", |
| 350 | + "interact(convolve_demo_same(noisy_signal, mean_kernel11),\n", |
| 351 | + " i=i_slider);" |
| 352 | + ] |
| 353 | + }, |
| 354 | + { |
| 355 | + "cell_type": "markdown", |
| 356 | + "metadata": {}, |
| 357 | + "source": [ |
278 | 358 | "**Exercise** Look up the documentation of `scipy.ndimage.convolve`. Apply the same convolution, but using a different `mode=` keyword argument to avoid the edge effects we see here."
|
279 | 359 | ]
|
280 | 360 | },
|
|
339 | 419 | },
|
340 | 420 | "outputs": [],
|
341 | 421 | "source": [
|
342 |
| - "result = np.convolve(step_signal, np.array([-1, 0, 1]),\n", |
343 |
| - " mode='valid')" |
| 422 | + "result_corr = np.correlate(step_signal, np.array([-1, 0, 1]),\n", |
| 423 | + " mode='valid')" |
| 424 | + ] |
| 425 | + }, |
| 426 | + { |
| 427 | + "cell_type": "code", |
| 428 | + "execution_count": null, |
| 429 | + "metadata": {}, |
| 430 | + "outputs": [], |
| 431 | + "source": [ |
| 432 | + "result_conv = np.convolve(step_signal, np.array([-1, 0, 1]),\n", |
| 433 | + " mode='valid')" |
344 | 434 | ]
|
345 | 435 | },
|
346 | 436 | {
|
|
355 | 445 | "source": [
|
356 | 446 | "fig, ax = plt.subplots()\n",
|
357 | 447 | "ax.plot(step_signal, label='signal')\n",
|
358 |
| - "ax.plot(result, linestyle='dashed', label='result')\n", |
| 448 | + "ax.plot(result_conv, linestyle='dashed', label='convolved')\n", |
| 449 | + "ax.plot(result_corr, linestyle='dashed', label='correlated',\n", |
| 450 | + " color='C3')\n", |
359 | 451 | "ax.legend(loc='upper left')\n",
|
360 |
| - "ax.margins(y=0.1)" |
| 452 | + "ax.margins(y=0.1) " |
361 | 453 | ]
|
362 | 454 | },
|
363 | 455 | {
|
364 | 456 | "cell_type": "markdown",
|
365 | 457 | "metadata": {},
|
366 | 458 | "source": [
|
367 |
| - "(This might look like the opposite to what you were expecting. For technical reasons, convolutions actually occur \"back to front\" between the input array and the kernel. Let's try the opposite kernel:)" |
368 |
| - ] |
369 |
| - }, |
370 |
| - { |
371 |
| - "cell_type": "code", |
372 |
| - "execution_count": null, |
373 |
| - "metadata": {}, |
374 |
| - "outputs": [], |
375 |
| - "source": [ |
376 |
| - "result2 = np.convolve(step_signal, np.array([1, 0, -1]),\n", |
377 |
| - " mode='valid')" |
378 |
| - ] |
379 |
| - }, |
380 |
| - { |
381 |
| - "cell_type": "code", |
382 |
| - "execution_count": null, |
383 |
| - "metadata": {}, |
384 |
| - "outputs": [], |
385 |
| - "source": [ |
386 |
| - "fig, ax = plt.subplots()\n", |
387 |
| - "ax.plot(result2);" |
| 459 | + "(For technical signal processing reasons, convolutions actually occur \"back to front\" between the input array and the kernel. Correlations occur in the signal order, so we'll use correlate from now on.)" |
388 | 460 | ]
|
389 | 461 | },
|
390 | 462 | {
|
|
395 | 467 | }
|
396 | 468 | },
|
397 | 469 | "source": [
|
398 |
| - "Whenever neighboring values are close, the filter response is close to 0. Right at the boundary of a step, we're subtracting a large value from a small value and and get a spike in the response. This spike \"identifies\" our edge." |
| 470 | + "Whenever neighboring values are close, the filter response is close to 0. Right at the boundary of a step, we're subtracting a small value from a large value and and get a spike in the response. This spike \"identifies\" our edge." |
399 | 471 | ]
|
400 | 472 | },
|
401 | 473 | {
|
|
418 | 490 | "metadata": {},
|
419 | 491 | "outputs": [],
|
420 | 492 | "source": [
|
421 |
| - "noisy_change = np.convolve(noisy_signal, np.array([1, 0, -1]))\n", |
| 493 | + "noisy_change = np.correlate(noisy_signal, np.array([-1, 0, 1]))\n", |
422 | 494 | "fig, ax = plt.subplots()\n",
|
423 | 495 | "ax.plot(noisy_signal, label='signal')\n",
|
424 | 496 | "ax.plot(noisy_change, linestyle='dashed', label='change')\n",
|
|
441 | 513 | "metadata": {},
|
442 | 514 | "outputs": [],
|
443 | 515 | "source": [
|
444 |
| - "mean_diff = np.convolve([1, 0, -1], [1/3, 1/3, 1/3], mode='full')\n", |
| 516 | + "mean_diff = np.correlate([-1, 0, 1], [1/3, 1/3, 1/3], mode='full')\n", |
445 | 517 | "print(mean_diff)"
|
446 | 518 | ]
|
447 | 519 | },
|
|
465 | 537 | "metadata": {},
|
466 | 538 | "outputs": [],
|
467 | 539 | "source": [
|
468 |
| - "smooth_change = np.convolve(noisy_signal, mean_diff,\n", |
469 |
| - " mode='same')\n", |
| 540 | + "smooth_change = np.correlate(noisy_signal, mean_diff,\n", |
| 541 | + " mode='same')\n", |
470 | 542 | "fig, ax = plt.subplots()\n",
|
471 | 543 | "ax.plot(noisy_signal, label='signal')\n",
|
472 | 544 | "ax.plot(smooth_change, linestyle='dashed', label='change')\n",
|
|
478 | 550 | "cell_type": "markdown",
|
479 | 551 | "metadata": {},
|
480 | 552 | "source": [
|
481 |
| - "**Exercise:** The Gaussian filter with $\\sigma=1$ is given by:\n", |
| 553 | + "**Exercise:** The Gaussian filter with variance $\\sigma^2$ is given by:\n", |
482 | 554 | "\n",
|
483 | 555 | "$$\n",
|
484 |
| - "k_i = \\frac{1}{\\sqrt{2\\pi}}\\exp{\\left(-\\frac{(x_i - x_0)^2}{2}\\right)}\n", |
| 556 | + "k_i = \\frac{1}{\\sqrt{2\\pi}\\sigma}\\exp{\\left(-\\frac{(x_i - x_0)^2}{2\\sigma^2}\\right)}\n", |
485 | 557 | "$$\n",
|
486 | 558 | "\n",
|
487 |
| - "1. Create this filter (for example, with width 9, center 4). (Plot it)\n", |
| 559 | + "1. Create this filter (for example, with width 9, center 4, sigma 1). (Plot it)\n", |
488 | 560 | "2. Convolve it with the difference filter (with appropriate mode). (Plot the result)\n",
|
489 | 561 | "3. Convolve it with the noisy signal. (Plot the result)"
|
490 | 562 | ]
|
|
494 | 566 | "execution_count": null,
|
495 | 567 | "metadata": {},
|
496 | 568 | "outputs": [],
|
497 |
| - "source": [] |
| 569 | + "source": [ |
| 570 | + "xi = np.arange(9)\n", |
| 571 | + "x0 = 9 // 2 # 4\n", |
| 572 | + "x = xi - x0\n", |
| 573 | + "... # complete this code" |
| 574 | + ] |
498 | 575 | },
|
499 | 576 | {
|
500 | 577 | "cell_type": "markdown",
|
|
682 | 759 | "\n",
|
683 | 760 | "%precision 2\n",
|
684 | 761 | "print(bright_square)\n",
|
685 |
| - "print(ndi.convolve(bright_square, mean_kernel))" |
| 762 | + "print(ndi.correlate(bright_square, mean_kernel))" |
686 | 763 | ]
|
687 | 764 | },
|
688 | 765 | {
|
|
795 | 872 | " slices = []\n",
|
796 | 873 | " for i, i_max in zip(center, xy_max):\n",
|
797 | 874 | " slices.append(slice(max(i - size, i_min), min(i + size + 1, i_max)))\n",
|
798 |
| - " return slices\n", |
| 875 | + " return tuple(slices)\n", |
799 | 876 | "\n"
|
800 | 877 | ]
|
801 | 878 | },
|
|
888 | 965 | "pixelated = image[::10, ::10]\n",
|
889 | 966 | "fig, (ax0, ax1) = plt.subplots(1, 2, figsize=(10, 5))\n",
|
890 | 967 | "ax0.imshow(image)\n",
|
891 |
| - "ax1.imshow(pixelated)" |
| 968 | + "ax1.imshow(pixelated) ;" |
892 | 969 | ]
|
893 | 970 | },
|
894 | 971 | {
|
|
912 | 989 | {
|
913 | 990 | "cell_type": "code",
|
914 | 991 | "execution_count": null,
|
915 |
| - "metadata": { |
916 |
| - "collapsed": true |
917 |
| - }, |
| 992 | + "metadata": {}, |
918 | 993 | "outputs": [],
|
919 | 994 | "source": [
|
920 | 995 | "from skimage import img_as_float\n",
|
|
968 | 1043 | },
|
969 | 1044 | "outputs": [],
|
970 | 1045 | "source": [
|
971 |
| - "filtered = ndi.convolve(pixelated, mean_kernel)\n", |
| 1046 | + "filtered = ndi.correlate(pixelated, mean_kernel)\n", |
972 | 1047 | "imshow_all(pixelated, filtered, titles=['pixelated', 'mean filtered'])"
|
973 | 1048 | ]
|
974 | 1049 | },
|
|
1040 | 1115 | "# Rename module so we don't shadow the builtin function\n",
|
1041 | 1116 | "from skimage import filters\n",
|
1042 | 1117 | "\n",
|
1043 |
| - "smooth_mean = ndi.convolve(bright_square, mean_kernel)\n", |
| 1118 | + "smooth_mean = ndi.correlate(bright_square, mean_kernel)\n", |
1044 | 1119 | "sigma = 1\n",
|
1045 | 1120 | "smooth = filters.gaussian(bright_square, sigma)\n",
|
1046 | 1121 | "imshow_all(bright_square, smooth_mean, smooth,\n",
|
|
1171 | 1246 | "execution_count": null,
|
1172 | 1247 | "metadata": {},
|
1173 | 1248 | "outputs": [],
|
1174 |
| - "source": [] |
| 1249 | + "source": [ |
| 1250 | + "... # add your plotting code here" |
| 1251 | + ] |
1175 | 1252 | },
|
1176 | 1253 | {
|
1177 | 1254 | "cell_type": "markdown",
|
|
1228 | 1305 | "outputs": [],
|
1229 | 1306 | "source": [
|
1230 | 1307 | "vertical_kernel = np.array([\n",
|
1231 |
| - " [1, 1, 1],\n", |
1232 |
| - " [0, 0, 0],\n", |
1233 |
| - " [-1, -1, -1]\n", |
| 1308 | + " [-1],\n", |
| 1309 | + " [ 0],\n", |
| 1310 | + " [ 1],\n", |
1234 | 1311 | "])\n",
|
1235 | 1312 | "\n",
|
1236 |
| - "gradient_vertical = ndi.convolve(pixelated.astype(float),\n", |
1237 |
| - " vertical_kernel)\n", |
| 1313 | + "gradient_vertical = ndi.correlate(pixelated.astype(float),\n", |
| 1314 | + " vertical_kernel)\n", |
1238 | 1315 | "fig, ax = plt.subplots()\n",
|
1239 | 1316 | "ax.imshow(gradient_vertical);"
|
1240 | 1317 | ]
|
|
1258 | 1335 | "- Compute the magnitude of the image gradient at each point: $\\left|g\\right| = \\sqrt{g_x^2 + g_y^2}$"
|
1259 | 1336 | ]
|
1260 | 1337 | },
|
| 1338 | + { |
| 1339 | + "cell_type": "code", |
| 1340 | + "execution_count": null, |
| 1341 | + "metadata": {}, |
| 1342 | + "outputs": [], |
| 1343 | + "source": [ |
| 1344 | + "... # add your horizontal and gradient magnitude code here" |
| 1345 | + ] |
| 1346 | + }, |
1261 | 1347 | {
|
1262 | 1348 | "cell_type": "markdown",
|
1263 | 1349 | "metadata": {
|
|
1374 | 1460 | "cell_type": "markdown",
|
1375 | 1461 | "metadata": {},
|
1376 | 1462 | "source": [
|
1377 |
| - "**Exercise: the simplest neural network.** Let's pretent we have an image and a \"ground truth\" image of what we want to detect:" |
| 1463 | + "**Exercise: the simplest neural network.** Let's pretend we have an image and a \"ground truth\" image of what we want to detect:" |
1378 | 1464 | ]
|
1379 | 1465 | },
|
1380 | 1466 | {
|
|
1592 | 1678 | "name": "python",
|
1593 | 1679 | "nbconvert_exporter": "python",
|
1594 | 1680 | "pygments_lexer": "ipython3",
|
1595 |
| - "version": "3.6.3" |
| 1681 | + "version": "3.7.3" |
1596 | 1682 | }
|
1597 | 1683 | },
|
1598 | 1684 | "nbformat": 4,
|
|
0 commit comments