Difference between revisions of "Pioneer21/Lecture03"

From PrattWiki
Jump to navigation Jump to search
(Created page with "This page serves as a supplement to the third group meeting of the Summer 2021 Pioneer program for image processing. == Python Requirements == The programs from this lecture...")
 
 
(3 intermediate revisions by the same user not shown)
Line 19: Line 19:
 
* <code>DATA = ski.data.NAME()</code> where DATA is a variable name you give to store the information from a built-in image and NAME is the name of a built-in image from scikit-image; the built-in images can be found in the Data section of the [https://scikit-image.org/docs/stable/auto_examples/index.html General Examples] page.
 
* <code>DATA = ski.data.NAME()</code> where DATA is a variable name you give to store the information from a built-in image and NAME is the name of a built-in image from scikit-image; the built-in images can be found in the Data section of the [https://scikit-image.org/docs/stable/auto_examples/index.html General Examples] page.
  
'''Starting on July 26, 2021, we will be using <code>AXIS.imshow(DATA)</code> instead of  <code>ski.io.imshow(DATA)</code> to display an image.'''
+
'''Starting on July 26, 2021, we will be using <code>AXIS.imshow(DATA)</code> instead of  <code>ski.io.imshow(DATA)</code> to display an image.  It looks like ski.io.imshow is going away.'''
  
 
Depending on the nature of an image, its DATA variable will be different shapes and contain different data types.  Here is how scikit-image and imshow() interpret things:
 
Depending on the nature of an image, its DATA variable will be different shapes and contain different data types.  Here is how scikit-image and imshow() interpret things:
Line 25: Line 25:
 
* A 3D-array will be interpreted as an RGB-based color image
 
* A 3D-array will be interpreted as an RGB-based color image
 
* For a 2D-array, the following data types and sizes might be useful:
 
* For a 2D-array, the following data types and sizes might be useful:
** An array of boolean (True or False) values or integer values with only integers 0 or 1 will produce an image with values at the extreme edges of the colormap.  By default in Python with matplotlib this is purple and gold. You can add some keyword arguments to the command to get black and white as follows:
+
** An array of boolean (True or False) values or integer values with only integers 0 or 1 will produce an image with values at the extreme edges of the colormap.  Assume that the code:<syntaxhighlight lang=python>
 +
bwimage = ski.data.binary_blobs()
 +
</syntaxhighlight>  has been run already for each of the cases below.  By default in Python with matplotlib this is purple and gold.
 
*** Default case with booleans <syntaxhighlight lang=python>
 
*** Default case with booleans <syntaxhighlight lang=python>
 
fig, ax = plt.subplots(num=1, clear=True)
 
fig, ax = plt.subplots(num=1, clear=True)
bwimage = ski.data.binary_blobs()
+
ax.imshow(bwimage)</syntaxhighlight> You can add some keyword arguments to the command to get black and white as follows:
ax.imshow(bwimage)</syntaxhighlight>
 
 
*** Black and white with booleans<syntaxhighlight lang=python>
 
*** Black and white with booleans<syntaxhighlight lang=python>
 
fig, ax = plt.subplots(num=1, clear=True)
 
fig, ax = plt.subplots(num=1, clear=True)
bwimage = ski.data.binary_blobs()
 
 
ax.imshow(bwimage, cmap=plt.cm.gray)</syntaxhighlight>
 
ax.imshow(bwimage, cmap=plt.cm.gray)</syntaxhighlight>
 
*** Black and white and no axis ticks with booleans<syntaxhighlight lang=python>
 
*** Black and white and no axis ticks with booleans<syntaxhighlight lang=python>
 
fig, ax = plt.subplots(num=1, clear=True)
 
fig, ax = plt.subplots(num=1, clear=True)
bwimage = ski.data.binary_blobs()
 
 
ax.imshow(bwimage, cmap=plt.cm.gray)
 
ax.imshow(bwimage, cmap=plt.cm.gray)
ax.set_axis_off()</syntaxhighlight>For each of the above, you can replace the array of booleans with an array of integers 0 or 1 by replacing the <code>bwimage</code> line with:<syntaxhighlight lang=python>
+
ax.set_axis_off()</syntaxhighlight>Note that for each of the above, you can replace the array of booleans with an array of integers 0 or 1 by replacing the <code>bwimage</code> line with:<syntaxhighlight lang=python>
 
bwimage = np.random.choice([0,1], (50,100))
 
bwimage = np.random.choice([0,1], (50,100))
 
</syntaxhighlight> or <syntaxhighlight lang=python>
 
</syntaxhighlight> or <syntaxhighlight lang=python>
 
bwimage = np.random.randint(0, 2, (50, 100))
 
bwimage = np.random.randint(0, 2, (50, 100))
 
</syntaxhighlight>  
 
</syntaxhighlight>  
** An array of integer values will produce an image with values mapped to the default Viridis (purple - green - blue - yellow) colormap.  You can add some keyword arguments to the command to get shades of gray as above:
+
** An array of integer values will produce an image with values mapped to the default Viridis (purple - green - blue - yellow) colormap.  Assume that the code:<syntaxhighlight lang=python>
 +
grayimage = ski.data.coins()
 +
</syntaxhighlight>  has been run already for each of the cases below.
 
*** Default case with integers <syntaxhighlight lang=python>
 
*** Default case with integers <syntaxhighlight lang=python>
 +
fig, ax = plt.subplots(num=1, clear=True)
 +
ax.imshow(grayimage)</syntaxhighlight> You can add some keyword arguments to the command to get shades of gray as above:
 +
*** Gray with integers <syntaxhighlight lang=python>
 +
fig, ax = plt.subplots(num=1, clear=True)
 +
ax.imshow(grayimage, cmap=plt.cm.gray)</syntaxhighlight>
 +
*** Gray and no axis ticks with integers<syntaxhighlight lang=python>
 +
fig, ax = plt.subplots(num=1, clear=True)
 +
ax.imshow(grayimage, cmap=plt.cm.gray)
 +
ax.set_axis_off()</syntaxhighlight>
 +
:::*'''Note 1''' - the addition of the colormap is required for using the axis version of imshow versus the scikit-image version of imshow.
 +
:::*'''Note 2''' - by default, imshow will stretch the range of integers to cover the whole map.  If you want to specifically map to a certain range - for instance, have 0 as pure black and 255 as pure white, you need to add <code>vmin</code> and <code>vmax</code> keyword arguments to explicitly give the values that map to the low and high end of the volormap.  For instance:<syntaxhighlight lang=python>
 
fig, ax = plt.subplots(num=1, clear=True)
 
fig, ax = plt.subplots(num=1, clear=True)
 
grayimage = ski.data.coins()
 
grayimage = ski.data.coins()
ax.imshow(grayimage)</syntaxhighlight>
+
ax.imshow(grayimage, cmap=plt.cm.gray, vmin=0, vmax=255))</syntaxhighlight> will produce the exact same image that ski.io.imshow(grayimage) would have produced. 
*** Gray with integers <syntaxhighlight lang=python>
+
** An array of floating-point values will also produce an image with values mapped to the default Viridis (purple - green - blue - yellow) colormap.  You can add some keyword arguments to the command to get shades of gray as above.  Assume that the code:<syntaxhighlight lang=python>
 +
x, y = np.meshgrid(np.linspace(-2, 2, 201), np.linspace(-1, 1, 101))
 +
z = np.exp(-np.sqrt(x**2+y**2))*np.cos(2*np.pi*x)*np.sin(4*np.pi*y)
 +
</syntaxhighlight>  has been run already for each of the cases below.
 +
*** Default case with floats<syntaxhighlight lang=python>
 +
fig, ax = plt.subplots(num=1, clear=True)
 +
ax.imshow(z)</syntaxhighlight>
 +
*** Gray with floats<syntaxhighlight lang=python>
 
fig, ax = plt.subplots(num=1, clear=True)
 
fig, ax = plt.subplots(num=1, clear=True)
 
grayimage = ski.data.coins()
 
grayimage = ski.data.coins()
 
ax.imshow(grayimage, cmap=plt.cm.gray)</syntaxhighlight>
 
ax.imshow(grayimage, cmap=plt.cm.gray)</syntaxhighlight>
*** Gray and no axis ticks with integers<syntaxhighlight lang=python>
+
*** Gray and no axis ticks with floats<syntaxhighlight lang=python>
 
fig, ax = plt.subplots(num=1, clear=True)
 
fig, ax = plt.subplots(num=1, clear=True)
 
grayimage = ski.data.coins()
 
grayimage = ski.data.coins()
 
ax.imshow(grayimage, cmap=plt.cm.gray)
 
ax.imshow(grayimage, cmap=plt.cm.gray)
ax.set_axis_off()</syntaxhighlight>*'''Note 1''' - the addition of the colormap is required for using the axis version of imshow versus the scikit-image version of imshow. *'''Note 2''' - by default, imshow will stratch the range of integers to cover the whole map.  If you want to specifically map to a certain range - for instance, have 0 as pure black and 255 as pure white, you need to add <code>vmin</code> and <code>vmax</code> keyword arguments to explicitly give the values that map to the low and high end of the volormap.  For instance:<syntaxhighlight lang=python>
+
ax.set_axis_off()</syntaxhighlight>
 +
:::*'''Note''' - once again, by default, imshow will stretch the range of floats to cover the whole map.  If you want to specifically map to a certain range - for instance, have 0 as pure black and 0.2 as pure white, you need to add <code>vmin</code> and <code>vmax</code> keyword arguments to explicitly give the values that map to the low and high end of the colormap.  Anything below vmin will be mapped to the low color and anything above vmax will be mapped to the high.  For instance:<syntaxhighlight lang=python>
 
fig, ax = plt.subplots(num=1, clear=True)
 
fig, ax = plt.subplots(num=1, clear=True)
grayimage = ski.data.coins()
+
ax.imshow(z, vmin=0, vmax=255))</syntaxhighlight> will produce an image with yellow rounded rectangles on a purple background with greenish-blue edges the further you get away from the center. The large all-yellow rectangles contain many values that are above 0.2 and the purple parts are all the negative parts of the array.
ax.imshow(grayimage, cmap=plt.cm.gray, vmin=0, vmax=255))
+
* For a 3D array, the third dimension should have three layers representing the red, green, and blue levels for each pixel. The entries either need to be integers between 0 and 255 or floating point numbers between 0 and 1. If the array contains values outside of those limits, strange things happen.
ax.set_axis_off()</syntaxhighlight> will produce the exact same image that ski.io.imshow(grayimage) would have produced.
 
 
 
