Как вырезать изображение по контуру opencv python
Перейти к содержимому

Как вырезать изображение по контуру opencv python

  • автор:

Как обрезать изображение по его контурной границе с помощью Python

У меня в основном есть тысячи изображений персонажей с черными очертаниями, все эти изображения имеют либо белый фон, либо какой-то графический фон, обычно просто текстуру дерева позади.

Я хочу создать функцию (opencv / pil / something), которая позволит мне просто автоматически обрезать эти изображения, в основном удаляя все, что находится за пределами контура персонажа.

Here

Слева — исходное изображение без кадра, справа — обрезанное изображение. Это вообще возможно?

1 ответ

Используя простые методы, вы можете добраться туда. Предполагая, что на фоне нет черного цвета, мы можем найти выделенный символ, просто замаскировав черный цвет.

enter image description here

Затем мы хотим заполнить все внутри контура.

enter image description here

И, наконец, мы можем просто затушевать все, что находится за пределами маски.

enter image description here

Очевидная проблема с этой конкретной картинкой заключается в том, что мы в конечном итоге ловим заключенный фон в руке мистера Бина. Я не вижу простого способа исправить это. Мы могли бы попробовать сопоставить цветовую гистограмму в области внутри маски; попробуйте найти области внутри маски с тем же цветовым профилем, что и область за пределами маски, но это будет намного сложнее, чем представленный в настоящее время код.

Если текущий метод будет работать для большинства ваших изображений, а остальные вы легко можете отредактировать вручную, сделайте это. Если это действительно неприемлемо в качестве ответа, дайте мне знать, и я попытаюсь решить его, если у меня будет время.

OpenCV в Python. Часть 4

Привет, Хабр! В этой статье я бы хотел рассказать как с помощью только OpenCV распознавать объекты, на примере игральных карт:

Введение

Допустим, у нас имеется следующее изображение с картами:

А также у нас имеются эталонные изображения каждой карты:

И теперь для того, чтобы детектировать каждую карту, нам необходимо написать три ключевые функции, которые:

  • находит контуры всех карт;
  • находит координаты каждой отдельной карты;
  • распознаёт карту с помощью ключевых точек.

Нахождение контуров карт

Первым аргументом в данную функцию мы передаём изображение в оттенках серого, к которому применяем гауссово размытие, для того, чтобы было легче найти контуры карт. После этого с помощью функции threshold() мы преобразуем наше серое изображение в бинарное. Данная функция принимает первым параметром изображение, вторым — пороговое значение, третьим — это максимальное значение, которое присваивается значениям пикселей, превышающим пороговое значение. Из нашего примера следует, что любое значение пикселя, превышающее 215, устанавливается равным 255, а любое значение, которое меньше 215, устанавливается равным нулю. И последним параметром передаём метод порогового значения. Мы используем THRESH_BINARY(), который указывает на то, что значения пикселей, которые больше 215 устанавливаются в максимальное значение, которое мы передали третьим параметром. Данная функция возвращает два значения, где первое — это значение, которое мы передали в данную функцию вторым аргументом, а второе — чёрно-белое изображение, которое выглядит подобным образом:

Теперь мы можем найти контуры наших карт, где контур — это кривая, соединяющая все непрерывные точки, которые имеют одинаковый цвет. Поиск контуров осуществляется с помощью метода findContours(), где в качестве первого аргумента эта функция принимает изображение, вторым — это тип контуров, который мы хотим извлечь. Я использую cv2.RETR_EXTERNAL для извлечения только внешних контуров. К примеру, для того, чтобы извлечь все контуры используют cv2.RETR_LIST, а последний параметром мы указываем метод аппроксимации контура. Мы используем cv2.CHAIN_APPROX_SIMPLE, указывая на то, что все лишние точки будут удалены, тем самым экономя память. Например, если вы нашли контур прямой линии, то разве вам нужны все точки этой линии, чтобы представить эту линию? Нет, нам нужны только две конечные точки этой линии. Это как раз то, что и делает cv2.CHAIN_APPROX_SIMPLE.

Нахождение координат карт

Данная функция принимает контуры, которые мы нашли в предыдущей функции, а также основное изображение в оттенках серого. Первым делом мы создаём словарь, где в роли ключа будет выступать название карты, а в роли значения координаты каждой карты. Далее мы проходимся в цикле по нашим контурам, где с помощью функции boundingRect() находим ограничительные рамки каждого контура: начальные x и y координаты, за которыми следуют ширина и высота рамки. Так получилось, что функция, которая искала контура, нашла аж 31 контур, хотя карт всего 4. Это могут быть незначительные контуры, которые мы дальше сортируем в условии, исходя из размера контура.

Теперь, зная координаты контура, мы можем вырезать по этим координатам каждую карту, что собственно мы и делаем в следующей строчке кода. Далее вырезанное изображение мы передаём в функцию find_features()(о ней мы поговорим ниже), которая опираясь на ключевые точки, возвращает нам название вырезанной карты. После этого добавляем всё в словарь.

Распознавание карт

