Задачи компьютерного зрения — поиск объектов нужного цвета
Сегодня я расскажу о том как распознать контур нужного цвета с помощью python/ opencv такая задача часто встречается в робототехнике, и всяких автоматизациях.
С помощью предложенного решения можно например различать контур линии за которую не должен выезжать робот, или обьект для коптера. Такая задача может возникнуть если нужно например увидеть что в корзину положили апельсин.
Чему научимся
Изначально я предполагаю что у человека есть python ide(подойдет практически любое) и базовое знание питона.
Установим библиотеку OpenCV с помощью следующей команды:
Добавим необходимые библиотеки:
Создадим обьект cup куда будет идти видео. 0 — камера дефолтная, 1 — кастомная.
считывает кадр. вместо _ может быть rate — туда пойдет fps камеры, но в данном случае я этим не пользуюсь.
А теперь давайте обработаем кадр для дальнейшего удобства. Уменьшим:
Рассмотрим подробнее функцию resize:
А теперь давайте на обработанном кадре распознаем контуры и отсортируем их:
А теперь давайте рассмотрим findContours подробнее:

Визуализация RETR_TREE: 
И теперь нарисуем контуры которые нашли:
И по нажатию кнопки останавливаем чтение камеры и закрываем все окна:
Спасибо за прочтение статьи.
Буду признателен если вы подпишитесь на мой канал в
Upd — забавно что статья набрала примерно в 8 раз меньше просмотров чем ожидалось, но при этом примерно расчетное количество " добавлено в закладки" всего в два раза больше. Так и живем.
Русские Блоги
[Python + OpenCV] Определение цветных квадратов и извлечение контуров
Некоторое время назад я разрабатывал комплексный дизайн «Крестики-нолики» с помощью роботизированной руки. Я напрямую купил устройство для роботизированной руки (включая роботизированную руку, камеру и малиновый пирог по цене 1600 юаней) в Интернете. Роботизированная рука не очень продвинута и имеет невысокую точность. Исходный код обеспечивает распознавание и захват трех цветных квадратов: красного, зеленого и синего.
После многих попыток было окончательно решено, что в кусках Tic-Tac-Toe также используются цветные квадраты размером 3 см * 3 см * 3 см. Сегодня я напишу несколько первых шагов, и первый шаг — решить проблему определения цветных квадратов.
Визуализация презентации
Перемещайте блок вручную, внешний контур всегда соответствует краю блока. 
Используйте встроенную камеру ноутбука, чтобы сделать снимок и определить зеленый квадрат.
Анализ кода
1 Прочтите изображение
Используйте python для чтения изображения с камеры, можно ссылаться на:[Python + OpenCV] Захват ноутбука и внешней камеры
2 Определение цвета
Если вы просто хотите распознать зеленый цвет, то этот абзац является лишним. Но если вы хотите определить красный или синий, вы можете напрямую ball_color = ‘green’ Изменить на ball_color = ‘red’ Или ball_color = ‘blue’ . из их color_dist Включен диапазон цветов в режиме HSV, который будет объяснен позже.
3 Обработка изображений
Первый шаг, размытие по Гауссу
Размытие исходного изображения для облегчения выделения цвета
gs_frame = cv2.GaussianBlur(frame, (5, 5), 0) ,из их
Параметр 1: frame Изображения, требующие размытия по Гауссу
Второй параметр: (5, 5) Длина и ширина гауссовой матрицы равны 5.
Третий параметр: 0 Стандартное отклонение равно 0
Необработанное исходное изображение выглядит следующим образом (эта камера слишком пикантная, исходное изображение выглядит очень размытым):
Размытое изображение по Гауссу (посмотрите внимательно, вы обнаружите, что оно более размытое, чем предыдущее)
На втором этапе BGR преобразуется в HSV.
Цветовой режим изображения сразу после преобразования размытия по Гауссу из BGR в HSV (в OpenCV режим RGB не используется, но используется режим BGR). Зачем использовать режим HSV? Поскольку в этом режиме удобнее извлекать один цвет, я не понимаю конкретного принципа.
hsv = cv2.cvtColor(gs_frame, cv2.COLOR_BGR2HSV)
Параметр 1: gs_frame Исходное изображение
Второй параметр: cv2.COLOR_BGR2HSV Метод преобразования цвета из BGR в HSV
Изображение в режиме HSV:
Шаг третий, коррозия
С точки зрения непрофессионала, изображение утончается, чтобы удалить точки шума.
erode_hsv = cv2.erode(hsv, None, iterations=2)
Параметр 1: hsv Исходное изображение
Третий параметр: iterations=2 Ширина коррозии
Видно, что помех намного меньше (фиолетовых точек намного меньше).
Четвертый шаг — удалить фоновую часть.
Удалите другие части, кроме зеленого, и преобразуйте изображение в двоичное изображение.
inRange_hsv = cv2.inRange(erode_hsv, color_dist[ball_color][‘Lower’], color_dist[ball_color][‘Upper’])
Параметр 1: erode_hsv Исходное изображение
Второй параметр: color_dist[ball_color][‘Lower’] Нижняя граница цвета
Третий параметр: color_dist[ball_color][‘Upper’] Верхний предел цвета
Как показано
4 Нарисуйте прямоугольную границу
Первый шаг — найти внешнюю границу
cnts = cv2.findContours(inRange_hsv.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
Используйте эту функцию, чтобы найти внешнюю границу поля и сохранить ее в cnts.
findContours ссылки
Второй шаг — найти прямоугольник
Найдите область с наибольшей областью в границе, выберите эту область как область, где расположен квадрат, нарисуйте наименьший ограничивающий прямоугольник области и запишите координаты положения прямоугольника. .
c = max(cnts, key=cv2.contourArea) Найдите самую большую площадь в границе
rect = cv2.minAreaRect(c) Нарисуйте наименьший ограничивающий прямоугольник области
box = cv2.boxPoints(rect) Запишите координаты положения четырех точек прямоугольника.
Третий шаг — нарисовать прямоугольник.
Нарисуйте границу анализируемого прямоугольника на исходном изображении.
cv2.drawContours(frame, [np.int0(box)], -1, (0, 255, 255), 2)
Параметр 1: frame Целевое изображение
Второй параметр: [np.int0(box)] Сам контур представляет собой список на Python
Третий параметр: -1 Укажите, какой контур в списке контуров рисовать, если -1, нарисуйте в нем все контуры.
Четвертый параметр: (0, 255, 255) Цвет контура BGR
Пятый параметр: 2 Ширина профиля
Окончательный результат показан на рисунке. 
Изображение в начале статьи — это изображение, снятое встроенной камерой ноутбука;
Чтобы упростить захват изображения, изображение в процессе анализа кода представляет собой внешнюю USB-камеру, а количество пикселей слишком мало.
Найти доминирующий цвет на контуре OpenCV
Я пытаюсь найти доминирующий цвет внутри контура (черный или белый). Я использую OpenCV для чтения изображения и извлечения белого на черных изображениях. Это то, что я получил так далеко: 
Зеленый контур — это контур, синие — ограничивающий прямоугольник. Таким образом, в этом случае я пытаюсь извлечь числа 87575220, но, как вы можете видеть, он также распознает некоторые случайные артефакты и, например, букву G. Я думаю, что решением было бы найти доминирующий цвет внутри контуров, и этот цвет должен быть близко к белому. Я понятия не имею, как это сделать, хотя.
Этот код у меня на данный момент:
Это оригинальная картина: 
3 ответа
Я попытался бы сделать ROI прежде, чем я начну искать числа. Вы не указали исходное изображение, поэтому этот пример сделан с размещенным вами изображением (с уже нарисованными рамками и контурами). Должен также работать с оригиналом, хотя. Шаги написаны в примере кода. Надеюсь, поможет. Ура!
Contour Detection using OpenCV (Python/C++)

Using contour detection, we can detect the borders of objects, and localize them easily in an image. It is often the first step for many interesting applications, such as image-foreground extraction, simple-image segmentation, detection and recognition.
So let’s learn about contours and contour detection, using OpenCV, and see for ourselves how they can be used to build various applications.
Contents
Application of Contours in Computer Vision
Some really cool applications have been built, using contours for motion detection or segmentation. Here are some examples:
- Motion Detection:In surveillance video, motion detection technology has numerous applications, ranging from indoor and outdoor security environments, traffic control, behaviour detection during sports activities, detection of unattended objects, and even compression of video. In the figure below, see how detecting the movement of people in a video stream could be useful in a surveillance application. Notice how the group of people standing still in the left side of the image are not detected. Only those in motion are captured. Do refer to this paper to study this approach in detail.

- Unattended object detection: Any unattended object in public places is generally considered as a suspicious object. An effective and safe solution could be: (Unattended Object Detection through Contour Formation using Background Subtraction).
- Background / Foreground Segmentation: To replace the background of an image with another, you need to perform image-foreground extraction (similar to image segmentation). Using contours is one approach that can be used to perform segmentation. Refer to this post for more details. The following images show simple examples of such an application:

Master Generative AI for CV
What are Contours
When we join all the points on the boundary of an object, we get a contour. Typically, a specific contour refers to boundary pixels that have the same color and intensity. OpenCV makes it really easy to find and draw contours in images. It provides two simple functions:
- findContours()
- drawContours()
Also, it has two different algorithms for contour detection:
- CHAIN_APPROX_SIMPLE
- CHAIN_APPROX_NONE
We will cover these in detail, in the examples below. The following figure shows how these algorithms can detect the contours of simple objects.

Now that you have been introduced to contours, let’s discuss the steps involved in their detection.
Steps for Detecting and Drawing Contours in OpenCV
OpenCV makes this a fairly simple task. Just follow these steps:
- Read the Image and convert it to Grayscale Format
Read the image and convert the image to grayscale format. Converting the image to grayscale is very important as it prepares the image for the next step. Converting the image to a single channel grayscale image is important for thresholding, which in turn is necessary for the contour detection algorithm to work properly.
- Apply Binary Thresholding
While finding contours, first always apply binary thresholding or Canny edge detection to the grayscale image. Here, we will apply binary thresholding.
This converts the image to black and white, highlighting the objects-of-interest to make things easy for the contour-detection algorithm. Thresholding turns the border of the object in the image completely white, with all pixels having the same intensity. The algorithm can now detect the borders of the objects from these white pixels.
Note: The black pixels, having value 0, are perceived as background pixels and ignored.
At this point, one question may arise. What if we use single channels like R (red), G (green), or B (blue) instead of grayscale (thresholded) images? In such a case, the contour detection algorithm will not work well. As we discussed previously, the algorithm looks for borders, and similar intensity pixels to detect the contours. A binary image provides this information much better than a single (RGB) color channel image. In a later portion of the blog, we have resultant images when using only a single R, G, or B channel instead of grayscale and thresholded images.
- Find the Contours
Use the findContours() function to detect the contours in the image.
- Draw Contours on the Original RGB Image.
Once contours have been identified, use the drawContours() function to overlay the contours on the original RGB image.
The above steps will make much more sense, and become even clearer when we will start to code.
Finding and Drawing Contours using OpenCV
Start by importing OpenCV, and reading the input image.
Python:
Download Code To easily follow along this tutorial, please download code by clicking on the button below. It’s FREE!
We assume that the image is inside the input folder of the current project directory. The next step is to convert the image into a grayscale image (single channel format).
Note: All the C++ code is contained within the main() function.
C++:
Next, use the cvtColor() function to convert the original RGB image to a grayscale image.
Python:
C++:
Now, use the threshold() function to apply a binary threshold to the image. Any pixel with a value greater than 150 will be set to a value of 255 (white). All remaining pixels in the resulting image will be set to 0 (black). The threshold value of 150 is a tunable parameter, so you can experiment with it.
After thresholding, visualize the binary image, using the imshow() function as shown below.
Python:
C++:
Check out the image below! It is a binary representation of the original RGB image. You can clearly see how the pen, the borders of the tablet and the phone are all white. The contour algorithm will consider these as objects, and find the contour points around the borders of these white objects.
Note how the background is completely black, including the backside of the phone. Such regions will be ignored by the algorithm. Taking the white pixels around the perimeter of each object as similar-intensity pixels, the algorithm will join them to form a contour based on a similarity measure.

Drawing Contours using CHAIN_APPROX_NONE
Now, let’s find and draw the contours, using the CHAIN_APPROX_NONE method.
Start with the findContours() function. It has three required arguments, as shown below. For optional arguments, please refer to the documentation page here.
- image : The binary input image obtained in the previous step.
- mode : This is the contour-retrieval mode. We provided this as RETR_TREE , which means the algorithm will retrieve all possible contours from the binary image. More contour retrieval modes are available, we will be discussing them too. You can learn more details on these options here.
- method : This defines the contour-approximation method. In this example, we will use CHAIN_APPROX_NONE .Though slightly slower than CHAIN_APPROX_SIMPLE , we will use this method here tol store ALL contour points.
It’s worth emphasizing here that mode refers to the type of contours that will be retrieved, while method refers to which points within a contour are stored. We will be discussing both in more detail below.
It is easy to visualize and understand results from different methods on the same image.
In the code samples below, we therefore make a copy of the original image and then demonstrate the methods (not wanting to edit the original).
Next, use the drawContours() function to overlay the contours on the RGB image. This function has four required and several optional arguments. The first four arguments below are required. For the optional arguments, please refer to the documentation page here.
- image : This is the input RGB image on which you want to draw the contour.
- contours : Indicates the contours obtained from the findContours() function.
- contourIdx : The pixel coordinates of the contour points are listed in the obtained contours. Using this argument, you can specify the index position from this list, indicating exactly which contour point you want to draw. Providing a negative value will draw all the contour points.
- color : This indicates the color of the contour points you want to draw. We are drawing the points in green.
- thickness : This is the thickness of contour points.
Python:
C++:
Executing the above code will produce and display the image shown below. We also save the image to disk.

The following figure shows the original image (on the left), as well as the original image with the contours overlaid (on the right).

As you can see in the above figure, the contours produced by the algorithm do a nice job of identifying the boundary of each object. However, if you look closely at the phone, you will find that it contains more than one contour. Separate contours have been identified for the circular areas associated with the camera lens and light. There are also ‘secondary’ contours, along portions of the edge of the phone.
Keep in mind that the accuracy and quality of the contour algorithm is heavily dependent on the quality of the binary image that is supplied (look at the binary image in the previous section again, you can see the lines associated with these secondary contours). Some applications require high quality contours. In such cases, experiment with different thresholds when creating the binary image, and see if that improves the resulting contours.
There are other approaches that can be used to eliminate unwanted contours from the binary maps prior to contour generation. You can also use more advanced features associated with the contour algorithm that we will be discussing here.
Using Single Channel: Red, Green, or Blue
Just to get an idea, the following are some results when using red, green and blue channels separately, while detecting contours. We discussed this in the contour detection steps previously. The following are the Python and C++ code for the same image as above.
Python:
C++:
The following figure shows the contour detection results for all the three separate color channels.

In the above image we can see that the contour detection algorithm is not able to find the contours properly. This is because it is not able to detect the borders of the objects properly, and also the intensity difference between the pixels is not well defined. This is the reason we prefer to use a grayscale, and binary thresholded image for detecting contours.
Drawing Contours using CHAIN_APPROX_SIMPLE
Let’s find out now how the CHAIN_APPROX_SIMPLE algorithm works and what makes it different from the CHAIN_APPROX_NONE algorithm.
Here’s the code for it:
Python:
C++:
The only difference here is that we specify the method for findContours() as CHAIN_APPROX_SIMPLE instead of CHAIN_APPROX_NONE .
The CHAIN_APPROX_SIMPLE algorithm compresses horizontal, vertical, and diagonal segments along the contour and leaves only their end points. This means that any of the points along the straight paths will be dismissed, and we will be left with only the end points. For example, consider a contour, along a rectangle. All the contour points, except the four corner points will be dismissed. This method is faster than the CHAIN_APPROX_NONE because the algorithm does not store all the points, uses less memory, and therefore, takes less time to execute.
The following image shows the results.

If you observe closely, there are almost no differences between the outputs of CHAIN_APPROX_NONE and CHAIN_APPROX_SIMPLE.
Now, why is that?
The credit goes to the drawContours() function. Although the CHAIN_APPROX_SIMPLE method typically results in fewer points, the drawContours() function automatically connects adjacent points, joining them even if they are not in the contours list.
So, how do we confirm that the CHAIN_APPROX_SIMPLE algorithm is actually working?
- The most straightforward way is to loop over the contour points manually, and draw a circle on the detected contour coordinates, using OpenCV.
- Also, we use a different image that will actually help us visualize the results of the algorithm.

The following code uses the above image to visualize the effect of the CHAIN_APPROX_SIMPLE algorithm. Almost everything is the same as in the previous code example, except the two additional for loops and some variable names.
- The first for loop cycles over each contour area present in the contours list.
- The second loops over each of the coordinates in that area.
- We then draw a green circle on each coordinate point, using the circle() function from OpenCV.
- Finally, we visualize the results and save it to disk.
Python:
C++:
Executing the code above, produces the following result:

Observe the output image, which is on the right-hand side in the above figure. Note that the vertical and horizontal sides of the book contain only four points at the corners of the book. Also observe that the letters and bird are indicated with discrete points and not line segments.
Contour Hierarchies
Hierarchies denote the parent-child relationship between contours. You will see how each contour-retrieval mode affects contour detection in images, and produces hierarchical results.
Parent-Child Relationship
Objects detected by contour-detection algorithms in an image could be:
- Single objects scattered around in an image (as in the first example), or
- Objects and shapes inside one another
In most cases, where a shape contains more shapes, we can safely conclude that the outer shape is a parent of the inner shape.
Take a look at the following figure, it contains several simple shapes that will help demonstrate contour hierarchies.

Now see below figure, where the contours associated with each shape in Figure 10 have been identified. Each of the numbers in Figure 11 have a significance.
- All the individual numbers, i.e., 1, 2, 3, and 4 are separate objects, according to the contour hierarchy and parent-child relationship.
- We can say that the 3a is a child of 3. Note that 3a represents the interior portion of contour 3.
- Contours 1, 2, and 4 are all parent shapes, without any associated child, and their numbering is thus arbitrary. In other words, contour 2 could have been labeled as 1 and vice-versa.

Contour Relationship Representation
You’ve seen that the findContours() function returns two outputs: The contours list, and the hierarchy. Let’s now understand the contour hierarchy output in detail.
The contour hierarchy is represented as an array, which in turn contains arrays of four values. It is represented as:
[ Next, Previous, First_Child, Parent ]
So, what do all these values mean?
Next : Denotes the next contour in an image, which is at the same hierarchical level. So,
- For contour 1, the next contour at the same hierarchical level is 2. Here, Next will be 2.
- Accordingly, contour 3 has no contour at the same hierarchical level as itself. So, it’s Next value will be -1.
Previous : Denotes the previous contour at the same hierarchical level. This means that contour 1 will always have its Previous value as -1.
First_Child : Denotes the first child contour of the contour we are currently considering.
- Contours 1 and 2 have no children at all. So, the index values for their First_Child will be -1.
- But contour 3 has a child. So, for contour 3, the First_Child position value will be the index position of 3a.
Parent : Denotes the parent contour’s index position for the current contour.
- Contours 1 and 2, as is obvious, do not have any Parent contour.
- For the contour 3a, its Parent is going to be contour 3
- For contour 4, the parent is contour 3a
The above explanations make sense, but how do we actually visualize these hierarchy arrays? The best way is to:
- Use a simple image with lines and shapes like the previous image
- Detect the contours and hierarchies, using different retrieval modes
- Then print the values to visualize them
Different Contour Retrieval Techniques
Thus far, we used one specific retrieval technique, RETR_TREE to find and draw contours, but there are three more contour-retrieval techniques in OpenCV, namely, RETR_LIST , RETR_EXTERNAL and RETR_CCOMP .
So let’s now use the image in Figure 10 to review each of these four methods, along with their associated code to get the contours.
The following code reads the image from disk, converts it to grayscale, and applies binary thresholding.
Python:
C++:
RETR_LIST
The RETR_LIST contour retrieval method does not create any parent child relationship between the extracted contours. So, for all the contour areas that are detected, the First_Child and Parent index position values are always -1.
All the contours will have their corresponding Previous and Next contours as discussed above.
See how the RETR_LIST method is implemented in code.
Python:
C++:
Executing the above code produces the following output:
LIST: [[[ 1 -1 -1 -1]
[ 2 0 -1 -1]
[ 3 1 -1 -1]
[ 4 2 -1 -1]
[-1 3 -1 -1]]]
You can clearly see that the 3rd and 4th index positions of all the detected contour areas are -1, as expected.
RETR_EXTERNAL
The RETR_EXTERNAL contour retrieval method is a really interesting one. It only detects the parent contours, and ignores any child contours. So, all the inner contours like 3a and 4 will not have any points drawn on them.
Python:
C++:
The above code produces the following output:
EXTERNAL: [[[ 1 -1 -1 -1]
[ 2 0 -1 -1]
[-1 1 -1 -1]]]

The above output image shows only the points drawn on contours 1, 2, and 3. Contours 3a and 4 are omitted as they are child contours.
RETR_CCOMP
Unlike RETR_EXTERNAL,RETR_CCOMP retrieves all the contours in an image. Along with that, it also applies a 2-level hierarchy to all the shapes or objects in the image.
- All the outer contours will have hierarchy level 1
- All the inner contours will have hierarchy level 2
But what if we have a contour inside another contour with hierarchy level 2? Just like we have contour 4 after contour 3a.
- Again, contour 4 will have hierarchy level 1.
- If there are any contours inside contour 4, they will have hierarchy level 2.
In the following image, the contours have been numbered according to their hierarchy level, as explained above.

The above image shows the hierarchy level as HL-1 or HL-2 for levels 1 and 2 respectively. Now, let us take a look at the code and the output hierarchy array also.
Python:
C++:
Executing the above code produces the following output:
CCOMP: [[[ 1 -1 -1 -1]
[ 3 0 2 -1]
[-1 -1 -1 1]
[ 4 1 -1 -1]
[-1 3 -1 -1]]]
Here, we see that all the Next , Previous , First_Child , and Parent relationships are maintained, according to the contour-retrieval method, as all the contours are detected. As expected, the Previous of the first contour area is -1. And the contours which do not have any Parent , also have the value -1
RETR_TREE
Just like RETR_CCOMP, RETR_TREE also retrieves all the contours. It also creates a complete hierarchy, with the levels not restricted to 1 or 2. Each contour can have its own hierarchy, in line with the level it is on, and the corresponding parent-child relationship that it has.

From the above figure, it is clear that:
- Contours 1, 2, and 3 are at the same level, that is level 0.
- Contour 3a is present at hierarchy level 1, as it is a child of contour 3.
- Contour 4 is a new contour area, so its hierarchy level is 2.
The following code uses RETR_TREE mode to retrieve contours.
Python:
C++:
Executing the above code produces the following output:
TREE: [[[ 3 -1 1 -1]
[-1 -1 2 0]
[-1 -1 -1 1]
[ 4 0 -1 -1]
[-1 3 -1 -1]]]
Finally, let’s look at the complete image with all the contours drawn when using RETR_TREE mode.

All the contours are drawn as expected, and the contour areas are clearly visible. You also infer that contours 3 and 3a are two separate contours, as they have different contour boundaries and areas. At the same time, it is very evident that contour 3a is a child of contour 3.
Now that you are familiar with all the contour algorithms available in OpenCV, along with their respective input parameters and configurations, go experiment and see for yourself how they work.
A Run Time Comparison of Different Contour Retrieval Methods
It’s not enough to know the contour-retrieval methods. You should also be aware of their relative processing time. The following table compares the runtime for each method discussed above.
- Contour detection can also fail, when the background of the object in the image is full of lines.
Taking Your Learning Further
If you think that you have learned something interesting in this article and would like to expand your knowledge, then you may like the Computer Vision 1 course offered by OpenCV. This is a great course to get started with OpenCV and Computer Vision which will be very hands-on and perfect to get you started and up to speed with OpenCV. The best part, you can take it in either Python or C++, whichever you choose. You can visit the course page here to know more about it.
Summary
You started with contour detection, and learned to implement that in OpenCV. Saw how applications use contours for mobility detection and segmentation. Next, we demonstrated the use of four different retrieval modes and two contour-approximation methods. You also learned to draw contours. We concluded with a discussion of contour hierarchies, and how different contour-retrieval modes affect the drawing of contours on an image.
- The contour-detection algorithms in OpenCV work very well, when the image has a dark background and a well-defined object-of-interest.
- But when the background of the input image is cluttered or has the same pixel intensity as the object-of-interest, the algorithms don’t fare so well.
You have all the code here, why not experiment with different images now! Try images containing varied shapes, and experiment with different threshold values. Also, explore different retrieval modes, using test images that contain nested contours. This way, you can fully appreciate the hierarchical relationships between objects.
Subscribe & Download Code
If you liked this article and would like to download code (C++ and Python) and example images used in this post, please click here. Alternately, sign up to receive a free Computer Vision Resource Guide. In our newsletter, we share OpenCV tutorials and examples written in C++/Python, and Computer Vision and Machine Learning algorithms and news.