Как нарисовать фигуры на пустом изображении точно такими, какими они были в исходном изображении, используя OpenCV?

#python #numpy #opencv #contour #opencv-drawcontour

#python #numpy #opencv #контур

Вопрос:

У меня есть исходное изображение (черный фон и белые объекты), и я хочу найти контуры на этом изображении, создать новое пустое изображение с черным фоном и нарисовать контуры на этом изображении один за другим, как они были на исходном изображении. Я знаю, как найти контуры и создать пустое изображение, но у меня возникают проблемы с рисованием контуров так же, как они были в исходном изображении. Я получаю некоторые результаты, но цветная заливка иногда заполняется неправильно или просто выглядит неправильно. Я думал, должен ли я получить обратную сторону контуров и заполнить ее, но я не уверен, как это сделать или возможно ли это. Что я в основном хочу сделать, это нарисовать фигуры изображения на видео один за другим.

Вот мой код.

 import cv2
import numpy as np
import sys
import statistics as st


# Function to denoise images
def denoise(contours):
    # Array that contains contours that will be removed
    filtered_cont = []
    sample = []
    # Gathering sample
    for contour in contours:
        sample.append(len(contour))
    # Calculating standard deviation
    stdev = st.stdev(sample)
    for contour in contours:
        # Comparing contour length to standard deviation divided by 3
        if len(contour) < stdev/3:
            # Appending small contours to an array
            filtered_cont.append(contour)
    return filtered_cont

img = cv2.imread(sys.argv[1])

# Getting image dimensions
h,w,l = img.shape
size = (w,h)

gray_image=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
contours,hierarchy=cv2.findContours(gray_image,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)

noisy_contours = denoise(contours)
# Filtering out noise
cv2.drawContours(img,noisy_contours,-1,color=(0,0,0),thickness=cv2.FILLED)
# Saving denoised image
cv2.imwrite('contours-denoised.png',img)


filtered=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edged=cv2.Canny(filtered,20,100)

# Creating blank black image
blank_image= np.zeros((h, w, 3), np.uint8)

# Finding contours from denoised image
contours,hierarchy=cv2.findContours(edged,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
# Sorting contours from large to small
contours.sort(key=len,reverse=True)

# Initializing video output
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('project.mp4',fourcc, 10, size)

# Iterating through contours
for  cont in contours:
    # Drawing one contour and filling it with white
    cv2.drawContours(blank_image, [cont], -1, color=(255, 255, 255), thickness=cv2.FILLED)
    # Writing image into video stream
    out.write(blank_image)
out.release()

# Saving image
cv2.imwrite('contours-denoised-drawn.png',blank_image)
  

Исходное изображение
Исходное изображение

Исходное изображение с шумом Исходное изображение с шумом

Изображение с шумом после обнаружения краев Хитрые края

Нарисованная версия изображения с шумом Нарисованная версия изображения с шумом (после Canny)

Комментарии:

1. Можете ли вы добавить изображение после canny?

2. @Ema Я добавил изображение в свой пост. на 3-м рисунке показаны тонкие края.

3. OpenCV drawcontours решает, какая область между контурами должна быть заполнена условием иерархии контуров, шаг denoise, который удаляет небольшие контуры, может повлиять на условие иерархии контуров, но я думал, что вы уже получили то, что хотите, в строке «cv2.imwrite(‘contours-denoised.png’,img)» хотя.

4. @Ema Я попытался прокомментировать функцию шумоподавления, но результат все равно испорчен. И вы правы, я хочу, чтобы мое изображение выглядело так, как оно выглядит после cv2.imwrite (‘contours-denoised.png’, img), но я хочу иметь возможность рисовать его по одному контуру за раз. Поэтому, когда я вставляю эти изображения в видео, это будет выглядеть так, как будто компьютер рисует линии по одной за раз.