Как заполнить дыры в изображении - PullRequest
2 голосов
/ 20 июня 2020

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

С точки зрения разброса: plot:

mlist_0 = movelist_porous[0]
rx = np.round(mlist_0[:,0])
ry = np.round(mlist_0[:,1])
fig, axs = plt.subplots(1,1,figsize=(12,8))
axs.plot(mlist_0[:,0], mlist_0[:,1], color='black')
plt.axis('off')
plt.savefig("test.png", bbox_inches='tight')
plt.show()
image

Я бы хотел получить такой результат:

image

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

Ответы [ 2 ]

5 голосов
/ 20 июня 2020

Здесь вы go, начиная с изображения из сюжета.

import numpy as np
import cv2

# Reading the image saved from plot
image = cv2.imread('test.jpg')

# Coversion to grayscale, inversion, edge detection
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.bitwise_not(gray)
edges = cv2.Canny(gray, 50, 200)

# Find the contours. The first two largest contours are for the outer contour
# So, taking the rest of the contours for inner contours
cnts = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[2:]

# Filling the inner contours with black color
for c in cnts:
    cv2.drawContours(image, [c], -1, (0, 0, 0), -1)

# Displaying the result
cv2.imshow("Contour", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Результат из кода:

enter image description here

2 голосов
/ 20 июня 2020

Если можете, используйте Jupyter Notebook с matplotlib.

Начиная с графика, я предлагаю вам использовать пороговую обработку, чтобы избавиться от шума вокруг линии.

im = cv2.imread('Fpeck.jpg', cv2.IMREAD_GRAYSCALE)
threshold = 127
apply_val = 255
ret, th = cv2.threshold(im, threshold, apply_val, cv2.THRESH_BINARY)

Если вы проверяете одну и ту же область исходного изображения и изображения с пороговым значением, вы можете увидеть улучшение (здесь, возможно, слишком мало):

enter image description here

Show the images side by side using this code:

original_vs_thresholded = np.concatenate([im[160:200,0:40], th[160:200,0:40]], axis=1)

After that find the contours on the thresholded image using cv2.RETR_TREE as retrieval mode, see https://docs.opencv.org/4.1.0/d9/d8b/tutorial_py_contours_hierarchy.html:

contours, hierarchy = cv2.findContours(th, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

Если вы напечатаете hierarchy, вы можете увидеть контуры и вложение, он содержит список индексов, где:

  • столбец (a) - это индекс следующего элемента в тот же уровень
  • столбец (b) - это индекс предыдущего элемента на том же уровне
  • столбец (c) - индекс дочернего контура
  • столбец ( г) - это индекс родительского контура

Это hierarchy:

#=>    a  b  c  d
#=>  [-1 -1  1 -1] <- boundary of the image
#=>  [-1 -1  2  0] <- bigger oval, external of the line
#=>  [-1 -1  3  1] <- bigger oval, internal of the line
#=>  [ 5 -1  4  2] <- shape1, external of the line
#=>  [-1 -1 -1  3] <- shape1, internal of the line
#=>  [ 7  3  6  2] <- and so on ...
#=>  [-1 -1 -1  5]
#=>  [ 9  5  8  2]
#=>  [-1 -1 -1  7]
#=>  [11  7 10  2]
#=>  [-1 -1 -1  9]
#=>  [13  9 12  2]
#=>  [-1 -1 -1 11]
#=>  [-1 11 14  2]
#=>  [-1 -1 -1 13]

Например, hierarchy[0][5] имеет значения [ 7 3 6 2] и соответствует contours[5].

Надеюсь, это даст вам базовое c понимание того, как выбрать правильный контур для построения окончательного sult.

Например, сбор индексов контуров, где hierarchy[0][0] == -1 или hierarchy[0][3] == 2.


Вы можете построить последовательность рисования контура, используя этот код в записной книжке:
im_cnt_th = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR)
for n, contour in enumerate(contours):
    color = tuple(int(n) for n in np.random.randint(256, size=3))
    print(color)
    cv2.drawContours(im_cnt_th, [contour], -1, color, cv2.FILLED)
    print(f'index: {n} - hyerarchy: {hierarchy[0][n]}')
    plt.imshow(im_cnt_th[:,:,::-1])
    plt.show()

Это результат, который вы должны получить ( см. Перекрытие внутренних и внешних контуров ):

enter image description here


Finally

For the required result, find the inner shape indexes:

inner_shapes_indexes = [ idx for idx, h in enumerate(hierarchy[0]) if h[3] == 2] # parent contour is indexed 2 in hierarchy

Then, build a black image, plot in white the oval, plot in black the inner shapes:

new_im = np.zeros_like(im)
cv2.drawContours(new_im, [contours[1]], -1, 255, cv2.FILLED)
for idx in inner_shapes_indexes:
    cv2.drawContours(new_im, [contours[idx]], -1, 0, cv2.FILLED)

введите описание изображения здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...