Обновить

Компьютерное зрение для контроля качества на линии: гречка, брак и бесплатная платформа для разметки и обучения модели

Уровень сложностиСредний
Время на прочтение5 мин
Охват и читатели10K
Всего голосов 5: ↑5 и ↓0+7
Комментарии10

Комментарии 10

Буду рад обратной связи.

Ну, давайте попробуем. Вы большой молодец, что обучили модель и она распознает то что надо, но я думаю, что само CV в такой задаче немного избыточно.

В таких задачах прежде чем идти в CV, стоит посмотреть, что дает самый простой baseline, ведь для него созданы все условия: синяя подсветка (контрастный фон), зерно на нем хорошо отделяется и всего 3 класса различающиеся яркостью зерна.

Если baseline дает приемлемую точность, нейросеть не нужна. Если нет, он покажет, где именно проблема, и задаст планку, которую CV должен превзойти.

Давайте соберем baseline (буду делать на коленке т.к. поздно уже). Что мы имеем?

Фон подсвечен синим (B-канал около 252), значит там где есть зерно синий канал упадет ниже уровня фона. Яркие голубые полосы подсветки по краям кадра при этом зерном не считаются, потому что их B-канал остается высоким.

Понятно, что синий канал у нас самый шумный, поэтому в признаки его не берем. Работать будет в красном канале, а для дополнительного очищения от шума будем вычитать из него, например, 30% зеленого канала, т.е. возьмем признак яркости: R - 0.3*G.

Два порога T1, T2 будут делить пиксели зерна на три класса. Считать будем доли пикселей, а не зерен, что позволит нам не разделять слипшиеся зерна, ведь нам нужны общие доли.

Помимо этого обрежем лишнее по краям кадра и обрежем 1 пиксель с краев зерен тк это самые зашумленные места.

Для подбора T1, T2 по трем кадрам из статьи прогоним обычным полным перебором (grid search) по двум порогам, либо методом тыка возьмем T1 как ~30% от диапазона (255) и проверим окрестности вокруг него. Затем имея T1 подберем T2 любым приглянувшимся методом. У меня получилось T1 = 87, T2 = 145. Теперь пишем небольшой скрипт, который реализует описанное выше:

#!/usr/bin/env python3

import sys
import numpy as np
from PIL import Image

T1, T2 = 87, 145  # признак < T1 плохое зерно, T1..T2 серое, >= T2 хорошее
G_WEIGHT = 0.3    # признак = R - G_WEIGHT * G
BLUE_DROP = 70    # зерно перекрывает фон: синий канал падает ниже (фон - BLUE_DROP)
MARGIN = 10       # отрезаем рамку по краям кадра
ERODE = 1         # срезаем пиксели с краев зерна

def grain_brightness(path):
    img = np.asarray(Image.open(path).convert("RGB"), dtype=np.float32)
    img = img[MARGIN:-MARGIN, MARGIN:-MARGIN]
    mask = img[:, :, 2] < np.median(img[:, :, 2]) - BLUE_DROP
    for _ in range(ERODE):
        m = mask.copy()
        m[1:] &= mask[:-1]
        m[:-1] &= mask[1:]
        m[:, 1:] &= mask[:, :-1]
        m[:, :-1] &= mask[:, 1:]
        mask = m
    return (img[:, :, 0] - G_WEIGHT * img[:, :, 1])[mask]

for path in sys.argv[1:] or sys.exit(__doc__):
    g = grain_brightness(path)
    good = (g >= T2).mean() * 100
    black = (g < T1).mean() * 100
    print(f"{path}: хорошие {good:.1f}%   серые {100 - good - black:.1f}%   плохие {black:.1f}%")

Скрипт на 30 строк, размером 1.3 Кб за ~25мс на CPU показал следующие результаты:

Хорошая партия: 83.3%/16.3%/0.4% насчитали руками: 86.3%/13.7%/0.0%

Плохая партия: 2.4%/24.1%/73.5% насчитали руками: 3.7%/22.9%/73.4%

Серая партия: 24.1%/63.4%/12.5% насчитали руками: 20.8%/70.4%/8.7%

Средняя абсолютная разница между baseline скриптом и тем что насчитали руками всего 2.5 п.п. При этом пачку из 24 кадров считает за 0.6 сек. Сам скрипт запускается элементарно: grid.py image.jpg.

Думаю, что пороги в скрипте можно подобрать еще качественнее, но я не тратил на это время.

Отличный комментарий. Даже лучше чем статья, по моему мнению.

Можно даже несколько улучшить производительность, использовав cv2 вместо PIL. Еще, зная центры кластеров в rgb, можно более точно найти линейное преобразование вместо R-0.3G. Или просто использовать PCA для зерен, отфильтровав маской фон.

И для эрозии есть PIL.ImageFilter.MinFilter(size=3)

Чувак в инфоцыгане метит а вы все обосрали, что за люди...

Спасибо за комментарий, все верно, задачу можно решить простым безлайном. Но вы верно отметили, что возможно потом надо будет править пороги и в целом поддерживать.

Цель платформы, что задачу разметки и построения модели сможет сделать не разработчик или датасайентист, а технолог на производстве самостоятельно. Грубо говоря - загрузил фото, разметил, нажал на кнопку, получил модель, запустил из браузера.

Аналог если интересно посмотрите - платформа roboflow

Я прекрасно понимаю суть вашей платформы как аналога roboflow, мой комментарий был не о критике вашей платформы, а о том что выбранный пример не совсем удачный, но это никак не отменяет полезности того что вы делаете.

По поводу CV решения этой задачи, я думаю вы сможете улучшить результат если замените Yolo на RF-DETR, но тут скорее вопрос, а надо ли вообще более точно в этой задачи или текущего уровня достаточно.

Отличное решение!

Не всегда нужно лезть за нейронками.

Еще проще поставить три светофильтра и три АЦП

Насколько я помню, yolo26 имеет бесплатную лицензию только для некоммерческого использования.

Отечественный roboflow уже придуман, если что - luna line. Они и сразу деплой + видео поддерживают, помимо прочих штук типа разметки и обучения.

Да, знаком с таким продуктом. Но сейчас он недоступен всем. На сайте требуется запросить отдельно демо, нет прозрачной цены.
Picva позиционируется как доступная всем платформа сразу

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации