1 00:00:08,753 --> 00:00:13,614 Let's take a look at some other functions we might want to use in Pillow to modify 2 00:00:13,614 --> 00:00:14,213 images. 3 00:00:14,213 --> 00:00:17,909 First, let's import all of the library functions we need. 4 00:00:17,909 --> 00:00:20,566 So we'll import PIL like we've been using. 5 00:00:20,566 --> 00:00:27,971 From PIL we'll import Image, and from IPython.display, we'll import Display. 6 00:00:27,971 --> 00:00:30,762 And let's load the image we're working with, 7 00:00:30,762 --> 00:00:33,215 and we can just convert it to rgbn.live. 8 00:00:33,215 --> 00:00:36,980 So that image was in read only slash msirecruitment.gif, and 9 00:00:36,980 --> 00:00:41,952 here we'll just image.open the file, and then that returns an image object which 10 00:00:41,952 --> 00:00:46,377 we call converton, send it the rgb string, and now we've got our image. 11 00:00:46,377 --> 00:00:50,222 And let's just display that image, inline, here. 12 00:00:50,222 --> 00:00:54,047 All right, so that's the image we've been working with. 13 00:00:54,047 --> 00:00:56,534 A task that's fairly common in image and 14 00:00:56,534 --> 00:01:00,347 picture manipulation is to create contact sheets of images. 15 00:01:00,347 --> 00:01:05,332 A contact sheet is one image that actually contains several other different images. 16 00:01:05,332 --> 00:01:07,522 So let's try and make a contact sheet for 17 00:01:07,522 --> 00:01:10,819 the Master of Science in Information advertisement image. 18 00:01:10,819 --> 00:01:15,530 In particular, let's change the brightness of the image in ten different ways. 19 00:01:15,530 --> 00:01:20,676 Then scale the images down to smaller sizes and put them side by side so 20 00:01:20,676 --> 00:01:25,392 that we can get a sense of which brightness we might want to use. 21 00:01:25,392 --> 00:01:28,739 So, first off, let's import the image enhance module, 22 00:01:28,739 --> 00:01:31,279 which has a nice object called brightness. 23 00:01:31,279 --> 00:01:34,775 So from PIL import image enhance. 24 00:01:34,775 --> 00:01:38,334 Checking the online documentation for this function, 25 00:01:38,334 --> 00:01:42,952 it takes a value between 0.0, which is a completely black image, and 26 00:01:42,952 --> 00:01:47,057 1.0 which is the original image, to adjust the brightness. 27 00:01:47,057 --> 00:01:51,564 All of the classes in the image enhance module do this in the same way. 28 00:01:51,564 --> 00:01:54,649 You create an object, in this case brightness, 29 00:01:54,649 --> 00:01:59,927 then you call the enhance function on that object with the appropriate parameter. 30 00:01:59,927 --> 00:02:04,389 Let's write a little loop to generate 10 images of different brightnesses. 31 00:02:04,389 --> 00:02:07,505 First, we need the brightness object with our image. 32 00:02:07,505 --> 00:02:10,494 So we'll create a variable called enhancer, and 33 00:02:10,494 --> 00:02:14,774 we'll set this to ImageEnhance.Brightness, and pass in the image. 34 00:02:14,774 --> 00:02:19,256 Now let's create a new list for our images, and then for each image, 35 00:02:19,256 --> 00:02:22,821 so from 0 to 10, let's do some processing of this. 36 00:02:22,821 --> 00:02:26,385 So divide I here by 10 to get the decimal values we want, 37 00:02:26,385 --> 00:02:28,480 and append it to the images list. 38 00:02:28,480 --> 00:02:32,851 We actually call the brightness routine by calling the enhance function as i said. 39 00:02:32,851 --> 00:02:37,009 So remember that you can dig into the details of this using a Help function if 40 00:02:37,009 --> 00:02:39,455 you want to, or by consulting the web docs. 41 00:02:39,455 --> 00:02:44,301 So, we'll do images.append and we'll do enhance or .enhance, and 42 00:02:44,301 --> 00:02:48,919 we'll just take our counter parameter here I and divide it by 10. 43 00:02:48,919 --> 00:02:53,325 Well, first, we'll get 0 and then 0.1, 0.2 and so forth. 44 00:02:53,325 --> 00:02:58,238 We can see that the result here is going to be a list of 10 PIL image.image 45 00:02:58,238 --> 00:02:58,961 objects. 46 00:02:58,961 --> 00:03:04,398 Jupiter nicely prints out the value of Python objects nested in lists. 47 00:03:04,398 --> 00:03:07,524 So let's just print out the images here. 48 00:03:07,524 --> 00:03:08,573 And there we go. 49 00:03:08,573 --> 00:03:12,823 We can see that we have these PIL.image.imageobjects and PIL actually, 50 00:03:12,823 --> 00:03:16,542 what we call print on them the function has been written. 51 00:03:16,542 --> 00:03:20,842 So we get to see a little bit more information about each of these objects. 52 00:03:20,842 --> 00:03:24,325 We see that the mode is RGB, of course we knew that, so we converted that. 53 00:03:24,325 --> 00:03:28,101 But we also see the size and then they give us a memory location which for 54 00:03:28,101 --> 00:03:32,581 our cases is not particularly interesting, but you could see that that changes for 55 00:03:32,581 --> 00:03:33,669 each of the images. 56 00:03:33,669 --> 00:03:37,199 So we know they're pointing to different images. 57 00:03:37,199 --> 00:03:40,327 Let's take this images now and composite them, 58 00:03:40,327 --> 00:03:42,931 one above another into a contact sheet. 59 00:03:42,931 --> 00:03:47,299 There's several different approaches we can use by all simply using new image 60 00:03:47,299 --> 00:03:50,159 which is like the first image but ten times as high. 61 00:03:50,159 --> 00:03:53,969 Let's check out the pil.image.newfunctionality. 62 00:03:53,969 --> 00:04:01,281 So we can do this using Help, which is a help pil.image.new, and run that cell. 63 00:04:01,281 --> 00:04:04,978 The new function requires that we passed to it a mode. 64 00:04:04,978 --> 00:04:08,730 We are going to use the mode RGB, which stands for Red, Green, Blue, 65 00:04:08,730 --> 00:04:11,220 and it's the mode of our current first image. 66 00:04:11,220 --> 00:04:14,309 There's lots of different image mode formats, 67 00:04:14,309 --> 00:04:17,332 and this one is actually one of the most common. 68 00:04:17,332 --> 00:04:21,960 For the size, we have a tuple, which is the width of the image and the height. 69 00:04:21,960 --> 00:04:25,031 We'll use the width of our current first image, but for 70 00:04:25,031 --> 00:04:27,261 the height we'll multiply this by ten. 71 00:04:27,261 --> 00:04:30,949 This will make a sort of canvas for our contact sheet. 72 00:04:30,949 --> 00:04:34,757 Finally the color is optional and we'll just leave it to black. 73 00:04:34,757 --> 00:04:37,754 So we'll create a new variable here called first image and 74 00:04:37,754 --> 00:04:41,300 we'll use that a lot, and it's just the first image from the list but 75 00:04:41,300 --> 00:04:43,642 we're going to use it as a reference for sizes. 76 00:04:43,642 --> 00:04:48,251 From PIL we want to import image, and then let's create the contact sheet. 77 00:04:48,251 --> 00:04:51,214 And so this is we call pil.image.news, so 78 00:04:51,214 --> 00:04:56,341 we're invoking the image new constructor, or what will be a constructor, 79 00:04:56,341 --> 00:05:01,492 to give us the first image mode so that's RB, that's the first parameter. 80 00:05:01,492 --> 00:05:06,666 And then we give it the width and then ten times the height. 81 00:05:06,666 --> 00:05:10,999 So now, we have a block image that's ten times the size of the other images in 82 00:05:10,999 --> 00:05:12,705 the contact sheet variable. 83 00:05:12,705 --> 00:05:16,306 Now let's just look through the image list and paste the results in. 84 00:05:16,306 --> 00:05:20,988 The Paste function will be called on the contact sheet Object, and 85 00:05:20,988 --> 00:05:25,763 it takes in a new image to paste as well as an x y offset for that image. 86 00:05:25,763 --> 00:05:30,539 In our case the x position is always 0 but the y location will change 87 00:05:30,539 --> 00:05:34,911 by 450 pixels each time that we iterate through the loop. 88 00:05:34,911 --> 00:05:40,227 So let's first create a counter variable for the y location and we'll start at 0. 89 00:05:40,227 --> 00:05:43,188 So we call that counter current location. 90 00:05:43,188 --> 00:05:46,012 And then for each image in our images list, 91 00:05:46,012 --> 00:05:49,709 let's paste the current image into the contact sheet. 92 00:05:49,709 --> 00:05:53,718 So we call contact_sheet.paste, we give it the image and 93 00:05:53,718 --> 00:05:57,803 we give it a 0, which is the x location so to the far left, and 94 00:05:57,803 --> 00:06:01,271 then the current location which is our y location. 95 00:06:01,271 --> 00:06:03,886 And then let's update our current location counters. 96 00:06:03,886 --> 00:06:10,802 So we update this by increasing it by 450 pixels, which is the height of our image. 97 00:06:10,802 --> 00:06:15,266 This contact sheet has gotten big, 4,500 pixels tall. 98 00:06:15,266 --> 00:06:17,842 Let's just resize this sheet for display. 99 00:06:17,842 --> 00:06:20,597 We could do this using the Resize function. 100 00:06:20,597 --> 00:06:23,735 This function takes in a tuple of width and height and 101 00:06:23,735 --> 00:06:28,028 will resize everything down to the size of just two individual images. 102 00:06:28,028 --> 00:06:31,286 So we just call contactsheet.resize and 103 00:06:31,286 --> 00:06:35,108 give it the tuple size that we want it to scale to. 104 00:06:35,108 --> 00:06:40,524 Now let's just display that composite image called display with contact sheet. 105 00:06:46,557 --> 00:06:48,953 You can see here that we have all of these images, 106 00:06:48,953 --> 00:06:52,647 they're stacked upon one another and they're different brightnesses. 107 00:06:52,647 --> 00:06:59,173 They really go from quite dark, maybe even black, to almost our full normal image. 108 00:06:59,173 --> 00:07:03,441 Okay, so that's a nice proof of concept but it's a little tough to see. 109 00:07:03,441 --> 00:07:07,188 Let's instead change this to a 3 by 3 grid values, and 110 00:07:07,188 --> 00:07:10,631 this is something you'll use in your assignment. 111 00:07:10,631 --> 00:07:14,552 So first thing we should do is make our canvas, we'll make it three times 112 00:07:14,552 --> 00:07:19,198 the width of our image and three times the height of the image, a nine-image square. 113 00:07:19,198 --> 00:07:21,443 So we'll call pil.image.new. 114 00:07:21,443 --> 00:07:25,661 Again, we want to pass in the mode of the image we're using, and then the width and 115 00:07:25,661 --> 00:07:29,964 the height each multiplied by nine, and we'll save this as our new contact sheet. 116 00:07:29,964 --> 00:07:34,304 Now we want to iterate over our images and place them into this grid. 117 00:07:34,304 --> 00:07:38,352 Remember that in PIL we manage the location of where we've referred to 118 00:07:38,352 --> 00:07:40,694 an image in the upper right hand corner. 119 00:07:40,694 --> 00:07:42,952 So, this would be 0.0. 120 00:07:42,952 --> 00:07:46,911 Let's use one variable for the x dimension and one for the y dimension. 121 00:07:46,911 --> 00:07:50,902 So x equals 0 and y equals 0. 122 00:07:50,902 --> 00:07:53,718 Now, let's just iterate over our images. 123 00:07:53,718 --> 00:07:57,419 Except we don't want to bother with the first one because it's just solid black. 124 00:07:57,419 --> 00:08:01,752 Instead we just want to deal with the images after the first one, and 125 00:08:01,752 --> 00:08:03,892 that should give us a nine total. 126 00:08:03,892 --> 00:08:05,627 So for image in images, and 127 00:08:05,627 --> 00:08:10,229 we just use slicing here to pull out from the first damage, that is the one 128 00:08:10,229 --> 00:08:14,840 in the one position as opposed to the zero position to the end of the list. 129 00:08:14,840 --> 00:08:17,781 And that gives us a sub list that we're going to iterate over. 130 00:08:17,781 --> 00:08:20,854 Let's paste the current image into the contact sheet. 131 00:08:20,854 --> 00:08:25,650 And so we do this with contact_sheet.paste and we pass in the image, 132 00:08:25,650 --> 00:08:27,127 and the x y position. 133 00:08:27,127 --> 00:08:29,304 Now, we need to update our x position. 134 00:08:29,304 --> 00:08:33,514 If it's going to be the width of the image, then we set it to zero and 135 00:08:33,514 --> 00:08:37,817 we update y as well to the point to the next line of the contact sheet. 136 00:08:37,817 --> 00:08:43,131 So, if x plus first image.width is equal to the contact sheet.width, we'll 137 00:08:43,131 --> 00:08:48,702 set x to 0 and we'll update y, and we'll make Y equal to the first image.height. 138 00:08:48,702 --> 00:08:52,111 So if this isn't true then we'll just update x, and 139 00:08:52,111 --> 00:08:57,071 so x will be equal to x plus the first image.width, and this will move us over 140 00:08:57,071 --> 00:09:01,667 a little bit horizontally but won't change our vertical alignment. 141 00:09:01,667 --> 00:09:04,779 Now let's resize the contact sheet. 142 00:09:04,779 --> 00:09:07,999 We'll make it just half the size by dividing it by two, and 143 00:09:07,999 --> 00:09:12,670 because the Resize function needs to take round numbers, we'll need to convert our 144 00:09:12,670 --> 00:09:16,913 divisions from floating point numbers into integers using the N function. 145 00:09:16,913 --> 00:09:20,609 And so we'll take our contact sheet, we'll resize it, 146 00:09:20,609 --> 00:09:23,154 we want to really pass two parameters. 147 00:09:23,154 --> 00:09:27,054 But we need to wrap those in into calls to make them integers, whole numbers, 148 00:09:27,054 --> 00:09:28,796 because we're doing a division. 149 00:09:28,796 --> 00:09:33,050 And so when you take two integers and divide one by the other integer, you 150 00:09:33,050 --> 00:09:37,817 always get a floating point return, and we want to typecast this into integers. 151 00:09:37,817 --> 00:09:42,588 Now let's display that as a composite image, and so 152 00:09:42,588 --> 00:09:47,909 just like before we display the contact sheet in Jupyter. 153 00:09:47,909 --> 00:09:50,934 We see here we have our 3 by 3 grid. 154 00:09:50,934 --> 00:09:55,548 In the upper left we start with very dark and it gets lighter as we go across, 155 00:09:55,548 --> 00:09:57,175 and then it wraps around. 156 00:09:57,175 --> 00:10:01,147 And it gets lighter and lighter until we get to the lightest image in our 157 00:10:01,147 --> 00:10:03,384 brightness levels at the lower right. 158 00:10:03,384 --> 00:10:06,927 And you could see actually how a photographer who might be looking to 159 00:10:06,927 --> 00:10:08,806 change the brightness of an image. 160 00:10:08,806 --> 00:10:12,262 Let's say they're going to put it in the background of a video or 161 00:10:12,262 --> 00:10:15,594 they want to put it as a background of a page and put text over it. 162 00:10:15,594 --> 00:10:18,243 We might want to see in a bunch of different variations, 163 00:10:18,243 --> 00:10:20,036 a bunch of different brightnesses. 164 00:10:20,036 --> 00:10:22,141 Now, we've written a function which could do that. 165 00:10:22,141 --> 00:10:28,284 So if something like Photoshop was written in Python, you could wire up a button now 166 00:10:28,284 --> 00:10:34,018 with this logic that just shows a bunch of alternative versions of the image. 167 00:10:34,018 --> 00:10:37,418 Well, that's been a tour of our first external API, 168 00:10:37,418 --> 00:10:40,754 the Python Imaging Library, or the Pillow module. 169 00:10:40,754 --> 00:10:44,999 In this series of lectures, you've learn how to read and write images, 170 00:10:44,999 --> 00:10:49,871 manipulate them with Pillow, and explore the functionality of third-party APIs 171 00:10:49,871 --> 00:10:53,158 using features of Python like DER, Help, and getmro. 172 00:10:53,158 --> 00:10:55,938 You've also been introduced to the console and 173 00:10:55,938 --> 00:10:58,863 how Python stores the libraries on the computer. 174 00:10:58,863 --> 00:11:01,842 Well, for this course, all of the libraries are intended for 175 00:11:01,842 --> 00:11:04,763 you to use in the Coursera website in the Jupyter system, and 176 00:11:04,763 --> 00:11:06,557 you won't need to install your own. 177 00:11:06,557 --> 00:11:11,188 It's good to get the idea of how this work is done in case you wanted to 178 00:11:11,188 --> 00:11:13,158 set things up on your own PC. 179 00:11:13,158 --> 00:11:16,666 Finally, while you can explore Pillow from within Python, 180 00:11:16,666 --> 00:11:20,122 most good modules also put their documentation up online. 181 00:11:20,122 --> 00:11:24,259 And you can read more about Pillow here at Read the Docs. 182 00:11:24,259 --> 00:11:27,660 And this will be very useful for your assignment which comes up soon.