Вопрос или проблема
У меня возникли проблемы с проектом калибровки камеры ROS уже некоторое время.
Я написал и скомпилировал C++ программу в ROS Noetic для распознавания шаблона шахматной доски для калибровки веб-камеры.
Программа написана так, что все сбор данных и обработка изображения происходят внутри исполняемого файла C++ с использованием VideoCapture cap(0)
и imshow()
.
Программа не требует структуры узлов издателей и подписчиков для ввода, обработки и вывода кадров и матриц с веб-камеры.
Программа на C++ компилируется без ошибок. Однако, при запуске с помощью rosrun она выполняется бесконечно и, похоже, не может найти шахматные доски, не отображает никакие окна вывода и не выводит никаких завершенных матриц (или чего-либо, кроме пустой командной строки, дающей понять, что она работает). Единственные способы выйти из программы после ее запуска – либо закрыть окно командной строки, либо ввести команду kill
.
Версии программного обеспечения:
Ubuntu 64-битная версия 20.04.4 LTS
Библиотека OpenCV2 версии 4.2.0
ROS noetic
CMake версия 3.16.3
GNU Make версия 4.2.1
Код на C++:
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/highgui.hpp>
#include <vector>
#include <iostream>
using namespace cv;
using namespace std;
Mat frame,cropped_left_image,cropped_right_image,fullframe;
vector<Point2f> cornersRight; // это будет заполнено обнаруженными углами
vector<Point2f> cornersLeft; // эти векторы хранят левые и правые угловые точки
Point2f offset(0,432); // половина кадра 1280X720. Это значение задает смещение для корректировки координат
const char* window_name4 = "Полный кадр";
bool detectAndDrawLeftChessboardCorners()
{
Size patternsize(8,6); // количество внутренних углов
Mat gray; // Матрица для хранения изображения в градациях серого
cvtColor(cropped_left_image,gray,COLOR_BGR2GRAY);// исходное изображение
// это будет заполнено обнаруженными углами
// CALIB_CB_FAST_CHECK экономит время на изображениях, которые не содержат углы шахматной доски
bool patternfound = findChessboardCorners(gray, patternsize, cornersLeft,
CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE
+ CALIB_CB_FAST_CHECK); // найти углы шахматной доски и отправить их в левый угол
if(patternfound)
cornerSubPix(gray, cornersLeft, Size(11, 11), Size(-1, -1),
TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
drawChessboardCorners(cropped_left_image, patternsize, Mat(cornersLeft), patternfound);
return true;
}
bool detectAndDrawRightChessboardCorners()
{
Size patternsize(8,6); // количество внутренних углов
Mat gray;
cvtColor(cropped_right_image,gray,COLOR_BGR2GRAY);// исходное изображение
// CALIB_CB_FAST_CHECK экономит время на изображениях, которые не содержат углы шахматной доски
bool patternfound = findChessboardCorners(gray, patternsize, cornersRight,
CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE
+ CALIB_CB_FAST_CHECK); // найти углы шахматной доски и отправить их в правый угол
if(patternfound)
cornerSubPix(gray, cornersRight, Size(11, 11), Size(-1, -1),
TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
drawChessboardCorners(cropped_right_image, patternsize, Mat(cornersRight), patternfound);
return true;
}
void compensateRightOffset(){
for(int i =0; i < cornersRight.size(); i++){
cornersRight[i]+=offset;
}
}
int main(int argc, char* argv[])
{
VideoCapture cap(0); // Открытие видео камеры по умолчанию (USB веб-камера)
if (cap.isOpened() == false) // если не получилось, завершить программу
{
cout << "Не могу открыть видеокамеру" << endl;
cin.get(); // ожидание нажатия любой клавиши
return -1;
}
double dWidth = cap.get(CAP_PROP_FRAME_WIDTH);
double dHeight = cap.get(CAP_PROP_FRAME_HEIGHT);
cout << "Разрешение видео: " << dWidth << " x " << dHeight << endl;
while (true)
{
bool bSuccess = cap.read(frame); // считать новый кадр с видео
if (bSuccess == false)
{
cout << "Видеокамера отключена" << endl;
cin.get(); // Ожидание нажатия любой клавиши
break;
}
cropped_left_image = frame(Range(0,(int)(dHeight)),Range(0,(0.6*dWidth)));
detectAndDrawLeftChessboardCorners();
cropped_right_image = frame(Range(0,dHeight),Range((0.4*dWidth),dWidth));
detectAndDrawRightChessboardCorners();
Mat cropped_left_full_display = cropped_left_image(Range(0,dHeight),Range(0,0.5*dWidth));
Mat cropped_right_full_display = cropped_right_image(Range(0,dHeight),Range(128,0.5*dWidth));
hconcat(cropped_left_full_display,cropped_right_full_display,fullframe);
compensateRightOffset();
imshow(window_name4, fullframe);
if (waitKey(10) == 27)
{
cout << "Клавиша Esc нажата пользователем. Остановка видео" << endl;
break;
}
}
return 0;
}
Я не понимаю, как такая ошибка может возникать в этой ситуации, и буду признателен за любую помощь с данной проблемой. Я не считаю, что это проблема с освещением, так как я тестировал эту программу в различных условиях окружающего освещения и получал тот же результат каждый раз.
Ответ или решение
Проблемы в коде калибровки камеры в ROS Noetic
Вы столкнулись с проблемами при калибровке камеры в ROS Noetic, и вашему коду C++ не удается обнаружить шахматную доску или выдавать ожидаемый результат. Давайте разберем этот код и выясним возможные причины его неправильного поведения.
1. Введение
Вы используете C++ программу для обработки видео с веб-камеры, используя библиотеку OpenCV для обнаружения шахматной доски и калибровки камеры. Вы отметили, что программа компилируется без ошибок, но при исполнении не показывает ожидаемых результатов — непрерывно работает, не показывает ни окон, ни матриц, и останавливается только при принудительном завершении.
2. Анализ кода
-
Захват видео и открытие окна:
VideoCapture cap(0); if (cap.isOpened() == false) { cout << "Cannot open the video camera" << endl; cin.get(); return -1; }
- Убедитесь, что ваша камера действительно подключена и устройство /dev/video0 доступно. В случае ошибки, вы должны увидеть выведенное сообщение "Cannot open the video camera".
-
Проблемы с отображением окна:
- Убедитесь, что функция
imshow()
вызывается корректно и окно имеет уникальное название. Название окна должно совпадать с именем вimshow()
, например:const char* window_name4 = "Complete Frame"; imshow(window_name4, fullframe);
- Попробуйте добавить
waitKey(0)
в случае, если окно закрывается слишком быстро.
- Убедитесь, что функция
-
Обработка шахматной доски:
- Убедитесь, что шахматная доска видна на изображениях и адаптируйте параметры функции
findChessboardCorners()
, например, размер паттерна и пороговые параметры, для улучшения точности обнаружения. -
Попробуйте отключить
CALIB_CB_FAST_CHECK
, чтобы повлиять на поведение обнаружения:bool patternfound = findChessboardCorners(gray, patternsize, cornersLeft, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE);
- Убедитесь, что шахматная доска видна на изображениях и адаптируйте параметры функции
-
Отладка и сообщения:
- Рекомендуется внедрить сообщения для отладки после каждой основной операции для более точного определения местоположения проблемы. Это поможет уточнить, выполняется ли каждый шаг или где процесс замирает.
3. Рекомендации
-
Проверка оборудования: Убедитесь, что веб-камера исправно работает с другими приложениями и доступна через OpenCV.
-
Параметры OpenCV: Попробуйте протестировать другие параметры для
findChessboardCorners()
иcornerSubPix()
. Иногда параметры одного окружения не являются оптимальными для другого. -
Тестирование отдельных компонентов: Разбейте процесс на меньшие части и протестируйте независимо, чтобы выявить, какой этап не функционирует должным образом.
4. Заключение
Ваш код нуждается в отладке и улучшении для увеличения устойчивости и производительности. Основное внимание следует уделить корректной обработке видео, проверке условий использования OpenCV и адаптации параметров обнаружения. Регулярное использование выводов для отладки поможет значительно упростить процесс обнаружения проблем.
Если эти шаги не привели к решению вашей проблемы, обратитесь за поддержкой к внешним разработчикам или изучите дополнительную документацию по OpenCV и ROS Noetic для более глубокого понимания.