Если можете, используйте 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)
Если вы проверяете одну и ту же область исходного изображения и изображения с пороговым значением, вы можете увидеть улучшение (здесь, возможно, слишком мало):
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()
Это результат, который вы должны получить ( см. Перекрытие внутренних и внешних контуров ):
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)
введите описание изображения здесь