<!--
 
== Image Processing Toolbox ==
 
For this lab, there are a few commands you will need to learn (or remember):
 
* <code>imread('filename.ext')</code> will load an image into MATLAB.  Depending on the image type, the return from this function may be a matrix of binary numbers (black and white images), an array of integers between 0 and 255 (grayscale images), or a three-layer matrix of integers between 0 and 255 (color images).
 
* <code>image(matrix)</code> will display the contents of a matrix as viewed from above.
 
** By default, the <code>image</code> command for a 1-layer matrix will assign colors based on a colormap that spans values from 0 to 255. Anything outside of that range will be clipped.
 
** There are ways to change that, but you will not need to for this lab
 
** The <code>image</code> command for a 3-layer matrix will assign colors based on the first layer being the red component, the second layer being the green component, and the third layer being the blue component.  
 
*** If the matrix is made up of floating-point numbers, <code>image</code> expects those numbers to be in the range [0, 1]
 
*** If the matrix is made up of unsigned integers, <code>image</code> expects those numbers to be in the range [0, 255]
 
*** If the matrix is made up of signed integers, <code>image</code> expects those numbers to be in the range [-128, 127]
 
* <code>imagesc(matrix)</code> for a one layer matrix will display the contents of a matrix as viewed from above and will also map the minimum value to "color 0" and the maximum value to "color 255"; for a three-layer matrix it will work just like <code>image</code>
 
