<jupyter_start><jupyter_text>8. Slicing, indexing images Sometimes we need to focus on a smaller part of an image, extract a specific plane or a specific series of pixels. All those operations are made very simple through Numpy. Let's first import packages:<jupyter_code>import numpy as np
import skimage
import skimage.io
import matplotlib.pyplot as plt<jupyter_output><empty_output><jupyter_text>And load again the image seen previously of<jupyter_code>image = skimage.io.imread('https://cildata.crbs.ucsd.edu/media/images/13901/13901.tif')
#image = skimage.io.imread('../Data/yeast.tif')
plt.subplots(figsize = (10,10))
plt.imshow(image, cmap = 'gray');<jupyter_output><empty_output><jupyter_text>8.1 Slicing  Cropping To crop an image, one can just specific the range of pixels that should be considered. We have seen before that one can select a specific pixel:<jupyter_code>image[550,210]<jupyter_output><empty_output><jupyter_text>To select an area one simple gives a range using a semi-column:<jupyter_code>cropped = image[700:800,800:900]
cropped.shape
plt.subplots(figsize = (5,5))
plt.imshow(cropped, cmap = 'gray');<jupyter_output><empty_output><jupyter_text>All pixels in a given dimension If we want to make a vertical cut through the image, i.e. take all rows but only part of the columns, we don't have to explicitly give the rows limits, we can just leave a semi-column:<jupyter_code>image.shape
cropped = image[:,800:900]
cropped.shape
plt.subplots(figsize = (5,5))
plt.imshow(cropped, cmap = 'gray');<jupyter_output><empty_output><jupyter_text>Using a step size Finally we are not forced to take all the pixels between two limits. We can also say that we take e.g. every third pixel:<jupyter_code>cropped = image[700:800:3,800:900:3]
cropped.shape
plt.subplots(figsize = (5,5))
plt.imshow(cropped, cmap = 'gray');<jupyter_output><empty_output><jupyter_text>Multi-dimensional image Often in biology, datasets are multi-dimensional: several wavelength were acquired, imaging was done in 3D or as a time-lapse etc. Also these different dimensions are often saved within one single file as a series of 2D images. Let's look at our previous image from the main dataset:<jupyter_code>#multiD_image = skimage.io.imread('images/46658_784_B12_1.tif')
multiD_image = skimage.io.imread('https://github.com/guiwitz/PyImageCourse_beginner/raw/master/images/46658_784_B12_1.tif')<jupyter_output><empty_output><jupyter_text>The shape of that image is:<jupyter_code>multiD_image.shape<jupyter_output><empty_output><jupyter_text>We have seen before that if the third dimension contains three planes, Matplotlib assumes that we have an RGB image and displays it accordingly:<jupyter_code>plt.imshow(multiD_image);<jupyter_output><empty_output><jupyter_text>What if we only want to look at the blue channel, which contains the cell nuclei? We can use again **slicing** to do that. But instead of cropping a part of a 2D image, we select one of the three planes: we take all rows ```:``` all columns ```:``` of the third channel ```2```:<jupyter_code>blue_image = multiD_image[:,:,2]
plt.imshow(blue_image, cmap = 'gray');<jupyter_output><empty_output><jupyter_text>8.2 Indexing There are many different ways to do array indexing, which means recovering series of specific parts of an array. We will focus on two: indexing with an other array, and indexing with position vectors.  Indexing with an array We have seen before that we can generate boolean arrays by doing a logical operation e.g. asking which pixels have a value above some values. Let's first explore what values the pixels in our cropped image have:<jupyter_code>plt.hist(np.ravel(blue_image))
plt.show()<jupyter_output><empty_output><jupyter_text>We can now create a boolean array telling us which pixels are e.g. above 50. This is usually called a **mask**.<jupyter_code>mymask = blue_image > 50
mymask<jupyter_output><empty_output><jupyter_text>We can plot that image. Matplotlib just interprets it as a binary image:<jupyter_code>plt.imshow(mymask, cmap = 'gray');<jupyter_output><empty_output><jupyter_text>All white pixesl (True) represent regions that are above the threshold. What if we now want to recover the actual pixel values of those pixesl in the "real" image? Instead of looking up values using ```cropped[xpix, ypix]``` we can pass the **entire** boolean array to the image, which results in the operation sketched here:<jupyter_code>from IPython.display import Image
Image(url='https://github.com/guiwitz/ISDAwPython_day2/raw/master/images/logical_indexing.jpeg',width=700)
blue_image[mymask]<jupyter_output><empty_output><jupyter_text>Of course **this only works if the two arrays have the same size**.  Indexing with vectors Sometimes, we need to know the location of objects in an image. For example we might want to know the positions of all pixels in the mask that we created above. We can recover that information using:<jupyter_code>mypositions = np.argwhere(mymask == True)
mypositions<jupyter_output><empty_output><jupyter_text>This command basically ask to return the position ("arg" like in mathematics) of pixels that fulfill some condition. Notice that we used here the ```==``` "is equal" sign just like we used it for a variable. Numpy once again knows that it has to do the comparison for all pixes. The returned positions are in a form of a 2D list:<jupyter_code>mypositions.shape<jupyter_output><empty_output><jupyter_text>We have **555207** pixels and each of them has **2** coordinates, row and column. We can now recover a single pixel, e.g. the 8th pixel:<jupyter_code>mypositions[8, :]<jupyter_output><empty_output><jupyter_text>which is at row = 1 and column = 0. We can use those coordinates to recover the value in the original image:<jupyter_code>blue_image[mypositions[8,0], mypositions[8,1]]<jupyter_output><empty_output><jupyter_text>We can also pass the entire rows and columns coordinate lists and recover in one shot all those pixels. All the rows are recovered using:<jupyter_code>mypositions[:, 0]<jupyter_output><empty_output><jupyter_text>and the columns:<jupyter_code>mypositions[:, 1]<jupyter_output><empty_output><jupyter_text>We pass those two list to the original image:<jupyter_code>blue_image[mypositions[:, 0],mypositions[:, 1]]<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09163219853643016, 'fraction_numerical': 0.018771874005727014, 'mean_word_length': 6.493444576877235, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 86, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '21', 'dir': 'jupyter-structured-clean-dedup', 'id': '631347', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2076, 'n_tokens_neox': 1962, 'n_words': 699, 'path': '08-Slicing_indexing.ipynb', 'repo_name': 'guiwitz/PyImageCourse_beginner', 'size': '6286'}