#image-processing #image-segmentation #opencv-python #image-thresholding
#обработка изображений #сегментация изображения #opencv-python #изображение-пороговое значение
Вопрос:
Я работаю над проектом, который включает в себя определение объема прозрачной жидкости (или воздуха, если это окажется проще) в ограниченном пространстве. Изображения, с которыми я работаю, представляют собой фоновое изображение контейнера без жидкости и изображение переднего плана, которое в редких случаях также может быть пустым, но в большинстве случаев частично заполнено некоторым количеством жидкости.
Хотя это может показаться довольно простым плавным и пороговым подходом, он оказывается несколько более сложным. Я работаю с набором с тоннами этих пар изображений фоновых и передних изображений, и, похоже, я не могу найти подход, который был бы достаточно надежным для применения ко всем изображениям в наборе. Моя работа до сих пор включает сглаживание и пороговое значение изображения и применение закрытия для его завершения.
bg_image = cv.imread("bg_image", 0)
fg_image = cv.imread("fg_image", 0)
blur_fg = cv.GaussianBlur(fg_image, (5, 5), sigmaX=0, sigmaY=0)
thresholded_image = cv.threshold(blur_fg, 186, 255, cv.THRESH_BINARY_INV)[1]
kernel = np.ones((4,2),np.uint8)
closing = cv.morphologyEx(thresholded_image, cv.MORPH_CLOSE, kernel)
Результаты различаются, вот пример, когда все идет хорошо:
В других примерах это не так хорошо:
Помимо этого, я также пытался:
- Вычитание фоновых и передних изображений
- Контрастное растяжение
- Выравнивание гистограммы
- Другие методы определения порога, такие как Otsu
Основная проблема заключается в том, что интенсивности пикселей в воздухе и жидкости иногда перекрываются (и в целом довольно низкий контраст), что приводит к неточным оценкам. Я склоняюсь к использованию границы, которая возникает между жидкостью и воздухом, но я не совсем уверен, как это сделать..
Я не хочу здесь переполняться информацией, поэтому я оставляю это на этом. Я благодарен за любые предложения и при необходимости могу предоставить дополнительную информацию.
Редактировать:
Вот несколько примеров изображений, с которыми можно поиграть.
Комментарии:
1. Я склоняюсь к использованию границы, которая возникает между жидкостью и воздухом, но я не совсем уверен, как это сделать. Из трех приведенных изображений кажется, что упомянутый «край» довольно темный по сравнению с обеими окружающими областями. Вы пробовали создавать какое-либо градиентное изображение (только горизонтальный градиент), которое также используется для определения границ (Canny, Sobel)? Также, пожалуйста, разместите некоторые фактические входные изображения (не эти графики), чтобы люди здесь могли поиграть.
2. Я использовал обнаружение краев, но не создал градиентное изображение. Но скажем, что можно выделить четкий край, как это может помочь в оценке объема? Я думал, что его можно использовать для определения длины области, в которой находится жидкость. Другим подходом может быть применение некоторого адаптированного порогового значения к различным областям, разделенным краем. Я добавил две пары входных изображений.
Ответ №1:
Вот подход, при котором вы вычисляете среднее значение каждого столбца пикселей в вашем изображении, а затем вычисляете градиент средних значений:
#!/usr/bin/env python3
import cv2
import numpy as np
import matplotlib.pyplot as plt
filename = 'fg1.png'
# Load image as greyscale and calculate means of each column of pixels
im = cv2.imread(filename, cv2.IMREAD_GRAYSCALE)
means = np.mean(im, axis=0)
# Calculate the gradient of the means
y = np.gradient(means)
# Plot the gradient of the means
xdata = np.arange(0, y.shape[0])
plt.plot(xdata, y, 'bo') # blue circles
plt.title(f'Gradient of Column Means for "{filename}"')
plt.xlabel('x')
plt.ylabel('Gradient of Column Means')
plt.grid(True)
plt.show()
Если вы просто построите средние значения всех столбцов, не используя градиент, вы получите следующее:
Комментарии:
1. Это отличное начало, однако я все еще не уверен, как это можно использовать для оценки объема (количества пикселей в темной области).
2. Не уверен, что понимаю. Если переход осуществляется в пикселе 58 на первом изображении и пикселе 22 на втором изображении, а ширина изображений составляет 118 пикселей, то, несомненно, это составит 58/118 пикселей в первом и 22/118 пикселей во втором?
3. О, да, это правда, извините за плотность.. Есть ли способ программно определить, на какой стороне градиента находится жидкость? (в двух примерах жидкость находится слева от градиента в одном случае и справа от градиента в другом.
4. Если вы посмотрите на второй красный график, вы можете увидеть, что средняя яркость пикселей с левой стороны заметно темнее (ниже), чем справа. На первом красном графике… что ж, остается только гадать, какая сторона темнее!
5. Если вы контролируете лабораторное оборудование и фотографируете, возможно, вы могли бы помочь себе, выбрав более контрастный фон, или покрасив жидкость, или улучшив освещение, или пометив нижний конец пробирки…