Как говорилось выше, распознавание карт будет осуществляться на основе ключевых точек. Ключевые точки — это интересные области изображения. Интересными участками называются такие участки, которые неоднородны. Например, это могут быть углы, так как там происходит резкое изменение интенсивности в двух разных направлениях. Если мы посмотрим на изображение ниже, а потом закроем глаза и попытаемся визуализировать этот образ, то мы вряд ли сможем увидеть что-то конкретное и особенное на этом изображении. Причина этого в том, что изображение не содержит никакой интересной информации:

Теперь закройте глаза и попытайтесь представить это изображение:

И вы увидите, что помните много деталей об этом образе. Причина этого в том, что на изображении много интересных областей. Теперь переходим к практике:

Для обнаружения ключевых точек я использую ORB, который мы инициализируем с помощью вызова функции ORB_create(), после чего мы находим ключевые точки и дискрипторы(которые кодируют интересную информацию в ряд чисел) для эталонной карты и для карты, которую мы вырезали из главного изображения. Вот, к примеру, как выглядят ключевые точки для короля:

Затем нам необходимо сопоставить(вычислить расстояние) дискрипторы первого изображения с дискрипторами второго и взять ближайший. Для этого мы создаём BFMatcher объект с помощью вызова метода BFMatcher(). Теперь мы можем с помощью функции knnMatch() найти k лучших совпадений для каждого дескриптора, где k в нашем случае равно 2. Далее нам необходимо выбрать только хорошие совпадения, основываясь на расстоянии. Поэтому мы проходимся в цикле по нашим совпадениям и если оно удовлетворяет условию m.distance < 0.75*n.distance, то мы засчитываем это совпадение как хорошее и добавляем в список. Потом считаем количество хороших совпадений(чем больше, тем лучше) и основываясь на этом делаем вывод, что за карта. Вот какие совпадения были найдены для каждой карты с королём:

И вслед за этим рисуем прямоугольник вокруг карты с помощью функции draw_rectangle_aroud_cards():

На этом всё. Надеюсь, было познавательно) Код и картинки можно найти на github. До новых встреч:)

OpenCV: Automatic select big contour areas and remove

Create a Mask using opencv python by color selection and contours filtering

Nicola Landro

Using OpenCV with python to select for color some areas into the images and after maintain only the biggest areas and remove it from image with the obtained mask.

Requirements

The requirements are only Python3 installed and installed libraries opencv, matplotlib and jupyter notebook, but I will use a colab notebook.
Remember that opencv on linux need to install it by pip and also with your package manager you mast instal python3-opencv, so if you are locally:

Now you can use Colab or run your jupyter notebook locally with:

Preparation

At first we need an image that we can download with that command into the notebook:

We also need to import the library that we will use:

Read and show image

To show an image file is simple on jupyter notebook:

But we need to read it with opencv to elaborate:

(Remember if you do plt.imshow(img) it will plot the image but with wrong color because matplotlib use RGB instead opencv have BGR)

Select Color

To select for color we must chouse a range of colors and after we can exec:

Now we can plot the mask obtained:

Select biggest Areas

Now we want to select only the biggest areas

Remove contour from image

So now we can remove it from image:

Now we have the script to remove also to alarge number of images the area with same properties.

Conclusions

Opencv have the same potential of GIMP (or Photoshop), but it enable you to scriptize the function, also ffmpeg give this capability, but you can also create plugin for GIMP.
So is not importat witch technique you will use, but contrinbute to opensource because it give you all that softwers!

How to crop the internal area of a contour?

I am working on Retinal fundus images.The image consists of a circular retina on a black background. With OpenCV, I have managed to get a contour which surrounds the whole circular Retina. What I need is to crop out the circular retina from the black background.

3 Answers 3

It is unclear in your question whether you want to actually crop out the information that is defined within the contour or mask out the information that isn’t relevant to the contour chosen. I’ll explore what to do in both situations.

Masking out the information

Assuming you ran cv2.findContours on your image, you will have received a structure that lists all of the contours available in your image. I’m also assuming that you know the index of the contour that was used to surround the object you want. Assuming this is stored in idx , first use cv2.drawContours to draw a filled version of this contour onto a blank image, then use this image to index into your image to extract out the object. This logic masks out any irrelevant information and only retain what is important — which is defined within the contour you have selected. The code to do this would look something like the following, assuming your image is a grayscale image stored in img :

If you actually want to crop.

If you want to crop the image, you need to define the minimum spanning bounding box of the area defined by the contour. You can find the top left and lower right corner of the bounding box, then use indexing to crop out what you need. The code will be the same as before, but there will be an additional cropping step:

The cropping code works such that when we define the mask to extract out the area defined by the contour, we additionally find the smallest horizontal and vertical coordinates which define the top left corner of the contour. We similarly find the largest horizontal and vertical coordinates that define the bottom left corner of the contour. We then use indexing with these coordinates to crop what we actually need. Note that this performs cropping on the masked image — that is the image that removes everything but the information contained within the largest contour.

Note with OpenCV 3.x

It should be noted that the above code assumes you are using OpenCV 2.4.x. Take note that in OpenCV 3.x, the definition of cv2.findContours has changed. Specifically, the output is a three element tuple output where the first image is the source image, while the other two parameters are the same as in OpenCV 2.4.x. Therefore, simply change the cv2.findContours statement in the above code to ignore the first output:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *