Это удалось, но, хотя площадь квадратов сетки бумаги определяется точно, когда я изображаю объекты известных размеров/площади (например, пенни США), я получаю значения, которые на 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]
И, наконец, код, который просто обходит поток камеры и вызывает две вышеупомянутые функции и выполняет среднее число пикселей на мм. , чтобы сгладить выходные значения площади (во избежание дрожания значений в реальном времени):Использование известного_grid_width = 5 # мм для бумаги с сеткой 5 мм позволяет получить точные измерения площади квадратов сетки (в среднем 24,94398288816283 мм^2), но завышает ожидаемые 2,853 см^2. площадь копейки примерно на 3%. Уменьшениеknown_grid_width, чтобы получить правильную площадь пенни, приводит к тому, что квадраты сетки имеют площадь около 23,8 мм^2, что является серьезной заниженной оценкой, а измерения бумажной сетки с помощью штангенциркуля выглядят соответствующими сеткам с шагом 5 мм. Я не думаю, что это проблема с порогами для MeasureArea(), и использование среднего и медианы для получения репрезентативного значения пикселей на мм в каждой итерации цикла также кажется довольно нечувствительным. Если проблема связана с морфологическими преобразованиями при обнаружении сетки, выбор ядра был ОЧЕНЬ чувствителен к тому, сколько квадратов сетки было обнаружено. Если не считать пластыря для использования площади пенни вместо известной_сетки_ширины (и, таким образом, сводящей на нет всю суть статьи), как я могу согласовать результаты площади сетки с пенни?Код: Выделить всё
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)
Любая помощь, которую вы можете оказать новичку, будет очень признательна, особенно для оценки неопределенности в области подгонок! Спасибо!!
Подробнее здесь: https://stackoverflow.com/questions/789 ... hon-opencv