Количественная неопределенность в измерениях площади с помощью Python opencvPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Количественная неопределенность в измерениях площади с помощью Python opencv

Сообщение Anonymous »

Я пытаюсь использовать 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(), и использование среднего и медианы для получения репрезентативного значения пикселей на мм в каждой итерации цикла также кажется довольно нечувствительным. Если проблема связана с морфологическими преобразованиями при обнаружении сетки, выбор ядра был ОЧЕНЬ чувствителен к тому, сколько квадратов сетки было обнаружено. Если не считать пластыря для использования площади пенни вместо известной_сетки_ширины (и, таким образом, сводящей на нет всю суть статьи), как я могу согласовать результаты площади сетки с пенни?
    Любая помощь, которую вы можете оказать новичку, будет очень признательна, особенно для оценки неопределенности в области подгонок! Спасибо!!

    Подробнее здесь: https://stackoverflow.com/questions/789 ... hon-opencv
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»