Я пытаюсь использовать OpenCV в сочетании с дешевым USB-микроскопом для измерения в реальном времени площади образцов, которые мы готовим с помощью прокатки фольги, и в настоящее время измеряем с помощью штангенциркуля. Из-за неровных краев некоторых из этих образцов я хотел исследовать их с помощью анализа изображений, а не делать предположения о том, что они круглые, прямоугольные и т. д. Кроме того, я хотел использовать бумагу с миллиметровой сеткой (на лайтбоксе, чтобы ищите отверстия) позади объектов, чтобы иметь возможность на лету выполнить калибровку шкалы пикселей мм. Это также значительно увеличивает контраст, что значительно упрощает установку пороговых значений и позволяет избежать проблем с отражениями и т. д.
Это удалось, но, хотя площадь квадратов сетки бумаги определяется точно, когда я изображаю объекты известных размеров/площади (например, пенни США), я получаю значения, которые на 2–4 % выше ожидаемых. Это можно легко компенсировать, изменяя опорное значение до тех пор, пока калибровочный объект не будет измерен правильно, но я беспокоюсь, что это всего лишь повязка за то, что я делаю неправильно, возможно, из-за морфологических преобразований / размытия по Гауссу, слишком сильно искажающих края? Пенни предназначался для проверки калибровки, но он не может находиться в рамке при обычном использовании, поэтому я в первую очередь хотел использовать сетку для калибровки. Камера установлена вертикально над головой и по центру, и попытка выполнить калибровку камеры, похоже, добавила больше сферических аберраций, чем улучшила ситуацию.
Это приводит к двум основным вопросам:
Что я здесь делаю не так?
Можно ли оценить неопределенность в областях, рассчитанных с помощью cv2.contourArea(контур)? Штангенциркули обычно позволяют нам достичь погрешности 0) and (cX > 0):
approxCurve = cv2.approxPolyDP(contour, 50, True)
# if the area is rectangle
if len(approxCurve)==4:
# get lengths of sides
(x,y,w,h) = cv2.boundingRect(contour)
delta = 0.2;
area = area = cv2.contourArea(contour)
cv2.drawContours(img, [contour], -1, (255,0,0), 3) # plot all found contours in blue
cv2.drawContours(outerBox, [contour], -1, (255,0,0), 3) # plot all found contours in blue
# Check if contour looks like a square within tolerance delta
if (abs((w/h)-1) < delta) and (area > grid_area_threshold) and (abs((w*h/area)-1) < delta) :
if area > 0:
area_list.append(area)
contour_list.append(contour)
for (area,contour) in zip(area_list,contour_list):
cv2.drawContours(img, [contour], -1, (0,255,0), 3) # plot square-like contours in green
# take the median or mean for grid scaling?
# Remove edge cases to reject noise
area_list.sort()
if len(area_list) < 2:
median = np.mean(area_list)
elif len(area_list) < 3:
median = np.mean(area_list[1:-1])
else:
median = np.mean(area_list[2:-2])
pixels_per_mm = 0
# take the side of a square which is the number of pixels per millimeter
if np.size(median) == 1:
pixels_per_mm = np.sqrt(median) / known_grid_width
# Annotate area onto each detected grid square for comparison
for contour in contour_list:
area = cv2.contourArea(contour)
if area > grid_area_threshold:
x, y, w, h = cv2.boundingRect(contour)
cv2.putText(img, '{0:.2f}'.format(area/(pixels_per_mm*pixels_per_mm)), (x, y+20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
return pixels_per_mm
[/code]
с выводом:
[img]https:// i.sstatic.net/C8BZKork.png[/img]
Код, который выполняет калибровку пикселей на мм и измеряет площадь объектов, превышающую установленный порог:
def measureArea(img, pixels_per_mm):
area_threshold = 100 # Reject small features
# Convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#
# Threshold detection
#
blur = cv2.GaussianBlur(gray, (5, 5), 0)
ret,th1 = cv2.threshold(gray,70,255,cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(th1, 1, 2)
for contour in contours:
area = cv2.contourArea(contour)
# Annotate object area onto image
if area > area_threshold:
x, y, w, h = cv2.boundingRect(contour)
cv2.putText(img, '{0:.2f} cm2'.format(area/(pixels_per_mm*pixels_per_mm*100)), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
cv2.drawContours(img, [contour], -1, (0,255,0), 1) # plot square-like contours in green
# print(area)
с выводом:
[img]https://i .sstatic.net/iVbE8Uuj.png[/img]
И, наконец, код, который просто обходит поток камеры и вызывает две вышеупомянутые функции и выполняет среднее число пикселей на мм. , чтобы сгладить выходные значения площади (во избежание дрожания значений в реальном времени):
def acquireFromCamera(show_calibration=False):
# Open the default camera (default was 0)
cam = cv2.VideoCapture(0)
pixel_scale_list = []
# Loop over camera input stream frames
while True:
# Swapped from camera input to imread for posting to stackoverflow
#
# ret, frame = cam.read()
frame = cv2.imread('original_image.png')
frame_copy = frame.copy()
pixels_per_mm = measureGridSize(frame)
# Get running average of pixel scale to smooth output areas
if not np.isnan(pixels_per_mm):
pixel_scale_list.append(pixels_per_mm)
avg_pixel_scale = np.convolve(pixel_scale_list, np.ones(len(pixel_scale_list))/len(pixel_scale_list), mode='valid')
print(avg_pixel_scale)
measureArea(frame_copy, avg_pixel_scale[0])
if show_calibration:
cv2.imshow('Area Detection', frame_copy)
# Display the captured frame
cv2.imshow('Camera (Press q to exit)', frame)
if cv2.waitKey(1) == ord('q'):
break
# Release the capture and writer objects
cam.release()
cv2.destroyAllWindows()
acquireFromCamera(True)
Использование известного_grid_width = 5 # мм для бумаги с сеткой 5 мм позволяет получить точные измерения площади квадратов сетки (в среднем 24,94398288816283 мм^2), но завышает ожидаемые 2,853 см^2. площадь копейки примерно на 3%. Уменьшениеknown_grid_width, чтобы получить правильную площадь пенни, приводит к тому, что квадраты сетки имеют площадь около 23,8 мм^2, что является серьезной заниженной оценкой, а измерения бумажной сетки с помощью штангенциркуля выглядят соответствующими сеткам с шагом 5 мм. Я не думаю, что это проблема с порогами для MeasureArea(), и использование среднего и медианы для получения репрезентативного значения пикселей на мм в каждой итерации цикла также кажется довольно нечувствительным. Если проблема связана с морфологическими преобразованиями при обнаружении сетки, выбор ядра был ОЧЕНЬ чувствителен к тому, сколько квадратов сетки было обнаружено. Если не считать пластыря для использования площади пенни вместо известной_сетки_ширины (и, таким образом, сводящей на нет всю суть статьи), как я могу согласовать результаты площади сетки с пенни?
Любая помощь, которую вы можете оказать новичку, будет очень признательна, особенно для оценки неопределенности в области подгонок! Спасибо!!
Я пытаюсь использовать OpenCV в сочетании с дешевым USB-микроскопом для измерения в реальном времени площади образцов, которые мы готовим с помощью прокатки фольги, и в настоящее время измеряем с помощью штангенциркуля. Из-за неровных краев некоторых из этих образцов я хотел исследовать их с помощью анализа изображений, а не делать предположения о том, что они круглые, прямоугольные и т. д. Кроме того, я хотел использовать бумагу с миллиметровой сеткой (на лайтбоксе, чтобы ищите отверстия) позади объектов, чтобы иметь возможность на лету выполнить калибровку шкалы пикселей мм. Это также значительно увеличивает контраст, что значительно упрощает установку пороговых значений и позволяет избежать проблем с отражениями и т. д. Это удалось, но, хотя площадь квадратов сетки бумаги определяется точно, когда я изображаю объекты известных размеров/площади (например, пенни США), я получаю значения, которые на 2–4 % выше ожидаемых. Это можно легко компенсировать, изменяя опорное значение до тех пор, пока калибровочный объект не будет измерен правильно, но я беспокоюсь, что это всего лишь повязка за то, что я делаю неправильно, возможно, из-за морфологических преобразований / размытия по Гауссу, слишком сильно искажающих края? Пенни предназначался для проверки калибровки, но он не может находиться в рамке при обычном использовании, поэтому я в первую очередь хотел использовать сетку для калибровки. Камера установлена вертикально над головой и по центру, и попытка выполнить калибровку камеры, похоже, добавила больше сферических аберраций, чем улучшила ситуацию. Это приводит к двум основным вопросам:[list] [*]Что я здесь делаю не так? [*]Можно ли оценить неопределенность в областях, рассчитанных с помощью cv2.contourArea(контур)? Штангенциркули обычно позволяют нам достичь погрешности 0) and (cX > 0): approxCurve = cv2.approxPolyDP(contour, 50, True) # if the area is rectangle if len(approxCurve)==4: # get lengths of sides (x,y,w,h) = cv2.boundingRect(contour) delta = 0.2; area = area = cv2.contourArea(contour)
cv2.drawContours(img, [contour], -1, (255,0,0), 3) # plot all found contours in blue cv2.drawContours(outerBox, [contour], -1, (255,0,0), 3) # plot all found contours in blue
# Check if contour looks like a square within tolerance delta if (abs((w/h)-1) < delta) and (area > grid_area_threshold) and (abs((w*h/area)-1) < delta) : if area > 0: area_list.append(area) contour_list.append(contour)
for (area,contour) in zip(area_list,contour_list): cv2.drawContours(img, [contour], -1, (0,255,0), 3) # plot square-like contours in green
# take the median or mean for grid scaling? # Remove edge cases to reject noise area_list.sort() if len(area_list) < 2: median = np.mean(area_list) elif len(area_list) < 3: median = np.mean(area_list[1:-1]) else: median = np.mean(area_list[2:-2]) pixels_per_mm = 0
# take the side of a square which is the number of pixels per millimeter if np.size(median) == 1: pixels_per_mm = np.sqrt(median) / known_grid_width
# Annotate area onto each detected grid square for comparison for contour in contour_list: area = cv2.contourArea(contour) if area > grid_area_threshold:
x, y, w, h = cv2.boundingRect(contour) cv2.putText(img, '{0:.2f}'.format(area/(pixels_per_mm*pixels_per_mm)), (x, y+20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
return pixels_per_mm [/code] с выводом: [img]https:// i.sstatic.net/C8BZKork.png[/img]
Код, который выполняет калибровку пикселей на мм и измеряет площадь объектов, превышающую установленный порог: [code]def measureArea(img, pixels_per_mm): area_threshold = 100 # Reject small features
# Convert to grayscale gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
contours,hierarchy = cv2.findContours(th1, 1, 2) for contour in contours: area = cv2.contourArea(contour) # Annotate object area onto image if area > area_threshold:
x, y, w, h = cv2.boundingRect(contour) cv2.putText(img, '{0:.2f} cm2'.format(area/(pixels_per_mm*pixels_per_mm*100)), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
cv2.drawContours(img, [contour], -1, (0,255,0), 1) # plot square-like contours in green # print(area) [/code] с выводом: [img]https://i .sstatic.net/iVbE8Uuj.png[/img]
И, наконец, код, который просто обходит поток камеры и вызывает две вышеупомянутые функции и выполняет среднее число пикселей на мм. , чтобы сгладить выходные значения площади (во избежание дрожания значений в реальном времени): [code]def acquireFromCamera(show_calibration=False): # Open the default camera (default was 0) cam = cv2.VideoCapture(0)
pixel_scale_list = []
# Loop over camera input stream frames while True: # Swapped from camera input to imread for posting to stackoverflow # # ret, frame = cam.read() frame = cv2.imread('original_image.png') frame_copy = frame.copy()
pixels_per_mm = measureGridSize(frame)
# Get running average of pixel scale to smooth output areas if not np.isnan(pixels_per_mm): pixel_scale_list.append(pixels_per_mm) avg_pixel_scale = np.convolve(pixel_scale_list, np.ones(len(pixel_scale_list))/len(pixel_scale_list), mode='valid')
print(avg_pixel_scale) measureArea(frame_copy, avg_pixel_scale[0]) if show_calibration: cv2.imshow('Area Detection', frame_copy)
# Display the captured frame cv2.imshow('Camera (Press q to exit)', frame)
if cv2.waitKey(1) == ord('q'): break
# Release the capture and writer objects cam.release() cv2.destroyAllWindows()
acquireFromCamera(True) [/code] Использование известного_grid_width = 5 # мм для бумаги с сеткой 5 мм позволяет получить точные измерения площади квадратов сетки (в среднем 24,94398288816283 мм^2), но завышает ожидаемые 2,853 см^2. площадь копейки примерно на 3%. Уменьшениеknown_grid_width, чтобы получить правильную площадь пенни, приводит к тому, что квадраты сетки имеют площадь около 23,8 мм^2, что является серьезной заниженной оценкой, а измерения бумажной сетки с помощью штангенциркуля выглядят соответствующими сеткам с шагом 5 мм. Я не думаю, что это проблема с порогами для MeasureArea(), и использование среднего и медианы для получения репрезентативного значения пикселей на мм в каждой итерации цикла также кажется довольно нечувствительным. Если проблема связана с морфологическими преобразованиями при обнаружении сетки, выбор ядра был ОЧЕНЬ чувствителен к тому, сколько квадратов сетки было обнаружено. Если не считать пластыря для использования площади пенни вместо известной_сетки_ширины (и, таким образом, сводящей на нет всю суть статьи), как я могу согласовать результаты площади сетки с пенни? Любая помощь, которую вы можете оказать новичку, будет очень признательна, особенно для оценки неопределенности в области подгонок! Спасибо!!
Я пытаюсь использовать OpenCV в сочетании с дешевым USB-микроскопом для измерения в реальном времени площади образцов, которые мы готовим с помощью прокатки фольги, и в настоящее время измеряем с помощью штангенциркуля. Из-за неровных краев...
В настоящее время я работаю над кодом для уравнения, определяющего значения «нуль» и «пустота», используя эти мотивы в качестве базового материала. Код предназначен для количественной оценки лей-линий изотопов, свойств фотонных реагентов и...
Я использую word2vec (gensim 4.3.3) для встраивания слов, результаты векторов слов из сохраненного файла «wv.vectors.npy» показывают, что все векторы слов малы, минимум всего массива равен -0,003 и max равен 0,003, то есть каждое слово включает в...
Справочная информация. Я студент-исследователь, разрабатывающий терапевтическое приложение в Android Studio Java с использованием двух Bluetooth IMU, которые выдают кватернионы. Текущая терапия, которую я разрабатываю, включает в себя датчик на...