Изучение Python OpenCV / Урок #2 – Работа с изображениями и видео — Transcript
Full transcript
- 0:00Hello. In this lesson, we'll learn how
- 0:02to work with images and videos using
- 0:04OpenCV. But before we explore the
- 0:08library and its capabilities, we should
- 0:10first understand what an image is made
- 0:11of and how to describe an image
- 0:13numerically in programming. But before
- 0:16we begin, I recommend itproger.com. On
- 0:19this site, you'll find code, homework
- 0:21assignments, and a lot of other useful
- 0:23information. The link to this lesson on
- 0:24the site will be in the description of
- 0:26this video. Go ahead, you won't regret
- 0:28it. It's no secret that images are made
- 0:30up of pixels. First, let's look at a
- 0:33simple example image. Imagine we need
- 0:35to display a black number on a white
- 0:37background. In this case, we only have
- 0:40two colors. To describe all the white
- 0:42dots, we can use the number one, or a
- 0:44white pixel. And to describe all the
- 0:47black dots, we'll use the number zero,
- 0:49or a black pixel. Such an image is easy
- 0:52to display and represent numerically,
- 0:54since we only have two numbers and two
- 0:55colors. Accordingly, when it comes to
- 0:58large black-and-white photographs, the
- 1:00principle is the same: you just need to
- 1:02create more black dots and more white
- 1:04dots. Describing such an image is as
- 1:06simple as describing a regular number.
- 1:08It still uses a binary format, meaning
- 1:10only ones and zeros. So far, we've
- 1:13looked at an image with two levels:
- 1:15black and white. Adding more levels
- 1:18creates more color gamut formats.
- 1:21Typically, 256 layers are used, from
- 1:23pure black to pure white. This gradient
- 1:26contains all shades of gray, allowing
- 1:28for images of a completely different
- 1:30quality. To describe such an image, we
- 1:34designate each cell from zero (pure
- 1:36black) to 255 (pure white). It turns
- 1:40out that an image consisting of a set
- 1:42of grayscale colors can be described
- 1:43just as simply. After all, the
- 1:46principle is the same, but the number
- 1:48of numbers increases to 255. Color
- 1:50images consist of three grayscale
- 1:52images, each converted to red, green,
- 1:55and blue, respectively. When these
- 1:57three images are superimposed, we
- 1:59obtain a color gamut. To describe such
- 2:02a photo numerically, we need to specify
- 2:04three values for each pixel: a value
- 2:07from zero to 255 from the first red
- 2:09image, a value from zero to 255 from
- 2:11the second green image, and finally, a
- 2:14value from zero to 255 from the third
- 2:16blue image. This format is also called
- 2:19RGB, and it is very common in
- 2:21programming when specifying different
- 2:23colors. If we are talking about videos,
- 2:26they, in turn, consist of hundreds or
- 2:28even thousands of images that quickly
- 2:30switch between each other. This creates
- 2:32the effect of animation. We can
- 2:34describe a video numerically by
- 2:36describing each individual image using
- 2:38the same principle we discussed earlier
- 2:40. Now that we know how images work and
- 2:43are read, we can move on to exploring
- 2:45the library itself. In this lesson, we
- 2:48will learn how to open and work with
- 2:49images and videos, and also become
- 2:51familiar with several basic functions
- 2:53for working with them. So, first of all
- 2:56, let's create a new file. This file
- 2:59itself can have any name. For example,
- 3:02I will call it main.p. At the very top,
- 3:04we need to import our Open CV library.
- 3:07That's why we specify the keyword. And
- 3:10our library, it's called CV2. That's
- 3:13why we import it by that name. That is,
- 3:16to import Open CV, we specify "CV."
- 3:19Then, after importing, we can easily
- 3:21access this library and access its
- 3:23various capabilities. First, I suggest
- 3:28exploring how to load and display
- 3:29images to the user. To implement this,
- 3:34we first need to create a variable.
- 3:37Let's call it image. Next, we access
- 3:40our CV2 library. And then, using a dot,
- 3:44we can access one of its possible
- 3:45functions. We're interested in a
- 3:48function called "I am read." Or,
- 3:50literally, it stands for "image read,"
- 3:52that is, read an image. And here, one
- 3:55parameter must be passed to this
- 3:57function. This is the full path to the
- 3:59image that needs to be loaded. Well,
- 4:02let me now create a new folder here.
- 4:05Let's call this folder, for example,
- 4:07images. And inside this folder, I'll
- 4:09place the image I've already prepared.
- 4:12That is, this image is simply an icon
- 4:14for this video lesson. Let me add this
- 4:16icon here. And after adding it, I can
- 4:19easily—it's also open for me—go to
- 4:22the Images folder. And then from the
- 4:25Images folder, I need to select this
- 4:27photo. I have it here as OpenCV.Pack.
- 4:30You can add any photo you want to the
- 4:32project. You can simply download it
- 4:34from Google. And, accordingly, you can
- 4:36attach it here in the same format.
- 4:40After loading the image, we need to
- 4:42display it, so we access our library
- 4:44and call a method called Show, that is,
- 4:46to display the image. This method takes
- 4:50two parameters. The first parameter is
- 4:52the caption for our image. The caption
- 4:55can be anything. Just don't enter it in
- 4:57Russian, because otherwise, it will
- 4:59most likely be displayed incorrectly,
- 5:01since we haven't set the encoding. I
- 5:03suggest entering it in English. Well,
- 5:05let's say it says Rzle here, yes,
- 5:07that's the result. As the second
- 5:09parameter, we need to specify the image
- 5:11itself. I have this image, it's in a
- 5:14separate variable in the EMG variable,
- 5:16so I'm passing it here. Also, if we try
- 5:19to run the program now, unfortunately,
- 5:21we won't notice anything yet. That is,
- 5:23the image will open and then
- 5:25immediately close. The thing is, we
- 5:27need to specify a time. And this time
- 5:30will be the time while the image will
- 5:31be displayed. To specify the time, we
- 5:34again access the library, we access the
- 5:37weight key method. And here I can
- 5:39specify the number of milliseconds. For
- 5:41example, if I specify a value of 1.000
- 5:43here, it will be 1.000 milliseconds, or
- 5:46, in other words, 1 second. And this is
- 5:48exactly how long the image will be
- 5:50displayed. So, at this point, my
- 5:51program will start, the image will be
- 5:53displayed for one second, and then the
- 5:55image will simply disappear. You can
- 5:57also specify 10 seconds here or 100
- 5:59seconds there. Well, for example, you
- 6:01can simply increase this number. I want
- 6:04to specify that the image will be
- 6:05displayed indefinitely. That is, it
- 6:09will be displayed until I manually stop
- 6:11the program or until I manually close
- 6:13the image. To specify this, I simply
- 6:16need to enter a zero here. This means
- 6:20that the image will be displayed
- 6:21indefinitely until I manually stop it.
- 6:25Now let's try testing all this. To do
- 6:28this, I right-click on our main file
- 6:29and simply click run. You might also
- 6:32think that an error occurred. In fact,
- 6:34it's just a notification text. Well, if
- 6:37you look closely, the image actually
- 6:38opened correctly. We have a caption for
- 6:41this image. And the image itself, here
- 6:43it is displayed. Everything is fine
- 6:44with it. Now, to stop the program, we
- 6:46can simply go to the PRM, here, as if
- 6:48clicking on stop the program. So, we
- 6:50see that the program has finished, and
- 6:52everything seems to have been processed
- 6:54correctly. Now, in addition to photos,
- 6:56let's learn how to display various
- 6:58videos. To begin, I suggest creating a
- 7:01new folder. Let's call this folder
- 7:03Windows, and I'll place the video I've
- 7:05already prepared in this folder. It's a
- 7:07fairly simple video, and a short one at
- 7:09that. I also recommend finding a short
- 7:13video, because if you're simply
- 7:14processing a very long video, it will
- 7:16take a long time to process. Therefore,
- 7:19it's better to find a video up to 20
- 7:21seconds long. I have just such a video.
- 7:24Now, I suggest commenting out all this
- 7:26code for now, so it doesn't get in the
- 7:27way. And just below, let's write the
- 7:31code for displaying a video. Here, we
- 7:34first need to create a variable. This
- 7:36variable can be called anything, but
- 7:38it's usually called cap, which stands
- 7:40for capture, or, in other words, a
- 7:42recording. And here we place the
- 7:44following. We access our library. Next,
- 7:48we call a method called video capture.
- 7:53We pass the full path to the file we
- 7:54want to work with to this method. I
- 7:57have this file, it's in the Window
- 7:58folder. And then the file itself, it's
- 8:01called rot.mp 4. Accordingly, I'm
- 8:05passing that exact name here. Next,
- 8:08since we're working with video, we need
- 8:10to create a loop. Again, let me remind
- 8:14you that a video consists of many
- 8:16different images that smoothly switch
- 8:18between each other, thereby creating an
- 8:20animation effect. Accordingly, we need
- 8:23to create a loop. And in this same loop
- 8:26, we'll completely loop through all of
- 8:28these images that make up the video
- 8:29itself. And we'll show each individual
- 8:32image to the user. This is how we
- 8:35create the video effect. And here we
- 8:37simply create a loop. Our loop is
- 8:39pretty trivial. We simply specify while
- 8:41true. That is, we create an infinite
- 8:43loop. And in fact, this loop will be
- 8:45terminated in two cases. First, if the
- 8:48video plays to the end, the loop will
- 8:50end. We'll even get a small error in
- 8:52the terminal. Well, that won't affect
- 8:55anything, but if the video ends, the
- 8:57loop will also end, plus there will be
- 8:59a small error. That's it. And the
- 9:02second way we'll end the loop is when
- 9:04we press a key. Let's say I press the Q
- 9:08key. If I press that key, the video
- 9:11will also end. We'll finish this check
- 9:14a little later. So, to start, let's
- 9:17define a few variables here. First, I
- 9:20suggest we define a variable, let's
- 9:22call it success. We'll also create a
- 9:26second variable here, which I'll call
- 9:28G. And I'll put the following in these
- 9:29variables. I'm accessing our video and
- 9:34calling the read method, which is the
- 9:36method that allows us to read the video
- 9:38itself. What will we store in these
- 9:42variables? Look, the success variable
- 9:45will be set to either true or false.
- 9:49True will be the value if we were able
- 9:51to read the current video image. False
- 9:55will be the value if we were unable to
- 9:57read the current video image. And then,
- 10:00the image variable, our second variable
- 10:02, will be set to the current image
- 10:03itself. And then, to simply display
- 10:07this image itself for now, we, of
- 10:09course, need to call the method we're
- 10:11already familiar with. This is show,
- 10:14which means to display an image. Yes,
- 10:17this method. We can pass any caption
- 10:19here. I'll specify the caption here
- 10:21again, let's call it result. And then
- 10:23we pass our image. In my case, it's G.
- 10:27At this point, nothing will be
- 10:28processed, since we still need to add
- 10:30one more condition here. In this
- 10:33condition, we'll simply specify a call
- 10:35to the weight key method. And here,
- 10:37we'll simply specify some minimum value
- 10:39, for example, 1 millisecond. Well,
- 10:41it's not possible to simply specify a
- 10:43smaller value. We simply need to call
- 10:45this method so that the video itself is
- 10:47displayed correctly. And we can specify
- 10:50a minimum value here. This way, each
- 10:53image in the video itself will be
- 10:54displayed for a minimum amount of time,
- 10:56right? That is, they will switch
- 10:59between each other as quickly as
- 11:00possible, so we will essentially see
- 11:02the video itself. We also need to add
- 11:06another operation here, or rather,
- 11:07another condition. And here we will
- 11:11track a key like Q. You can track
- 11:13different keys. We will track the Q key
- 11:16specifically. And here we simply need
- 11:19to write the code for this key. It, in
- 11:21turn, is like this. Well, if any of
- 11:24these match, then we will, as it were,
- 11:27break out of the loop itself. Now let's
- 11:30run our entire project and see what
- 11:32we've got. Here, our video is playing.
- 11:35If you press Q, unfortunately, nothing
- 11:37will happen at this point. So, let's
- 11:39probably just stop the program for now.
- 11:43And nothing happens because we need to
- 11:45change the order of these conditions,
- 11:46right? So, we need to check, well,
- 11:49initially write the code, and then
- 11:51check for the OR function. In this case
- 11:54, this key will be processed correctly.
- 11:56So, here we go again. We've started the
- 11:58video, everything works correctly. I
- 12:00press Q. And then the video stops,
- 12:02everything works correctly.
- 12:04Additionally, thanks to Open CV, you
- 12:06can also read data from a webcam. To do
- 12:10this, instead of the full path to a
- 12:12video, you just need to specify zero.
- 12:16This way, you'll access the only
- 12:18current webcam on your computer. If you
- 12:22have multiple webcams, you can specify
- 12:24their numbers. So, for example, zero
- 12:26means accessing the first camera, one
- 12:28means accessing the second camera, and
- 12:30so on. I only have one webcam, so I'm
- 12:33leaving it at zero here. Also, before
- 12:36we test and run this, we need to
- 12:38specify the dimensions for the image
- 12:40itself. To do this, we specify here,
- 12:43well, that is, we access our capture,
- 12:46our video, and access the set method.
- 12:49We need to pass two parameters here.
- 12:51These are the ID, uh, the
- 12:52characteristics that we'll be setting,
- 12:55and the value itself. For example, if I
- 12:58want to set the width, the width's ID
- 13:00is three, so I enter three here. You
- 13:03can also specify any width you like.
- 13:05Let's say I specify it as 500. I also
- 13:07want to specify the height. The height
- 13:11is identified by ID four, so I specify
- 13:13that here. And let's say we specify the
- 13:16height as 300. So, my image will be 500
- 13:19by 300. If we run this now, we'll
- 13:21notice that our webcam opens correctly.
- 13:24It displays the correct image. If you
- 13:26want to exit the webcam, you can simply
- 13:28press the Q key. Now let's explore some
- 13:31image manipulation functions. Since the
- 13:37Open CV library works with images and
- 13:39video, it naturally includes a ton of
- 13:40different functions for transforming
- 13:42various videos and images. We'll
- 13:47explore some of these functions now,
- 13:49and we'll continue to explore them
- 13:50throughout the video course. Then, in
- 13:54the final lessons of this course, we'll
- 13:56be able to use this knowledge to
- 13:58develop a neural network, for example,
- 14:00for face recognition or license plate
- 14:02tracking. For now, let's reduce the
- 14:06image size. My image is way too big. So
- 14:11, before we reduce it, let's perhaps
- 14:13display its dimensions on the screen.
- 14:15To do this, I simply access our image,
- 14:18my EMG variable, and access the shape
- 14:20value. I also suggest commenting out
- 14:23the image output itself so that we
- 14:25simply output the data to the terminal.
- 14:27And so we get a tuple consisting of
- 14:29three elements. The first element is
- 14:31the height of our image, 720 pixels.
- 14:34The second element is the image width,
- 14:361,280 pixels. And the third element is
- 14:39the number of layers. The thing is, our
- 14:41image is in the standard RGB format,
- 14:43meaning we have three layers. These are
- 14:46red, green, and blue, or, in other
- 14:48words, red, green, and blue. And,
- 14:51accordingly, this is the number that
- 14:52was output here. If we need to change
- 14:56the dimensions of the image itself, we
- 14:58can do it as follows. First, we can
- 15:01create a new variable. Let's call it
- 15:04new image. Well, let's say this is its
- 15:06name. And then I set the following to
- 15:09this variable. I access our library and
- 15:12call a method called resй. Here, in
- 15:16this method, I first pass the image I
- 15:18need to change. In my case, it's our
- 15:22standard image. And as the second
- 15:25parameter, I pass a tuple containing
- 15:27two elements: the new width and the new
- 15:29height. What's interesting is that you
- 15:32can specify new dimensions here that
- 15:34will be larger than the current value.
- 15:36That is, you can specify, for example,
- 15:382000 by 2000, and it will be processed
- 15:40absolutely correctly. But let's specify
- 15:43here, perhaps, something like 300 by
- 15:45500; let's say, those are the
- 15:46dimensions here. And a little lower,
- 15:50I'd like to display not the image we
- 15:52initially uploaded, but a new image. So
- 15:56, let's write new image here, and,
- 15:58accordingly, we will display this image
- 16:00. So, let's run the program. And if we
- 16:04look now, you can see that our width is
- 16:06300 pixels, right? And the height is
- 16:09500 pixels. So, when we specify the
- 16:12Rйiz method, we first specify the
- 16:14width, then the height. But when we
- 16:17output these values, they're output in
- 16:19a slightly different format. The height
- 16:22is output first, then the width. If you
- 16:25want to scale the image down
- 16:26proportionally, you can do it this way.
- 16:29We first access our main image. Then we
- 16:33access its size. And we take it here,
- 16:35that is, we initially need to take the
- 16:37width. The width is like the second
- 16:39element for us. It will be indexed as
- 16:42the first element, yes, because indexes
- 16:44start at zero. So, we take the current
- 16:48width of our image and simply divide it
- 16:50by two. But I'd also like to round this
- 16:54all down to a whole number, so I put
- 16:56two division signs here. This way, we
- 16:59get a whole number. I do exactly the
- 17:01same thing with the height, only I
- 17:03specify a different index here. Again,
- 17:05let me remind you that the first
- 17:07element in the shape tuple was
- 17:08responsible for the height, so we take
- 17:10it here at index zero. And we also end
- 17:12up dividing it by two. Furthermore, we
- 17:15could actually avoid creating a new
- 17:16variable here. Let's not do that. I'll
- 17:19simply assign a new value to the same
- 17:21variable. That's perfectly fine. There
- 17:23won't be any problems with that. Now,
- 17:25if we run this, we'll notice that our
- 17:27image has become exactly half as big,
- 17:29right? That is, it's proportionally
- 17:31smaller, both in width and height. If
- 17:35you don't need to reduce the image's
- 17:37size, but simply crop it, you can use
- 17:39indices and slices. For example, when I
- 17:43display the image here, I'll
- 17:44immediately try to crop it. That is,
- 17:46I'll try to display only a specific
- 17:48part of the image. And for that, I need
- 17:50to use indices and slices. Here, look,
- 17:52I want to, for example, specify that
- 17:55I'll take the first 100 pixels of the
- 17:57image by width. I'll take them and
- 17:59display them on the screen. And also,
- 18:00let's say, I want to take the first 100
- 18:02pixels by height, or even the first 150
- 18:04pixels, and I want to display them on
- 18:06the screen too. To specify this, I
- 18:09specify here that it's as if the
- 18:11zero-based coordinate is located at
- 18:13this point, that is, in the upper left
- 18:15corner, we have the zero-based
- 18:16coordinate. Everything is calculated
- 18:18from it, right. So, if I specify it
- 18:21from zero, then, accordingly, it's from
- 18:23this point. So, from zero to 100 pixels
- 18:27, we'll crop this image by width. And
- 18:31also, from zero to 150 pixels by height
- 18:33, we'll crop this image. Well, in fact,
- 18:37this cropped piece will be shown. Well,
- 18:40user, right. Let's restart the project.
- 18:42Here I restarted it. And now we notice
- 18:44that, you see, everything was processed
- 18:46absolutely correctly. That is, we got
- 18:48an image that consists of a small piece
- 18:50of our previous image. I don’t need
- 18:53to crop the image at the moment. So,
- 18:56let me cut this code out anyway. I’ll
- 18:59also leave it here so you just remember
- 19:01how to crop an image by the required
- 19:02number of pixels. In addition, let’s
- 19:06now study some methods that allow us to
- 19:08transform the image itself. For now,
- 19:13let’s study a method that allows us
- 19:14to add additional blur to an image.
- 19:18First, we need to create a variable. We
- 19:21can create a new variable, or I’ll
- 19:23write everything to an existing
- 19:24variable. This won’t be fundamentally
- 19:27important. Here we access our library
- 19:30and call a method called Gusen Blur.
- 19:34Here I need to specify several
- 19:35parameters. First, this is the image we
- 19:37are working with. In my case, this is
- 19:39the image stored in the EMG variable.
- 19:42The second parameter is the kernel size
- 19:44. This is how much blur we'll apply to
- 19:47our image. The second parameter is a
- 19:51map. We pass two values here. Let's say
- 19:53I'm not going to have a super strong
- 19:55blur right now. Let's say I specify
- 19:57three and three. We'll change that a
- 19:59little later. You'll be able to see a
- 20:00stronger blur format. We also need to
- 20:03specify sig. For now, let's just set
- 20:06the value to zero here. Sig x is
- 20:08essentially a multiplier for this blur
- 20:11applied to the image, yes. Right now,
- 20:15we won't have this enhanced blur in the
- 20:17image. If we run this now, we'll notice
- 20:22that the image is still a little blurry
- 20:23. It's not super noticeable, but if we
- 20:28increase the value now, let's say we
- 20:30set the value to nine. Incidentally,
- 20:33there's an important point here. If you
- 20:35set values like, for example, 8 or 4—
- 20:38that is, if you set even values—then
- 20:40all of this will generate an error. You
- 20:42can only set odd values here, like 3, 5
- 20:46, 7, 9, and so on. Let's set 9.9. If I
- 20:50run this now, you'll notice that the
- 20:52image is actually quite blurry. We can
- 20:56easily see this here. So, with Gusin BL
- 20:59, you can quickly blur the image you
- 21:01need. The Open CV library also has a
- 21:05variety of functions that allow us to
- 21:07convert the image to the desired format
- 21:09. Currently, our image format is RGB,
- 21:13meaning we use three layers: red, green
- 21:16, and blue. But we can also convert the
- 21:19image to any other format. If we
- 21:24convert an image to, say, black and
- 21:26white or grayscale, then working with
- 21:28it is much easier because the number of
- 21:30colors is reduced, and processing the
- 21:32photo itself is significantly faster.
- 21:38So, let's now try converting our RGB
- 21:40image to grayscale. To do this, we need
- 21:44to create a new variable. Again, I'll
- 21:46be storing everything in the same
- 21:48variable. Here, we simply access our
- 21:52library, accessing a method called CVT
- 21:54color, or, in full, convert color. Here
- 21:58, we specify several parameters. First,
- 22:01the image we're working with. We also
- 22:03simply specify the ghost format. For
- 22:06this, we need to access our library
- 22:08again. And here, we access the format
- 22:11we need. Look, our image is in RGB
- 22:14format, but if we're talking about Open
- 22:16CV, this format is called BGR. So, it's
- 22:20essentially the same thing as RGB. RGB
- 22:23is simply red, green, blue, and BGR is
- 22:26blue, green, red. Well, it's sort of
- 22:29flipped, but essentially, it's the same
- 22:31thing. So, we need to use a format like
- 22:33BGR to grade, right? So, we're
- 22:35converting the RGB format—or what's
- 22:37called BGR here—to a format like this
- 22:40. If we run this now, we'll notice that
- 22:43our image is blurry and gray. So, it's
- 22:47really just gray. There aren't any
- 22:49additional layers here. Now there's one
- 22:51layer, and it's kind of a gray layer.
- 22:54By the way, we can even try to display
- 22:56information about the image now. Let me
- 22:59just uncomment this. And let's stop the
- 23:01program and run it again. And now we
- 23:03can see that, you see, we have a third
- 23:05parameter. It's not even passed here,
- 23:07but in fact, if it were specified here,
- 23:09it would simply be a one, yes, because
- 23:11we are really only using one layer now.
- 23:13This is a gray layer, so to speak.
- 23:16Previously, three layers were used: red
- 23:19, green, and blue. Later, we will need
- 23:22to find the corners of the image. The
- 23:25thing is, if we find the corners of the
- 23:27image, then we can determine key points
- 23:29, so to speak. And this will make it
- 23:32easier for us to understand what is in
- 23:33a particular image. To find the corners
- 23:36of the image, we need to use a special
- 23:38built-in function that exists in Open
- 23:40CV. We will study it now. Again, we
- 23:44will set a new value in the same
- 23:46variable. That is, we turn to our
- 23:49library and then call a method called
- 23:51Cany. This method accepts, well, three
- 23:55required parameters. The first
- 23:57parameter is, of course, our image. And
- 24:00as the second parameter, we need to
- 24:02pass threshold 1, or the first
- 24:03threshold. And as the third parameter,
- 24:06threshold 2, or the second threshold.
- 24:08What are thresholds? Thresholds are
- 24:11something like the precision of
- 24:12determining all these angles. And let's
- 24:15now specify a value here, say, like 90
- 24:17and 90, and just run it and try to see
- 24:20what we get, and then change these
- 24:22values. Well, look, at this point, what
- 24:25we get is that our image now looks
- 24:27completely different from how it looked
- 24:29before. That is, our image is now a
- 24:32binary image. There are only two colors
- 24:35here: black and white. And thanks to
- 24:38this white color, we have all the
- 24:40outlines, so to speak. For example, I
- 24:43had text here, I had various circles
- 24:45here, and I had some other image here.
- 24:49And, accordingly, it's all outlined,
- 24:51plus this and that image, it's now
- 24:53actually in binary format. That is,
- 24:56from a programming perspective,
- 24:58describing such an image is very, very
- 25:00simple, since there are only two colors
- 25:02, and, accordingly, either zeros or
- 25:04ones are used here. Again, ones are
- 25:07needed to describe everything, well,
- 25:09white, and zeros are needed to describe
- 25:11black. That's all. And, by the way,
- 25:15converting such an image to binary
- 25:17format without initially converting it
- 25:19to grayscale would be difficult,
- 25:21because converting from RGB to binary
- 25:23format directly would be, well, quite
- 25:25problematic, since we have so many
- 25:27colors, and most likely, the library
- 25:28simply won't understand where exactly
- 25:30it needs to place all these outlines.
- 25:35But when we have grayscale format, when
- 25:37we only have one layer instead of three
- 25:39, as before, then, accordingly,
- 25:41converting from one layer to binary
- 25:43format and to an even simpler format is
- 25:45no longer, well, a particular problem.
- 25:48Well, look, here we specify thresholds,
- 25:50so to speak. This is like the precision
- 25:53of defining all these outlines. And
- 25:54right now, I've set it to 90. And in
- 25:56fact, it's already worked absolutely
- 25:58correctly. Well, since I have a fairly
- 26:01simple image, everything worked
- 26:03absolutely correctly here, but you
- 26:05could specify a value here, say, like
- 26:0730 or 30. And let's just try to see
- 26:09what we get in that case. And in that
- 26:14case, we can notice that, see, our
- 26:15precision for this particular drawing
- 26:17has improved, right, because more
- 26:19contours have appeared and more small
- 26:21details have been involved, right? That
- 26:25is, if you need greater precision, then
- 26:27, accordingly, you can decrease this
- 26:29value. If I specify, say, 300 here, and
- 26:32let's stop this and run it again, we
- 26:34can see that, see, how few contours
- 26:36were outlined here, right? In fact, for
- 26:39this drawing, we just drew a tiny bit
- 26:43of contours here, yes. We'll probably
- 26:45leave the value at 100x100 or 90x90.
- 26:48This value suited me just fine, so
- 26:50we'll probably leave it as is for now.
- 26:55Furthermore, we can add additional
- 26:57width to all these contours or,
- 26:58conversely, decrease this width. That
- 27:01is, we can increase or decrease the
- 27:03stroke width. To implement this, we
- 27:06need to use some additional functions.
- 27:09Let's look at them now. So, let's turn
- 27:12to the library. We'll use a method
- 27:15called delate. This method takes
- 27:19several parameters. First, it's the
- 27:21image itself. Second, it's a kpnel. And
- 27:26kpnel is essentially the number of
- 27:28points with which we will, well,
- 27:30describe this width. And here, to
- 27:34specify the number of points, we need
- 27:36to create a matrix. A matrix comes in a
- 27:40format where we write a single list,
- 27:42and within that list, each element is
- 27:44some other list, right? So, let's say,
- 27:47if I write something like this, then
- 27:49that would be a matrix, right? So, we
- 27:52have one list, and within it, there are
- 27:54other different lists. So, of course,
- 27:58we can create such a list ourselves,
- 28:00but why bother creating it ourselves if
- 28:02we have a library called whatever we
- 28:04like? So, I'll import it here too. If
- 28:11you don't have this library here, you
- 28:12can go to the terminal. Here you can
- 28:16type pip install and then num. Well,
- 28:19I'll even do this just in case, to make
- 28:21sure it's installed. I already have it
- 28:23installed, so nothing was downloaded.
- 28:25Well, if you don't have it installed,
- 28:27it would have been downloaded. And here
- 28:29I can probably add an alias. Mm, of
- 28:31course, you don't have to add it, but
- 28:33for some reason, they always add an
- 28:35alias in any documentation. I'll
- 28:36probably do the same. And I'll simply
- 28:40refer to this library, the PAY library,
- 28:42by its shorter name, but you don't have
- 28:44to add the alias. That's up to you, of
- 28:48course. So what do I want to do? I want
- 28:51to create this matrix. Again, it's very
- 28:54convenient to create a matrix if we're
- 28:56using PAY. Let's initially create a
- 28:58variable. Let's call it KNNEL. Since
- 29:00we'll be substituting kрnel here, yes,
- 29:02we'll name the parameter that way, too.
- 29:05Here, we're accessing our library,
- 29:07accessing a method called. And what
- 29:12this method does is create a matrix in
- 29:14which all elements will have the value
- 29:16one. And here we simply specify the
- 29:20number of elements in the first list
- 29:22and the number of elements in all
- 29:23subsequent lists. So, for example, I'll
- 29:26just say that our first list here will
- 29:28have five elements. So, well,
- 29:29essentially, there will be five more
- 29:32lists like this. And each of these
- 29:33lists will have five elements. For
- 29:35example, one 1 one. And so on. So, five
- 29:38elements. To indicate this, I specify a
- 29:41tuple here and specify that our first
- 29:43list consists of five elements. And
- 29:45each of the following lists will also
- 29:47have five elements. Plus, we can
- 29:50additionally specify the format of
- 29:52these numbers themselves. For this, we
- 29:55again turn to us. And here we simply
- 29:58specify the data type. I'll use a data
- 30:00type like u in. Let's write it
- 30:03correctly. U in 8. So, this means that
- 30:06we can only have numbers that are
- 30:08greater than zero. And these are
- 30:11integers, yes, 1 2 3 4 and so on. We've
- 30:14specified this format here. Now,
- 30:15finally, we can specify the kernel here
- 30:18. So, we'll create the matrix we need.
- 30:21We also need to specify the iteration
- 30:23value here. Iteration is simply a loop
- 30:26—yes, how many times will the code we
- 30:28need execute? Well, in fact, if I
- 30:30specify, for example, a value of 10
- 30:32here, then a very, very large outline
- 30:35will be added. Let's start with a value
- 30:37of one and just try to test it, and
- 30:39then increase this value a little later
- 30:40. And so, we can see that, see, if I
- 30:43specify one, we notice that all our
- 30:45outlines become much larger, right? In
- 30:49fact, we understand that all these
- 30:50numbers, or rather, all these outlines,
- 30:52are already connected to each other. If
- 30:55there were any gaps somewhere before,
- 30:57now these gaps are clearly gone. And,
- 31:00of course, in this case, if we actually
- 31:02use additional increase in the outline,
- 31:05then in fact, we can, of course,
- 31:06increase the precision here. Let's say
- 31:10we set 150 here, or maybe even 250, or
- 31:13better yet, let's just set it to 200.
- 31:15Again, we stop the program and restart
- 31:18it. And here's what we get, right? So,
- 31:22we've reduced the precision of all
- 31:24these outlines, while increasing the
- 31:25thickness of these outlines, and what
- 31:27we get is a picture that essentially
- 31:32looks exactly the same as before. But
- 31:34since there are fewer lines, further
- 31:36processing of the picture will be
- 31:38faster, right? So, the more of these
- 31:41angles, the more of these lines, the
- 31:42longer the further processing of the
- 31:44picture will take. At this point, we've
- 31:46done everything logically. We've
- 31:48reduced, well, the number of angles,
- 31:50but increased the thickness. And
- 31:55finally, to optimize all of this even
- 31:57more thoroughly, after we've converted
- 31:59the image to binary format, after we've
- 32:01specified all these angles (and we've
- 32:03specified them quite small), after
- 32:05we've increased the line weight, we'll
- 32:07further decrease this line weight a
- 32:08little. That is, by using the line
- 32:13weight, we were able to simply outline
- 32:15all the necessary contours. Moreover,
- 32:18once we've outlined all these
- 32:19additional contours, we were able to
- 32:21specify a lower precision. And now,
- 32:24after we've clearly found everything we
- 32:26need, we can simply reduce these
- 32:28contours. We can reduce this outline's
- 32:30thickness. After this, we'll get
- 32:34exactly the same image as the original,
- 32:36but we'll now specify a lower precision
- 32:38here, which will speed up future image
- 32:40processing. So, let's implement this.
- 32:43To do this, we'll again place
- 32:45everything in the same variable. Here
- 32:47I'm using a method where we specify
- 32:49which image we're working with. That's
- 32:51G. We also need to specify the kernel
- 32:53here, plus we need to specify the
- 32:55number of iterations. Let's say there's
- 32:57only one iteration here, right? If we
- 33:00run this now, this is what we get. Yes,
- 33:03in some cases, we didn't process
- 33:05everything perfectly, but for the
- 33:07computer, everything was simply perfect
- 33:09. What's the main thing we got? We got
- 33:14the image, it's in binary format. We
- 33:18used lower precision to process it, and
- 33:20thereby increased the overall
- 33:22processing speed of the entire image.
- 33:26We also initially increased the outline
- 33:28so that we could 100%cover all the
- 33:30necessary corners. And then, to make it
- 33:35all more pleasant to look at—or
- 33:36rather, not even more pleasant, but so
- 33:38that the computer could process it all
- 33:40faster—we reduced the number of these
- 33:42white dots, and essentially got the
- 33:44image we needed. So, it's very easy to
- 33:47recognize such an image in the future.
- 33:49So, in the future, we'll be working
- 33:51with images like these. And we'll be
- 33:53recognizing various objects in them.
- 33:55For example, we'll be recognizing
- 33:57numbers or symbols, right? So, we'll be
- 33:59reading license plates. And in the
- 34:02future, we'll also be recognizing
- 34:04various faces, right? And to do that,
- 34:07we'll also be converting the image to
- 34:09binary format. Well, that concludes our
- 34:11lesson. I hope you enjoyed it. If so,
- 34:14don't forget to subscribe to the
- 34:16channel and join our social media
- 34:17accounts. All the links will be in the
- 34:19description of this video. That's all
- 34:21for now from me. See you soon. Bye. M.
About this transcript
This page contains the full transcript of Изучение Python OpenCV / Урок #2 – Работа с изображениями и видео by Гоша Дударь, generated from the public captions YouTube serves with the video. The transcript has 5,778 words across 839 segments, with the original timestamps preserved so you can click any line to jump to that moment in the embedded player.
What you can do with it
Use the transcript to take notes, quote the speaker, build a study guide, generate a summary with ChatGPT or Claude via the YouTube Summary tool, or export it as a timed subtitle file with YouTube to SRT. You can also re-open it in the transcriber to translate the transcript into 100+ languages.
Free YouTube transcript tool
YouTube2Text is a free YouTube transcript generator — no signup, no daily limit. Paste any YouTube link and get the full transcript instantly, with timestamps, click-to-jump, translation to 100+ languages, AI prompts for ChatGPT, Claude, and Gemini, and exports to TXT, SRT, VTT, or Markdown.