Conversation
atani20
left a comment
There was a problem hiding this comment.
Необычная постановка задачи и нетипичный подход к решению. Работа хорошая, сделана с умом.
Хотелось бы больше описания того, что происходит ReadMe или же больше комментариев в коде, чтобы быстрее вникать в происходящее. Так же неплохо бы добавить в ReadMe требования к фотографии. Например, присутствие листа бумаги и луча на изображении.
Еще можно сравнить то, что получилось и то, что должно было получиться и посчитать по этому метрики для оценки качества работы алгоритма.
| cap = cv2.VideoCapture(0) | ||
| if cap.isOpened(): |
There was a problem hiding this comment.
Как я понимаю, предполагается, что система работает в real time и считывает видео с определенной камеры, которая наблюдает за лучом. Но сейчас открывается вебка на ноутбуке, которая начинает анализировать мое изображение) Лучше будет как-то обойти этот момент и в лабе не вызывать чтение с камеры.
There was a problem hiding this comment.
присоединюсь к комментарию Тани - следует добавить хотя бы простой аргумент для запуска программы в желаемом режиме, а то ревьюверам приходится самим код править) но все равно прикольно было увидеть у кого-то поддержку такого режима работы. що сказатi, це фанастишно
There was a problem hiding this comment.
Да, простите. Я что-то не подумал, как будет работать на ноутбуках.
Поправлю)
| if cap.isOpened(): | ||
| cap.set(3, WIDTH) | ||
| cap.set(4, HEIGHT) | ||
| while True: | ||
| suc, img = cap.read() | ||
| getContours(img, cam_mode=True) | ||
| if cv2.waitKey(1) & 0xFF == ord('q'): | ||
| break | ||
| else: | ||
| answer = [["ImageName", "DirectionToCamera", "FrameExist", "FigureExist", "FigureInPlaneSheet", "FigureInFrame", | ||
| "FigureShape"]] | ||
| for i in range(1, 31): | ||
| img_name = str(i) + ".jpg" | ||
| img = cv2.imread("Data_jpg\\" + img_name) | ||
| answer += getContours(img) | ||
|
|
||
| with open("results\\answers.csv", mode="w", encoding='utf-8') as w_file: | ||
| file_writer = csv.writer(w_file, delimiter=";", lineterminator="\r") | ||
| for ans in answer: | ||
| file_writer.writerow(ans) |
There was a problem hiding this comment.
Будет здорово, если ты напишешь этот кусочек кода вот так:
if __name__ == '__main__':
# тут весь код
так же можно вынести код из if и else в две разные функции. В одной обработка видео в real-time, в другой обработка изображений из папки
| for i in range(1, 31): | ||
| img_name = str(i) + ".jpg" | ||
| img = cv2.imread("Data_jpg\\" + img_name) | ||
| answer += getContours(img) |
There was a problem hiding this comment.
Если изображений станет меньше 31, то код упадет. Если больше, то обработаются не все.
Можно сделать универсально:
import os
folder = "Data_jpg"
img_names = os.listdir(folder)
for name in img_names:
img = cv2.imread(os.path.join(folder, name))
answer += getContours(img)
There was a problem hiding this comment.
Да, понимаю.
Скорее я оставил эту конструкцию из соображения "потом докручу, как надо".
|
|
||
| def getContours(img, cam_mode=False): | ||
| imgC = prepareImage(img) | ||
| contours, h = cv2.findContours(imgC, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) |
There was a problem hiding this comment.
Как я понимаю, контуры находятся не всегда хорошо. В качестве эксперимента, можно попробовать такой подход.
Сделать шаблонную фотографию только листа бумаги (только зеркала). Найти особые точки на этом и текущем изображении. Сопоставить эти особые точки и найти матрицу гомографии. Можно воспользоваться примером отсюда https://docs.opencv.org/master/d1/de0/tutorial_py_feature_homography.html
Найти точки, описывающие углы прямоугольника, задающего контур на изображении-шаблоне. С помощью матрицы гомографии найти этот прямоугольник-контур на текущей картинке.
Тут надо смотреть, как долго работает такой подход, можем ли мы его использовать в real-time, работает ли подход на реальной системе, а не только на абстракции.
There was a problem hiding this comment.
В ходе реализации я пробовал использовать особые точки, но из этого не вышло ничего путного.
Может быть я где-то ошибся, но раз уж не только мне это кажется разумной идеей, то попробую ещё раз.
| if contours_to_draw[i] is not None: | ||
| if ellipse is not None: |
There was a problem hiding this comment.
эти два условия можно объединить в одно if contours_to_draw[i] is not None and ellipse is not None
There was a problem hiding this comment.
Хотелось бы в случае отсутствия эллипса всё-таки отрисовать контуры)
Как минимум для проверки корректности работы
| img_blur = cv2.GaussianBlur(img_gray, (3, 3), 1.6) | ||
| img_canny = cv2.Canny(img_blur, 10, 120) |
There was a problem hiding this comment.
В алгоритме Canny используется заблюриваение с помощью Гауссиана. Так что нет смысла блюрить его заранее, а затем еще раз в детекторе. Вместе с тем, можно попробовать предобработку другим фильтром, например фильтром Соблея. Не факт, что результаты получатся лучше
There was a problem hiding this comment.
@atani20 В OpenCV'шной версии Canny применяется только фильтр Собеля, поэтому предобработка Гауссовским сглаживанием кажется уместной
https://stackoverflow.com/questions/63543033/does-cv2-canny-perform-a-gaussian-blur
There was a problem hiding this comment.
Спасибо за замечание. Не знала об этом
| return False | ||
|
|
||
|
|
||
| def getContours(img, cam_mode=False): |
There was a problem hiding this comment.
Эта функция очень большая и не сразу становится понятно, что делается в каждой из ее частей. Предлагаю вынести код в теле некоторых циклов и ифов в отдельные функции с говорящими именами.
via8
left a comment
There was a problem hiding this comment.
т.к. моменты, на которые я тоже обратил внимание, в основном уже прокомментированы другими, оставлю замечания касательно работы в целом:
- следует доработать программу на предмет адекватного поведения в случае невалидных данных (как, например, версия Тани со считыванием содержимого директории с датасетом может помочь здесь)
- хотелось бы увидеть более детальное описание алгоритма в ридми, либо побольше комментариев прямо в коде над неочевидными операциями (а лучше и то и другое конечно). ревьюверу довольно тяжко вникать в происходящее в таком алгоритме, где довольно много констант, хотелось бы видеть описание хотя бы той их части, которая соответствует индексам
*а вообще прикольная работа получилась с этими вашими тамагочи
| cap = cv2.VideoCapture(0) | ||
| if cap.isOpened(): |
There was a problem hiding this comment.
присоединюсь к комментарию Тани - следует добавить хотя бы простой аргумент для запуска программы в желаемом режиме, а то ревьюверам приходится самим код править) но все равно прикольно было увидеть у кого-то поддержку такого режима работы. що сказатi, це фанастишно
| "FigureShape"]] | ||
| for i in range(1, 31): | ||
| img_name = str(i) + ".jpg" | ||
| img = cv2.imread("Data_jpg\\" + img_name) |
There was a problem hiding this comment.
Данный вариант указания пути будет работать только в Windows, для универсальности используй
path_file = os.sep.join([path_dir, filename])
либо модуль pathlib
DariaZubkova
left a comment
There was a problem hiding this comment.
Интересная постановка задачи! Немного было сложно разобраться, как уже писали ранее, комментарии в коде не повредили бы.
Результаты работы можно было бы еще просто печатать в консоль, чтобы не лезть в файл(results\answers.csv) для проверки. Т.к. рассматриваются последовательно все данные с датасета, то можно последовательно также выводить текстовые и визуальные результаты, чтобы сразу отслеживать, как алгоритм сработал на этих данных.
|
Замечания все по делу и всё поправлю в следующей версии. Также отвечу Дарье по поводу вывода результатов: |
На данный момент не всегда корректно или вообще не получается определить контуры листа, вследствие чего из-за использования иерархии контуров есть проблемы в определении контура эллипса