/
Dev_Devil
/
ComputerVision
Обзор
Документация
Войти
/
Dev_Devil
/
ComputerVision
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
Klette_Computer_Vision_2019/part9/CodC++.cpp
243 строки
8 KB
Geek_bro
9 глава
02 дек 2025, 00:04
02 дек 2025, 00:04
1accd7f
Код
Авторство
О чём код?
// ============================================================ // ============== ЕДИНЫЙ КОД (ГЛАВА 9 — ПРИЗНАКИ) ============= // ============== ОБНАРУЖЕНИЕ, СОВПАДЕНИЕ, ТРЕКИНГ ============ // ============================================================ // Требуется OpenCV (core, imgproc, highgui, features2d, video, videoio) // // Пример компиляции (Linux, OpenCV4): // g++ main.cpp -o features `pkg-config --cflags --libs opencv4` // // Запуск: // ./features #include <opencv2/opencv.hpp> #include <opencv2/features2d.hpp> #include <iostream> // -------------------------- // CONFIG — УКАЗЫВАЕШЬ СВОИ ФАЙЛЫ // -------------------------- const std::string IMG1_PATH = "image1.png"; const std::string IMG2_PATH = "image2.png"; const std::string VIDEO_PATH = "video.mp4"; // если нет видео → оставь пустым "" const int LK_SHOW_EVERY = 10; // каждые сколько кадров показывать результат LK // -------------------------- // Вспомогательные функции // -------------------------- void show_img(const cv::Mat &img, const std::string &title = "Image") { cv::imshow(title, img); cv::waitKey(0); } cv::Mat load_gray(const std::string &path) { cv::Mat img = cv::imread(path, cv::IMREAD_GRAYSCALE); if (img.empty()) { std::cerr << "Не удалось загрузить изображение: " << path << std::endl; throw std::runtime_error("FileNotFound: " + path); } return img; } // -------------------------- // ORB: детекция и описание // -------------------------- void detect_orb(const cv::Mat &img, std::vector<cv::KeyPoint> &kp, cv::Mat &desc, int n_features = 1000) { cv::Ptr<cv::ORB> orb = cv::ORB::create(n_features); orb->detectAndCompute(img, cv::noArray(), kp, desc); } cv::Mat draw_keypoints(const cv::Mat &img, const std::vector<cv::KeyPoint> &kp, const std::string &title) { cv::Mat out; cv::drawKeypoints(img, kp, out, cv::Scalar::all(-1), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS); show_img(out, title); return out; } // -------------------------- // Сопоставление дескрипторов // -------------------------- std::vector<cv::DMatch> match_descriptors(const cv::Mat &desc1, const cv::Mat &desc2, float ratio = 0.75f) { cv::BFMatcher bf(cv::NORM_HAMMING); std::vector<std::vector<cv::DMatch>> knn_matches; bf.knnMatch(desc1, desc2, knn_matches, 2); std::vector<cv::DMatch> good; for (const auto &m : knn_matches) { if (m.size() < 2) continue; if (m[0].distance < ratio * m[1].distance) { good.push_back(m[0]); } } return good; } void draw_matches_img(const cv::Mat &img1, const std::vector<cv::KeyPoint> &kp1, const cv::Mat &img2, const std::vector<cv::KeyPoint> &kp2, const std::vector<cv::DMatch> &matches, int max_draw = 50) { std::vector<cv::DMatch> sorted_matches = matches; std::sort(sorted_matches.begin(), sorted_matches.end(), [](const cv::DMatch &a, const cv::DMatch &b) { return a.distance < b.distance; }); if (sorted_matches.size() > (size_t)max_draw) sorted_matches.resize(max_draw); cv::Mat out; cv::drawMatches(img1, kp1, img2, kp2, sorted_matches, out, cv::Scalar::all(-1), cv::Scalar::all(-1), std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); show_img(out, "ORB Matches"); } // -------------------------- // Lucas–Kanade трекинг (C++ версия) // -------------------------- void lucas_kanade_track(const std::string &video_path, int show_every = 10) { cv::VideoCapture cap(video_path); if (!cap.isOpened()) { std::cerr << "Не удалось открыть видео: " << video_path << std::endl; return; } cv::Mat old_frame; if (!cap.read(old_frame) || old_frame.empty()) { std::cerr << "Пустой первый кадр видео" << std::endl; return; } cv::Mat old_gray; cv::cvtColor(old_frame, old_gray, cv::COLOR_BGR2GRAY); std::vector<cv::Point2f> p0; cv::goodFeaturesToTrack(old_gray, p0, 300, 0.01, 7); cv::TermCriteria criteria(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 30, 0.01); cv::Size winSize(15, 15); int maxLevel = 3; cv::Mat mask = cv::Mat::zeros(old_frame.size(), old_frame.type()); int frame_id = 0; for (;;) { cv::Mat frame; if (!cap.read(frame) || frame.empty()) break; cv::Mat frame_gray; cv::cvtColor(frame, frame_gray, cv::COLOR_BGR2GRAY); std::vector<cv::Point2f> p1; std::vector<uchar> status; std::vector<float> err; if (p0.empty()) break; cv::calcOpticalFlowPyrLK(old_gray, frame_gray, p0, p1, status, err, winSize, maxLevel, criteria); std::vector<cv::Point2f> good_new; std::vector<cv::Point2f> good_old; for (size_t i = 0; i < p0.size(); ++i) { if (status[i]) { good_new.push_back(p1[i]); good_old.push_back(p0[i]); } } for (size_t i = 0; i < good_new.size(); ++i) { cv::Point p_new = good_new[i]; cv::Point p_old = good_old[i]; cv::line(mask, p_new, p_old, cv::Scalar(0, 255, 0), 2); cv::circle(frame, p_new, 3, cv::Scalar(0, 0, 255), -1); } cv::Mat combined; cv::add(frame, mask, combined); if (frame_id % show_every == 0) { cv::imshow("Lucas–Kanade", combined); // Нажмите любую клавишу для продолжения, 'q' для выхода int key = cv::waitKey(30); if (key == 'q' || key == 27) break; } old_gray = frame_gray.clone(); p0 = good_new; frame_id++; } cap.release(); cv::destroyWindow("Lucas–Kanade"); } // ============================================================ // ======================= MAIN PART ========================== // ============================================================ int main() { try { // 1. Загружаем изображения cv::Mat img1 = load_gray(IMG1_PATH); cv::Mat img2 = load_gray(IMG2_PATH); show_img(img1, "Image 1"); show_img(img2, "Image 2"); // 2. ORB признаки std::vector<cv::KeyPoint> kp1, kp2; cv::Mat desc1, desc2; detect_orb(img1, kp1, desc1); detect_orb(img2, kp2, desc2); std::cout << "Image1 ORB keypoints: " << kp1.size() << std::endl; std::cout << "Image2 ORB keypoints: " << kp2.size() << std::endl; draw_keypoints(img1, kp1, "ORB Keypoints (Image 1)"); draw_keypoints(img2, kp2, "ORB Keypoints (Image 2)"); // 3. Сопоставление if (!desc1.empty() && !desc2.empty()) { std::vector<cv::DMatch> matches = match_descriptors(desc1, desc2); std::cout << "Good matches: " << matches.size() << std::endl; if (!matches.empty()) { draw_matches_img(img1, kp1, img2, kp2, matches); } } else { std::cout << "Один из наборов дескрипторов пуст — сопоставление пропущено." << std::endl; } // 4. Трекинг LK (опционально) if (!VIDEO_PATH.empty()) { lucas_kanade_track(VIDEO_PATH, LK_SHOW_EVERY); } else { std::cout << "Видео для LK не указано — трекинг пропущен." << std::endl; } } catch (const std::exception &e) { std::cerr << "Ошибка: " << e.what() << std::endl; return 1; } return 0; }