1 00:00:05,450 --> 00:00:10,230 First, let's import the PIL library and the image object. 2 00:00:10,230 --> 00:00:14,370 Import PIL then from pill we'll import image. 3 00:00:14,370 --> 00:00:17,730 Let's import the display functionality from 4 00:00:17,730 --> 00:00:22,740 IPython so from IPython.display will import display. 5 00:00:22,740 --> 00:00:24,780 Finally, let's load the image 6 00:00:24,780 --> 00:00:26,775 we were working with last time. 7 00:00:26,775 --> 00:00:30,250 So that image is in read_only/msi_recruitment.gif. 8 00:00:31,580 --> 00:00:34,770 I will open it into the image object. 9 00:00:34,770 --> 00:00:36,705 Let's execute that so. 10 00:00:36,705 --> 00:00:38,730 Great. Now, let's check out 11 00:00:38,730 --> 00:00:40,980 a few more methods of the image library. 12 00:00:40,980 --> 00:00:42,690 First, we're going to look at copy. 13 00:00:42,690 --> 00:00:44,660 If you remember, we can do this using 14 00:00:44,660 --> 00:00:47,345 the built-in Python help command. 15 00:00:47,345 --> 00:00:50,900 So help image.copy. All right. 16 00:00:50,900 --> 00:00:53,540 Here's some information about copy. 17 00:00:53,540 --> 00:00:56,390 We see that the copy takes no arguments and that 18 00:00:56,390 --> 00:00:59,360 the return object is an image object itself. 19 00:00:59,360 --> 00:01:01,145 Now, let's look at save. 20 00:01:01,145 --> 00:01:03,755 So help image.save. 21 00:01:03,755 --> 00:01:08,480 Okay. There's quite a bit to the image.save object. 22 00:01:08,480 --> 00:01:10,460 The image save method has 23 00:01:10,460 --> 00:01:12,440 a couple of parameters which are interesting. 24 00:01:12,440 --> 00:01:14,510 The first called fp, 25 00:01:14,510 --> 00:01:17,315 is the filename we want to save the object to. 26 00:01:17,315 --> 00:01:20,340 The second format is interesting. 27 00:01:20,340 --> 00:01:22,470 It allows us to change the type of 28 00:01:22,470 --> 00:01:24,770 the image but the docs tells us that this should 29 00:01:24,770 --> 00:01:26,600 be done automatically by looking at 30 00:01:26,600 --> 00:01:29,960 the file extension as well. Let's give it a try. 31 00:01:29,960 --> 00:01:32,860 This file was originally a Gif image file, 32 00:01:32,860 --> 00:01:34,430 but I bet if we save it with 33 00:01:34,430 --> 00:01:36,935 a.png format and read it again, 34 00:01:36,935 --> 00:01:39,130 we'll get a different kind of file. 35 00:01:39,130 --> 00:01:41,750 Let's image.save and we'll just call it 36 00:01:41,750 --> 00:01:44,330 msi_recruitment.png and that's going 37 00:01:44,330 --> 00:01:46,730 to save it in your home directory. 38 00:01:46,730 --> 00:01:48,710 Then we'll open a new image. 39 00:01:48,710 --> 00:01:53,220 So image.open msi_recruitment.png and 40 00:01:53,220 --> 00:01:54,935 take that into an image variable. 41 00:01:54,935 --> 00:01:57,080 Now, let's inspect like we did 42 00:01:57,080 --> 00:01:59,060 in the previous lecture and call 43 00:01:59,060 --> 00:02:04,765 inspect.getmro and wrap image in the type function. 44 00:02:04,765 --> 00:02:07,820 Indeed, this created a new file 45 00:02:07,820 --> 00:02:09,110 which we could view by going into 46 00:02:09,110 --> 00:02:11,030 the Jupyter Notebook file list by clicking 47 00:02:11,030 --> 00:02:13,220 on the logo at the top of the browser, 48 00:02:13,220 --> 00:02:15,080 and we can see this new object is 49 00:02:15,080 --> 00:02:17,795 actually a png image file object. 50 00:02:17,795 --> 00:02:20,255 For the purposes of this class, 51 00:02:20,255 --> 00:02:21,980 the difference between the image formats 52 00:02:21,980 --> 00:02:23,780 really isn't so important, 53 00:02:23,780 --> 00:02:26,720 but it's nice that you can explore how a library works 54 00:02:26,720 --> 00:02:31,280 using the functions of help, dir and getmro. 55 00:02:31,390 --> 00:02:33,980 The Pillow library also has 56 00:02:33,980 --> 00:02:37,160 some nice image filters to add some effects. 57 00:02:37,160 --> 00:02:40,010 It does this through the filter function. 58 00:02:40,010 --> 00:02:41,750 The filter function takes 59 00:02:41,750 --> 00:02:43,520 a filter object and those are all 60 00:02:43,520 --> 00:02:47,720 stored in the image filter object. Let's take a look. 61 00:02:47,720 --> 00:02:49,910 So from PIL, we'll import 62 00:02:49,910 --> 00:02:51,575 the image filter object 63 00:02:51,575 --> 00:02:54,960 and then run help on image filter. 64 00:02:56,120 --> 00:02:59,599 There are a bunch of different filters here, 65 00:02:59,599 --> 00:03:02,795 but let's just try and apply the blur filter. 66 00:03:02,795 --> 00:03:04,220 Before we do this, 67 00:03:04,220 --> 00:03:07,820 we have to convert the image to what's called RGB mode. 68 00:03:07,820 --> 00:03:09,595 This is a bit magical. 69 00:03:09,595 --> 00:03:12,950 Images like Gifs are limited into how many colors 70 00:03:12,950 --> 00:03:16,685 can be displayed at once based on the size of the pallet. 71 00:03:16,685 --> 00:03:18,020 This is similar to 72 00:03:18,020 --> 00:03:21,500 a painter's palette which only has so much room. 73 00:03:21,500 --> 00:03:24,605 This is actually a very old image format. 74 00:03:24,605 --> 00:03:25,940 If we convert the image 75 00:03:25,940 --> 00:03:27,610 into something more sophisticated, 76 00:03:27,610 --> 00:03:30,500 we can apply these interesting image transforms. 77 00:03:30,500 --> 00:03:33,290 Sometimes, learning a new library means digging a 78 00:03:33,290 --> 00:03:36,530 bit deeper into the domain the library is about. 79 00:03:36,530 --> 00:03:40,280 We could convert this image using the convert function. 80 00:03:40,280 --> 00:03:43,130 So image and then we'll just call 81 00:03:43,130 --> 00:03:46,010 image.convertRGB and this stands for red, 82 00:03:46,010 --> 00:03:47,690 green and blue mode which 83 00:03:47,690 --> 00:03:50,050 is a pretty common mode for images. 84 00:03:50,050 --> 00:03:52,130 Then I will create a new variable 85 00:03:52,130 --> 00:03:53,885 blurred image and we'll set that to 86 00:03:53,885 --> 00:03:56,000 image.filter and we'll pass 87 00:03:56,000 --> 00:03:59,315 in the PIL.imagefilter.blur parameter. 88 00:03:59,315 --> 00:04:01,610 You'll note that the parameter that we're passing in 89 00:04:01,610 --> 00:04:03,950 is really a placeholder, 90 00:04:03,950 --> 00:04:05,810 it's not a function that 91 00:04:05,810 --> 00:04:08,185 we're running it's an object we're passing in. 92 00:04:08,185 --> 00:04:11,770 Then, let's display that blurred image. 93 00:04:12,400 --> 00:04:15,860 I encourage you to pause the video here and jump into 94 00:04:15,860 --> 00:04:16,880 the notebooks and start 95 00:04:16,880 --> 00:04:19,655 experimenting with some of the other filters. 96 00:04:19,655 --> 00:04:21,260 The emboss and sharpen 97 00:04:21,260 --> 00:04:23,525 filters for instance are interesting. 98 00:04:23,525 --> 00:04:24,695 Or for a challenge, 99 00:04:24,695 --> 00:04:26,450 check out the box blur or 100 00:04:26,450 --> 00:04:28,370 the median filter functions and look 101 00:04:28,370 --> 00:04:29,750 at their parameters to get 102 00:04:29,750 --> 00:04:33,030 a sense of how they're being used. 103 00:04:35,210 --> 00:04:37,660 Okay. Let me show you 104 00:04:37,660 --> 00:04:40,555 one more function in this lecture, which is crop. 105 00:04:40,555 --> 00:04:42,580 This removes portions of 106 00:04:42,580 --> 00:04:45,745 the image except for the bounding box that you describe. 107 00:04:45,745 --> 00:04:49,060 When you think of images think of individual dots or 108 00:04:49,060 --> 00:04:52,390 pixels which make up the image being lined up on a grid. 109 00:04:52,390 --> 00:04:55,150 You can actually see the number of pixels high 110 00:04:55,150 --> 00:04:58,240 the image is and the width of the image. 111 00:04:58,240 --> 00:04:59,890 So let's do that here, 112 00:04:59,890 --> 00:05:01,930 we'll print the image. 113 00:05:01,930 --> 00:05:03,340 We'll use the string 114 00:05:03,340 --> 00:05:06,010 formatting to pass in two parameters. 115 00:05:06,010 --> 00:05:08,410 The first is going to be image.width, 116 00:05:08,410 --> 00:05:10,420 the width of the image in pixels and 117 00:05:10,420 --> 00:05:14,060 image.height the height of the image in pixels. 118 00:05:14,240 --> 00:05:18,390 We see it's 800 by 450. 119 00:05:18,390 --> 00:05:20,290 This means that this image is 120 00:05:20,290 --> 00:05:22,330 800 pixels wide and we call that 121 00:05:22,330 --> 00:05:25,090 the x-axis and 450 pixels 122 00:05:25,090 --> 00:05:27,440 high and we call that the y-axis. 123 00:05:27,440 --> 00:05:30,070 If we take a look at the crop documentation, 124 00:05:30,070 --> 00:05:31,810 we see that the first parameter 125 00:05:31,810 --> 00:05:33,550 to the function is a tuple, 126 00:05:33,550 --> 00:05:35,140 which is the left upper, 127 00:05:35,140 --> 00:05:38,770 right and lower values of the x, y coordinates. 128 00:05:38,770 --> 00:05:40,780 So the two corners of the image. 129 00:05:40,780 --> 00:05:44,110 So help image.crop, we run 130 00:05:44,110 --> 00:05:48,710 that and we see that there's a box that we provide. 131 00:05:48,710 --> 00:05:51,519 With PIL images, we define 132 00:05:51,519 --> 00:05:52,930 the bounding box using 133 00:05:52,930 --> 00:05:55,600 the upper left corner and lower right corner. 134 00:05:55,600 --> 00:05:57,970 We count the number of pixels out from 135 00:05:57,970 --> 00:06:00,455 the upper left corner which is zero zero. 136 00:06:00,455 --> 00:06:02,420 This might seem odd if you're used to 137 00:06:02,420 --> 00:06:04,910 coordinate systems which start in the lower left, 138 00:06:04,910 --> 00:06:08,990 a lot of us learned these in primary school mathematics. 139 00:06:08,990 --> 00:06:11,630 Just remember that we define our box in 140 00:06:11,630 --> 00:06:16,320 the same way we count out the positions in the image. 141 00:06:16,330 --> 00:06:18,920 So if we wanted to get 142 00:06:18,920 --> 00:06:21,245 the Michigan logo out of this image, 143 00:06:21,245 --> 00:06:22,805 we might start with the left, 144 00:06:22,805 --> 00:06:27,395 I'd say 50 pixels and the top at zero pixels. 145 00:06:27,395 --> 00:06:30,650 Then we might walk to the right another 190 146 00:06:30,650 --> 00:06:35,050 pixels and set the lower bound to say a 150 pixels. 147 00:06:35,050 --> 00:06:38,840 Let's display and we'll call image.crop and we 148 00:06:38,840 --> 00:06:42,065 pass it a parameter is a tuple. 149 00:06:42,065 --> 00:06:44,360 Remember that we're going to put all four of 150 00:06:44,360 --> 00:06:46,640 these parameters in one tuple object and 151 00:06:46,640 --> 00:06:48,470 pass it in and this should display 152 00:06:48,470 --> 00:06:51,050 the image. There we go. 153 00:06:51,050 --> 00:06:52,250 That's the School of 154 00:06:52,250 --> 00:06:55,700 Information logo cropped out of the image. 155 00:06:55,700 --> 00:06:59,300 Of course, crop like other functions only returns 156 00:06:59,300 --> 00:07:03,455 a copy of the image and doesn't change the image itself. 157 00:07:03,455 --> 00:07:06,380 A strategy I like to do is to try and draw 158 00:07:06,380 --> 00:07:08,180 the bounding box directly on 159 00:07:08,180 --> 00:07:11,015 the image where I'm trying to line things up. 160 00:07:11,015 --> 00:07:15,110 We can draw on images using the image draw object. 161 00:07:15,110 --> 00:07:17,150 I'm not going to go into this in detail, 162 00:07:17,150 --> 00:07:19,910 but here's a quick example of how I 163 00:07:19,910 --> 00:07:23,345 might draw the bounding box in this particular case. 164 00:07:23,345 --> 00:07:28,225 So from PIL we'll import the image draw object, 165 00:07:28,225 --> 00:07:30,525 we'll instantiate this, so we'll call 166 00:07:30,525 --> 00:07:32,805 imagedraw.draw and we pass it the image. 167 00:07:32,805 --> 00:07:35,120 You can check the documentation to learn more 168 00:07:35,120 --> 00:07:38,315 about how you would use this object. 169 00:07:38,315 --> 00:07:40,190 Then we say drawing 170 00:07:40,190 --> 00:07:42,800 object.rectangle and we give it the rectangle 171 00:07:42,800 --> 00:07:44,390 the outline that we're actually 172 00:07:44,390 --> 00:07:47,155 interested in and we give it a fill value. 173 00:07:47,155 --> 00:07:49,250 You can set the fill to different colors or 174 00:07:49,250 --> 00:07:51,320 types and an outline, 175 00:07:51,320 --> 00:07:53,930 in this case we want to make it red. 176 00:07:53,930 --> 00:07:56,480 Because we ran this on the drawing object, 177 00:07:56,480 --> 00:07:57,950 it actually executes it and 178 00:07:57,950 --> 00:07:59,540 the drawing object has a reference 179 00:07:59,540 --> 00:08:00,950 to the underlying image. 180 00:08:00,950 --> 00:08:03,290 So let's display this image now in 181 00:08:03,290 --> 00:08:10,385 the Jupyter Notebook. There we go. 182 00:08:10,385 --> 00:08:14,015 We have an image which is our main image of 183 00:08:14,015 --> 00:08:20,065 the logo that's outlined in the red box for our flier. 184 00:08:20,065 --> 00:08:22,700 Okay. That's been an overview of how 185 00:08:22,700 --> 00:08:24,785 to use PIL for single images, 186 00:08:24,785 --> 00:08:26,510 but a lot of work might involve 187 00:08:26,510 --> 00:08:28,400 multiple images and in fact, 188 00:08:28,400 --> 00:08:31,175 your assignment involves multiple images. 189 00:08:31,175 --> 00:08:33,710 So in the next lecture, we're going to tackle that and 190 00:08:33,710 --> 00:08:37,140 set you up for this assignment. I'll see you there.