* <code>colorbar</code> will add a...colorbar to the right of an image to show the numerical values and colors associated with them.  This is only useful for a one-layer image.
 
* <code>colormap MAP</code> will assign a particular colormap.  For this assignment, the most useful one is '''gray''' for grayscale images.
 
* <code>axis equal</code> will tell MATLAB to display an item such that each direction has the same scale.  For the imaging commands, this is useful in that it will make each pixel a square regardless of the shape of the figure window, thus preserving the geometry of an image.
 
  
 
== Links ==
 
== Links ==
* 2D Convolution link for 6.1: [HTTP://www.songho.ca/dsp/convolution/convolution2d_example.HTML HTTP://www.songho.ca/dsp/convolution/convolution2d_example.HTML]
+
* 2D Convolution information: [HTTP://www.songho.ca/dsp/convolution/convolution2d_example.HTML HTTP://www.songho.ca/dsp/convolution/convolution2d_example.HTML]
* Kernel link for Exercise 7: [https://en.wikipedia.org/wiki/Kernel_(image_processing) https://en.wikipedia.org/wiki/Kernel_(image_processing)]
+
* Kernels: [https://en.wikipedia.org/wiki/Kernel_(image_processing) https://en.wikipedia.org/wiki/Kernel_(image_processing)]
* Test Card for Exercise 8: [https://en.wikipedia.org/wiki/Test_card https://en.wikipedia.org/wiki/Test_card]
+
* Test Card for later use: [https://en.wikipedia.org/wiki/Test_card https://en.wikipedia.org/wiki/Test_card]
  
 
== Examples ==
 
== Examples ==
The following sections will contain both the example programs given in the lab as well as the image or images they produce.  You should still type these into your own version of MATLAB to make sure you are getting the same answers.  These are provided so you can compare what you get with what we think you should get.
+
The following sections will contain examples of different images.  You may want to run them in your own version of Python to make sure you are getting the same answers.  These are provided so you can compare what you get with what we think you should get.
  
 
=== Example 1: Black & White Images===
 
=== Example 1: Black & White Images===
[[File:IP1 E1 Plot1.png|thumb]]
+
<!-- [[File:IP1 E1 Plot1.png|thumb]] -->
<syntaxhighlight lang=matlab>
+
<syntaxhighlight lang=python>
a = [ 1 0 1 0 0; ...
+
a = np.array([
      1 0 1 0 1; ...
+
    [1, 0, 1, 0, 0],
      1 1 1 0 0; ...
+
    [1, 0, 1, 0, 1],
      1 0 1 0 1; ...
+
    [1, 1, 1, 0, 0],
      1 0 1 0 1 ];
+
    [1, 0, 1, 0, 1],
figure(1); clf
+
    [1, 0, 1, 0, 1]])
imagesc(a)
+
fig, ax = plt.subplots(num=1, clear=True)
colormap gray; colorbar
+
ax.imshow(a, cmap=plt.cm.gray)
 +
ax.set_axis_off()
 +
fig.tight_layout()
 +
fig, ax = plt.subplots(num=2, clear=True)
 +
aplot2 = ax.imshow(a, cmap=plt.cm.gray)
 +
fig.colorbar(aplot2)
 +
fig.tight_layout()
 
</syntaxhighlight>
 
</syntaxhighlight>
 
<br clear=all>
 
<br clear=all>
  
 
=== Example 2: Simple Grayscale Images===
 
=== Example 2: Simple Grayscale Images===
[[File:IP1 E2 Plot1.png|thumb]]
+
<!-- [[File:IP1 E2 Plot1.png|thumb]] -->
<syntaxhighlight lang=matlab>
+
<syntaxhighlight lang=python>
b = 0:255;
+
bx, by = np.meshgrid(range(255), range(255))
figure(1); clf
+
fig, ax = plt.subplots(num=1, clear=True)
image(b)  
+
ax.imshow(bx, cmap=plt.cm.gray)
colormap gray; colorbar
+
fig.tight_layout()
 +
fig, ax = plt.subplots(num=2, clear=True)
 +
ax.imshow(by, cmap=plt.cm.gray)
 +
fig.tight_layout()
 
</syntaxhighlight>
 
</syntaxhighlight>
 
<br clear=all>
 
<br clear=all>
  
 
=== Example 3: Less Simple Grayscale Images===
 
=== Example 3: Less Simple Grayscale Images===
[[File:IP1 E3 Plot1.png|thumb]]
+
<!-- [[File:IP1 E3 Plot1.png|thumb]] -->
<syntaxhighlight lang=matlab>
+
<syntaxhighlight lang=python>
[x, y] = meshgrid(linspace(0, 2*pi, 201));
+
x, y = np.meshgrid(np.linspace(0, 2*np.pi, 201),
z = cos(x).*cos(2*y);
+
                  np.linspace(0, 2*np.pi, 201));
figure(1); clf
+
z = np.cos(x)*np.cos(2*y);
imagesc(z)
+
fig, ax = plt.subplots(num=1, clear=True)
axis equal; colormap gray; colorbar
+
zplot = ax.imshow(z, cmap=plt.cm.gray)
 +
ax.axis('equal')
 +
fig.colorbar(zplot)
 +
fig.tight_layout()
 
</syntaxhighlight>
 
</syntaxhighlight>
Notice how the use of <code>axis equal</code> made the image look like a square since it is 201x201 but also caused the display to be filled with whitespace as a result of the figure size versus the image size.
+
Notice how the use of <code>ax.axis('equal')</code> will make the image look like a square since it is 201x201 but also caused the display to be filled with some whitespace as a result of the figure size versus the image size.  Also note that the values from -1 to 1 were automatically mapped to the full colormap.
 
<br clear=all>
 
<br clear=all>
  
 
=== Example 4: Building an Image===
 
=== Example 4: Building an Image===
[[File:IP1 E4 Plot1.png|thumb]]
+
<!-- [[File:IP1 E4 Plot1.png|thumb]] -->
<syntaxhighlight lang=matlab>
+
<syntaxhighlight lang=python>
rad = 100;
+
rad = 100
del = 10;
+
delta = 10
[x, y] = meshgrid((-3*rad-del):(3*rad+del));
+
x, y =np.meshgrid(range((-3*rad-delta),(3*rad+delta)+1),
[rows, cols] = size(x);
+
                  range((-3*rad-delta),(3*rad+delta)+1))
dist = @(x, y, xc, yc) sqrt((x-xc).^2+(y-yc).^2);
+
rows, cols = x.shape
venn_img = zeros(rows, cols, 3);
+
dist = lambda x, y, xc, yc: np.sqrt((x-xc)**2+(y-yc)**2)
venn_img(:,:,1) = (dist(x, y, rad.*cos(0), rad.*sin(0)) < 2*rad);
+
venn_img = np.zeros((rows, cols, 3));
venn_img(:,:,2) = (dist(x, y, rad.*cos(2*pi/3), rad.*sin(2*pi/3)) < 2*rad);
+
venn_img[:,:,0] = (dist(x, y, rad*np.cos(0), rad*np.sin(0)) < 2*rad);
venn_img(:,:,3) = (dist(x, y, rad.*cos(4*pi/3), rad.*sin(4*pi/3)) < 2*rad);
+
venn_img[:,:,1] = (dist(x, y, rad*np.cos(2*np.pi/3), rad*np.sin(2*np.pi/3)) < 2*rad);
figure(1); clf
+
venn_img[:,:,2] = (dist(x, y, rad*np.cos(4*np.pi/3), rad*np.sin(4*np.pi/3)) < 2*rad);
image(venn_img)
+
fig, ax = plt.subplots(num=1, clear=True)
axis equal
+
ax.imshow(venn_img)
 +
ax.axis('equal')
 +
fig.tight_layout()
 
</syntaxhighlight>
 
</syntaxhighlight>
 
<br clear=all>
 
<br clear=all>
  
 
=== Example 5: Exploring Colors===
 
=== Example 5: Exploring Colors===
[[File:IP1 E5 Plot1.png|thumb]]
+
<!-- [[File:IP1 E5 Plot1.png|thumb]] -->
<syntaxhighlight lang=matlab>
+
<syntaxhighlight lang=python>
[x, y] = meshgrid(linspace(0, 1, 256));
+
nr = 100
 +
nc = 200
 +
x, y = np.meshgrid(np.linspace(0, 1, nc),
 +
                  np.linspace(0, 1, nr))
 
other = 0.5;
 
other = 0.5;
palette = zeros(256, 256, 3);
+
palette = np.zeros((nr, nc, 3))
palette(:,:,1) = x;
+
palette[:,:,0] = x
palette(:,:,2) = y;
+
palette[:,:,1] = y
palette(:,:,3) = other;
+
palette[:,:,2] = other
figure(1); clf
+
fig, ax = plt.subplots(num=1, clear=True)
imagesc(palette)
+
ax.imshow(palette)
axis equal
+
ax.axis('equal')
 +
fig.tight_layout()
 
</syntaxhighlight>
 
</syntaxhighlight>
 
<br clear=all>
 
<br clear=all>
  
=== Example 6: 1D Convolution===
 
<syntaxhighlight lang=matlab>
 
x = [1, 2, 4, 8, 7, 5, 1]
 
h = [1, -1]
 
y = conv(x, h)
 
</syntaxhighlight>
 
<syntaxhighlight lang=matlab>
 
x =
 
  
    1    2    4    8    7    5    1
+
=== Example 6: 11x11 Blurring===
 
+
<!--
 
 
h =
 
 
 
    1    -1
 
 
 
 
 
y =
 
 
 
    1    1    2    4    -1    -2    -4    -1
 
</syntaxhighlight>
 
<br clear=all>
 
 
 
=== Example 7: 1D Convolution Using 'same'===
 
 
 
<syntaxhighlight lang=matlab>
 
x = [1, 2, 4, 8, 7, 5, 1]
 
h = [1, -1]
 
y = conv(x, h, 'same')
 
</syntaxhighlight>
 
<syntaxhighlight lang=matlab>
 
x =
 
 
 
    1    2    4    8    7    5    1
 
 
 
 
 
h =
 
 
 
    1    -1
 
 
 
 
 
y =
 
 
 
    1    2    4    -1    -2    -4    -1
 
</syntaxhighlight>
 
<br clear=all>
 
 
 
=== Example 8: 10x10 Blurring===
 
 
[[File:IP1 E8 Plot1.png|thumb]]
 
[[File:IP1 E8 Plot1.png|thumb]]
 
[[File:IP1 E8 Plot2.png|thumb]]
 
[[File:IP1 E8 Plot2.png|thumb]]
<syntaxhighlight lang=matlab>
+
-->
x = imread('coins.png');
+
<syntaxhighlight lang=python>
h = ones(10, 10)/10^2;
+
x = ski.data.coins()
y = conv2(x, h, 'same');
+
h = np.ones((11, 11))/11**2;
figure(1); clf
+
y = sig.convolve2d(x, h, 'same');
image(x)
+
fig, ax = plt.subplots(num=1, clear=True)
axis equal; colormap gray; colorbar
+
ax.imshow(x, cmap=plt.cm.gray)
title('Original')
+
ax.axis('equal')
figure(2); clf
+
ax.set(title='Original')
image(y)
+
fig.tight_layout()
axis equal; colormap gray; colorbar
+
fig, ax = plt.subplots(num=2, clear=True)
title('10x10 Blur')
+
ax.imshow(y, cmap=plt.cm.gray)
 +
ax.axis('equal')
 +
ax.set(title='Blurred')
 +
fig.tight_layout()
 
</syntaxhighlight>
 
</syntaxhighlight>
 
<br clear=all>
 
<br clear=all>
  
=== Example 9: Make No Assumptions===
+
=== Example 7: Basic Edge Detection and Display===
<syntaxhighlight lang=matlab>
+
<syntaxhighlight lang=python>
x = [1, 2, 4, 8, 7, 5, 1]
+
x, y = np.meshgrid(np.linspace(-1, 1, 200),
h = [1, -1]
+
                  np.linspace(-1, 1, 200));
y = conv(x, h, 'valid')
+
z1 = (.7<np.sqrt(x**2+y**2)) * (np.sqrt(x**2+y**2)<.9)
</syntaxhighlight>
+
z2 = (.3<np.sqrt(x**2+y**2)) * (np.sqrt(x**2+y**2)<.5)
<syntaxhighlight lang=matlab>
 
x =
 
 
 
    1    2    4    8    7    5    1
 
 
 
 
 
h =
 
 
 
    1    -1
 
 
 
 
 
y =
 
 
 
    1    2    4    -1    -2    -4
 
</syntaxhighlight>
 
<br clear=all>
 
 
 
=== Example 10: Basic Edge Detection and Display===
 
<syntaxhighlight lang=matlab>
 
[x, y] = meshgrid(linspace(-1, 1, 200));
 
z1 = (.7<sqrt(x.^2+y.^2)) & (sqrt(x.^2+y.^2)<.9);
 
z2 = (.3<sqrt(x.^2+y.^2)) & (sqrt(x.^2+y.^2)<.5);
 
 
zimg = 100*z1+200*z2;
 
zimg = 100*z1+200*z2;
figure(1); clf
+
fig, ax = plt.subplots(num=1, clear=True)
image(zimg); axis equal; colormap gray; colorbar; title('Original')
+
ax.imshow(zimg, cmap=plt.cm.gray)
 +
ax.axis('equal')
 +
ax.set(title='Original')
 +
fig.tight_layout()
  
hx = [1 -1; 1 -1];
+
hx = np.array([[1, -1]])
edgex = conv2(zimg, hx, 'valid');
+
edgex = sig.convolve2d(zimg, hx, 'same')
figure(2); clf
+
fig, ax = plt.subplots(num=2, clear=True)
imagesc(edgex); axis equal; colormap gray; colorbar; title('Vertical Edges')
+
ax.imshow(edgex, cmap=plt.cm.gray)
 +
ax.axis('equal')
 +
ax.set(title='Vertical Edges')
 +
fig.tight_layout()
  
hy = hx';
+
hy = np.array([[1], [-1]])
edgey = conv2(zimg, hy, 'valid');
+
edgey = sig.convolve2d(zimg, hy, 'same')
figure(3); clf
+
fig, ax = plt.subplots(num=3, clear=True)
imagesc(edgey); axis equal; colormap gray; colorbar; title('Horizontal Edges')
+
ax.imshow(edgey, cmap=plt.cm.gray)
 +
ax.axis('equal')
 +
ax.set(title='Horizontal Edges')
 +
fig.tight_layout()
  
edges = sqrt(edgex.^2 + edgey.^2);
+
edges = np.sqrt(edgex**2 + edgey**2)
figure(4); clf
+
fig, ax = plt.subplots(num=4, clear=True)
imagesc(edges); axis equal; colormap gray; colorbar; title('Edges')
+
ax.imshow(edges, cmap=plt.cm.gray)
 +
ax.axis('equal')
 +
ax.set(title='Edges')
 +
fig.tight_layout()
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
<!--
 
<gallery>
 
<gallery>
 
File:IP1 E10 Plot1.png|Original
 
File:IP1 E10 Plot1.png|Original
Line 272: Line 242:
 
File:IP1 E10 Plot4.png|Edges
 
File:IP1 E10 Plot4.png|Edges
 
</gallery>
 
</gallery>
 +
-->
 
<br clear=all>
 
<br clear=all>
  
 +
<!--
 
=== Example 11: Chips!===
 
=== Example 11: Chips!===
 
<syntaxhighlight lang=matlab>
 
<syntaxhighlight lang=matlab>
Line 397: Line 369:
 
title('Change Me')
 
title('Change Me')
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
-->
 +
 +
<!--
 +
 +
=== Example 6: 1D Convolution===
 +
<syntaxhighlight lang=matlab>
 +
x = [1, 2, 4, 8, 7, 5, 1]
 +
h = [1, -1]
 +
y = conv(x, h)
 +
</syntaxhighlight>
 +
<syntaxhighlight lang=matlab>
 +
x =
 +
 +
    1    2    4    8    7    5    1
 +
 +
 +
h =
 +
 +
    1    -1
 +
 +
 +
y =
 +
 +
    1    1    2    4    -1    -2    -4    -1
 +
</syntaxhighlight>
 +
<br clear=all>
 +
 +
=== Example 7: 1D Convolution Using 'same'===
 +
 +
<syntaxhighlight lang=matlab>
 +
x = [1, 2, 4, 8, 7, 5, 1]
 +
h = [1, -1]
 +
y = conv(x, h, 'same')
 +
</syntaxhighlight>
 +
<syntaxhighlight lang=matlab>
 +
x =
 +
 +
    1    2    4    8    7    5    1
 +
 +
 +
h =
 +
 +
    1    -1
 +
 +
 +
y =
 +
 +
    1    2    4    -1    -2    -4    -1
 +
</syntaxhighlight>
 +
<br clear=all>
 +
 +
=== Example 9: Make No Assumptions===
 +
<syntaxhighlight lang=matlab>
 +
x = [1, 2, 4, 8, 7, 5, 1]
 +
h = [1, -1]
 +
y = conv(x, h, 'valid')
 +
</syntaxhighlight>
 +
<syntaxhighlight lang=matlab>
 +
x =
 +
 +
    1    2    4    8    7    5    1
 +
 +
 +
h =
 +
 +
    1    -1
 +
 +
 +
y =
 +
 +
    1    2    4    -1    -2    -4
 +
</syntaxhighlight>
 +
<br clear=all>
 
-->
 
-->

Latest revision as of 20:43, 27 July 2021

This page serves as a supplement to the third group meeting of the Summer 2021 Pioneer program for image processing.

Python Requirements

The programs from this lecture will require several modules:

The start of any script we use in this lecture will be:

import numpy as np
import matplotlib.pyplot as plt
import skimage as ski
import scipy.signal as sig

scikit-image commands

The main command for this session is:

  • DATA = ski.data.NAME() where DATA is a variable name you give to store the information from a built-in image and NAME is the name of a built-in image from scikit-image; the built-in images can be found in the Data section of the General Examples page.

Starting on July 26, 2021, we will be using AXIS.imshow(DATA) instead of ski.io.imshow(DATA) to display an image. It looks like ski.io.imshow is going away.

Depending on the nature of an image, its DATA variable will be different shapes and contain different data types. Here is how scikit-image and imshow() interpret things:

  • A 2D-array will either be black and white, grayscale, or it will be mapped to a colormap
  • A 3D-array will be interpreted as an RGB-based color image
  • For a 2D-array, the following data types and sizes might be useful:
    • An array of boolean (True or False) values or integer values with only integers 0 or 1 will produce an image with values at the extreme edges of the colormap. Assume that the code:
      bwimage = ski.data.binary_blobs()
      
      has been run already for each of the cases below. By default in Python with matplotlib this is purple and gold.
      • Default case with booleans
        fig, ax = plt.subplots(num=1, clear=True)
        ax.imshow(bwimage)
        
        You can add some keyword arguments to the command to get black and white as follows:
      • Black and white with booleans
        fig, ax = plt.subplots(num=1, clear=True)
        ax.imshow(bwimage, cmap=plt.cm.gray)
        
      • Black and white and no axis ticks with booleans
        fig, ax = plt.subplots(num=1, clear=True)
        ax.imshow(bwimage, cmap=plt.cm.gray)
        ax.set_axis_off()
        
        Note that for each of the above, you can replace the array of booleans with an array of integers 0 or 1 by replacing the bwimage line with:
        bwimage = np.random.choice([0,1], (50,100))
        
        or
        bwimage = np.random.randint(0, 2, (50, 100))
        
    • An array of integer values will produce an image with values mapped to the default Viridis (purple - green - blue - yellow) colormap. Assume that the code:
      grayimage = ski.data.coins()
      
      has been run already for each of the cases below.
      • Default case with integers
        fig, ax = plt.subplots(num=1, clear=True)
        ax.imshow(grayimage)
        
        You can add some keyword arguments to the command to get shades of gray as above:
      • Gray with integers
        fig, ax = plt.subplots(num=1, clear=True)
        ax.imshow(grayimage, cmap=plt.cm.gray)
        
      • Gray and no axis ticks with integers
        fig, ax = plt.subplots(num=1, clear=True)
        ax.imshow(grayimage, cmap=plt.cm.gray)
        ax.set_axis_off()
        
  • Note 1 - the addition of the colormap is required for using the axis version of imshow versus the scikit-image version of imshow.
  • Note 2 - by default, imshow will stretch the range of integers to cover the whole map. If you want to specifically map to a certain range - for instance, have 0 as pure black and 255 as pure white, you need to add vmin and vmax keyword arguments to explicitly give the values that map to the low and high end of the volormap. For instance:
    fig, ax = plt.subplots(num=1, clear=True)
    grayimage = ski.data.coins()
    ax.imshow(grayimage, cmap=plt.cm.gray, vmin=0, vmax=255))
    
    will produce the exact same image that ski.io.imshow(grayimage) would have produced.
    • An array of floating-point values will also produce an image with values mapped to the default Viridis (purple - green - blue - yellow) colormap. You can add some keyword arguments to the command to get shades of gray as above. Assume that the code:
      x, y = np.meshgrid(np.linspace(-2, 2, 201), np.linspace(-1, 1, 101))
      z = np.exp(-np.sqrt(x**2+y**2))*np.cos(2*np.pi*x)*np.sin(4*np.pi*y)
      
      has been run already for each of the cases below.
      • Default case with floats
        fig, ax = plt.subplots(num=1, clear=True)
        ax.imshow(z)
        
      • Gray with floats
        fig, ax = plt.subplots(num=1, clear=True)
        grayimage = ski.data.coins()
        ax.imshow(grayimage, cmap=plt.cm.gray)
        
      • Gray and no axis ticks with floats
        fig, ax = plt.subplots(num=1, clear=True)
        grayimage = ski.data.coins()
        ax.imshow(grayimage, cmap=plt.cm.gray)
        ax.set_axis_off()
        
  • Note - once again, by default, imshow will stretch the range of floats to cover the whole map. If you want to specifically map to a certain range - for instance, have 0 as pure black and 0.2 as pure white, you need to add vmin and vmax keyword arguments to explicitly give the values that map to the low and high end of the colormap. Anything below vmin will be mapped to the low color and anything above vmax will be mapped to the high. For instance:
    fig, ax = plt.subplots(num=1, clear=True)
    ax.imshow(z, vmin=0, vmax=255))
    
    will produce an image with yellow rounded rectangles on a purple background with greenish-blue edges the further you get away from the center. The large all-yellow rectangles contain many values that are above 0.2 and the purple parts are all the negative parts of the array.
  • For a 3D array, the third dimension should have three layers representing the red, green, and blue levels for each pixel. The entries either need to be integers between 0 and 255 or floating point numbers between 0 and 1. If the array contains values outside of those limits, strange things happen.

Links

Examples

The following sections will contain examples of different images. You may want to run them in your own version of Python to make sure you are getting the same answers. These are provided so you can compare what you get with what we think you should get.

Example 1: Black & White Images

a = np.array([
    [1, 0, 1, 0, 0],
    [1, 0, 1, 0, 1],
    [1, 1, 1, 0, 0],
    [1, 0, 1, 0, 1],
    [1, 0, 1, 0, 1]])
fig, ax = plt.subplots(num=1, clear=True)
ax.imshow(a, cmap=plt.cm.gray)
ax.set_axis_off()
fig.tight_layout()
fig, ax = plt.subplots(num=2, clear=True)
aplot2 = ax.imshow(a, cmap=plt.cm.gray)
fig.colorbar(aplot2)
fig.tight_layout()


Example 2: Simple Grayscale Images

bx, by = np.meshgrid(range(255), range(255))
fig, ax = plt.subplots(num=1, clear=True)
ax.imshow(bx, cmap=plt.cm.gray)
fig.tight_layout()
fig, ax = plt.subplots(num=2, clear=True)
ax.imshow(by, cmap=plt.cm.gray)
fig.tight_layout()


Example 3: Less Simple Grayscale Images

x, y = np.meshgrid(np.linspace(0, 2*np.pi, 201),
                   np.linspace(0, 2*np.pi, 201));
z = np.cos(x)*np.cos(2*y);
fig, ax = plt.subplots(num=1, clear=True)
zplot = ax.imshow(z, cmap=plt.cm.gray)
ax.axis('equal')
fig.colorbar(zplot)
fig.tight_layout()

Notice how the use of ax.axis('equal') will make the image look like a square since it is 201x201 but also caused the display to be filled with some whitespace as a result of the figure size versus the image size. Also note that the values from -1 to 1 were automatically mapped to the full colormap.

Example 4: Building an Image

rad = 100
delta = 10
x, y =np.meshgrid(range((-3*rad-delta),(3*rad+delta)+1),
                  range((-3*rad-delta),(3*rad+delta)+1))
rows, cols = x.shape
dist = lambda x, y, xc, yc: np.sqrt((x-xc)**2+(y-yc)**2)
venn_img = np.zeros((rows, cols, 3));
venn_img[:,:,0] = (dist(x, y, rad*np.cos(0), rad*np.sin(0)) < 2*rad);
venn_img[:,:,1] = (dist(x, y, rad*np.cos(2*np.pi/3), rad*np.sin(2*np.pi/3)) < 2*rad);
venn_img[:,:,2] = (dist(x, y, rad*np.cos(4*np.pi/3), rad*np.sin(4*np.pi/3)) < 2*rad);
fig, ax = plt.subplots(num=1, clear=True)
ax.imshow(venn_img)
ax.axis('equal')
fig.tight_layout()


Example 5: Exploring Colors

nr = 100
nc = 200
x, y = np.meshgrid(np.linspace(0, 1, nc),
                   np.linspace(0, 1, nr))
other = 0.5;
palette = np.zeros((nr, nc, 3))
palette[:,:,0] = x
palette[:,:,1] = y
palette[:,:,2] = other
fig, ax = plt.subplots(num=1, clear=True)
ax.imshow(palette)
ax.axis('equal')
fig.tight_layout()



Example 6: 11x11 Blurring

x = ski.data.coins()
h = np.ones((11, 11))/11**2;
y = sig.convolve2d(x, h, 'same');
fig, ax = plt.subplots(num=1, clear=True)
ax.imshow(x, cmap=plt.cm.gray)
ax.axis('equal')
ax.set(title='Original')
fig.tight_layout()
fig, ax = plt.subplots(num=2, clear=True)
ax.imshow(y, cmap=plt.cm.gray)
ax.axis('equal')
ax.set(title='Blurred')
fig.tight_layout()


Example 7: Basic Edge Detection and Display

x, y = np.meshgrid(np.linspace(-1, 1, 200),
                   np.linspace(-1, 1, 200));
z1 = (.7<np.sqrt(x**2+y**2)) * (np.sqrt(x**2+y**2)<.9)
z2 = (.3<np.sqrt(x**2+y**2)) * (np.sqrt(x**2+y**2)<.5)
zimg = 100*z1+200*z2;
fig, ax = plt.subplots(num=1, clear=True)
ax.imshow(zimg, cmap=plt.cm.gray)
ax.axis('equal')
ax.set(title='Original')
fig.tight_layout()

hx = np.array([[1, -1]])
edgex = sig.convolve2d(zimg, hx, 'same')
fig, ax = plt.subplots(num=2, clear=True)
ax.imshow(edgex, cmap=plt.cm.gray)
ax.axis('equal')
ax.set(title='Vertical Edges')
fig.tight_layout()

hy = np.array([[1], [-1]])
edgey = sig.convolve2d(zimg, hy, 'same')
fig, ax = plt.subplots(num=3, clear=True)
ax.imshow(edgey, cmap=plt.cm.gray)
ax.axis('equal')
ax.set(title='Horizontal Edges')
fig.tight_layout()

edges = np.sqrt(edgex**2 + edgey**2)
fig, ax = plt.subplots(num=4, clear=True)
ax.imshow(edges, cmap=plt.cm.gray)
ax.axis('equal')
ax.set(title='Edges')
fig.tight_layout()