Object Measurement System from Image and Video

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1 servicesAll 1566 services
Object Measurement System from Image and Video
Medium
~5 business days
FAQ
AI Development Areas
AI Solution Development Stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823
  • image_logo-aider_0.jpg
    AIDER company logo development
    762
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    848

System Development измерения объектов по изображению/видео

Измерение размеров через компьютерное зрение заменяет штангенциркули, рулетки и ручные измерения. Система работает в двух режимах: с калиброванной камерой (известный масштаб, точность до десятых миллиметра) и с референсным объектом в кадре (для полевых измерений).

Методы масштабирования

Метод 1: Калиброванная камера

Один раз фотографируем объект известного размера (калибровочная пластина) с рабочего расстояния, вычисляем коэффициент pixels_per_mm:

import cv2
import numpy as np

class CalibratedMeasurement:
    def __init__(self, pixels_per_mm: float,
                 camera_matrix: np.ndarray = None,
                 dist_coefficients: np.ndarray = None):
        self.ppm = pixels_per_mm
        self.camera_matrix = camera_matrix
        self.dist_coefficients = dist_coefficients

    def calibrate_from_reference(self, image: np.ndarray,
                                   known_width_mm: float) -> float:
        """Калибровка по объекту известной ширины"""
        # Предполагаем что объект уже выровнен и занимает ~80% ширины
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        _, binary = cv2.threshold(gray, 0, 255,
                                   cv2.THRESH_BINARY + cv2.THRESH_OTSU)

        contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL,
                                        cv2.CHAIN_APPROX_SIMPLE)
        main = max(contours, key=cv2.contourArea)
        x, y, w, h = cv2.boundingRect(main)

        self.ppm = w / known_width_mm
        return self.ppm

    def measure_contour(self, image: np.ndarray) -> dict:
        """Измерение основных параметров объекта"""
        if self.camera_matrix is not None:
            # Исправление дисторсии линзы
            image = cv2.undistort(image, self.camera_matrix,
                                   self.dist_coefficients)

        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        _, binary = cv2.threshold(gray, 0, 255,
                                   cv2.THRESH_BINARY + cv2.THRESH_OTSU)

        contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL,
                                        cv2.CHAIN_APPROX_SIMPLE)
        if not contours:
            return {'measured': False}

        c = max(contours, key=cv2.contourArea)

        # Bounding rectangle
        x, y, w, h = cv2.boundingRect(c)

        # Минимальный описывающий прямоугольник (с вращением)
        rect = cv2.minAreaRect(c)
        (cx, cy), (rw, rh), angle = rect
        min_side = min(rw, rh)
        max_side = max(rw, rh)

        # Периметр через arc length
        perimeter_px = cv2.arcLength(c, True)

        # Площадь
        area_px = cv2.contourArea(c)

        return {
            'width_mm': round(w / self.ppm, 3),
            'height_mm': round(h / self.ppm, 3),
            'length_mm': round(max_side / self.ppm, 3),
            'width_min_mm': round(min_side / self.ppm, 3),
            'angle_deg': round(angle, 2),
            'perimeter_mm': round(perimeter_px / self.ppm, 3),
            'area_mm2': round(area_px / self.ppm**2, 3),
            'center': (round(cx / self.ppm, 2), round(cy / self.ppm, 2))
        }

Метод 2: Референсный объект в кадре (ArUco маркеры)

import cv2.aruco as aruco

def measure_with_aruco(image: np.ndarray,
                        marker_size_mm: float = 50.0) -> dict:
    """Измерение с ArUco маркером как референсом"""
    aruco_dict = aruco.getPredefinedDictionary(aruco.DICT_4X4_250)
    detector = aruco.ArucoDetector(aruco_dict)

    corners, ids, _ = detector.detectMarkers(image)

    if ids is None:
        return {'error': 'no_aruco_marker_found'}

    # Вычисляем pixels_per_mm из маркера
    marker_corners = corners[0][0]
    marker_width_px = np.linalg.norm(marker_corners[0] - marker_corners[1])
    ppm = marker_width_px / marker_size_mm

    # Дальше стандартное измерение
    measurer = CalibratedMeasurement(pixels_per_mm=ppm)
    return measurer.measure_contour(image)

Измерение в 3D через стереопару

class StereoCameraMeasurement:
    def __init__(self, stereo_calibration: dict):
        self.Q = stereo_calibration['Q']          # disparity-to-depth матрица
        self.baseline_mm = stereo_calibration['baseline_mm']
        self.focal_length_px = stereo_calibration['focal_length_px']

    def measure_3d(self, left_img: np.ndarray,
                    right_img: np.ndarray) -> dict:
        # Stereo matching
        stereo = cv2.StereoSGBM_create(
            minDisparity=0,
            numDisparities=96,
            blockSize=11,
            P1=8 * 3 * 11**2,
            P2=32 * 3 * 11**2,
            disp12MaxDiff=1,
            uniquenessRatio=10,
            speckleWindowSize=100,
            speckleRange=32
        )

        disparity = stereo.compute(
            cv2.cvtColor(left_img, cv2.COLOR_BGR2GRAY),
            cv2.cvtColor(right_img, cv2.COLOR_BGR2GRAY)
        ).astype(np.float32) / 16.0

        # Конвертация диспаретности в 3D облако точек
        points_3d = cv2.reprojectImageTo3D(disparity, self.Q)

        return self._extract_dimensions_3d(points_3d)

Точность и применения

Метод Диапазон Точность Применение
2D с калибровкой (фиксированное расстояние) 1–500 мм ±0.1–0.5 мм Конвейер, QC
ArUco референс 10–2000 мм ±1–5 мм Полевые измерения
Стерео (10 cm базис) 50–1000 мм ±0.5–2 мм 3D измерение
LiDAR + RGB 100–5000 мм ±1–3 мм Крупные объекты
Задача Срок
2D измерение на конвейере 2–4 недели
Система с ArUco для полевого применения 3–5 недель
3D стерео система 6–10 недель