//============================================================================= // fc2view — minimal live viewer for Point Grey / FLIR FlyCapture2 cameras. // // The vendor GUI (FlyCap2) can't run on Ubuntu 24.04 (dead GTK2 deps), so // this is a small native replacement built on OpenCV. It connects to the // first camera on the bus, streams frames into a window, and lets you save // snapshots. // // Keys: q or Esc quit // s save a snapshot (PNG, native bit depth) to $PWD // // Build: g++ fc2view.cpp -I/usr/include/flycapture \ // $(pkg-config --cflags --libs opencv4) -lflycapture -o fc2view //============================================================================= #include "FlyCapture2.h" #include #include #include #include #include using namespace FlyCapture2; static void printError(const Error &e) { e.PrintErrorTrace(); } // Timestamped filename like fc2--20260929-142530.png static std::string snapshotName(unsigned int serial) { std::time_t t = std::time(nullptr); std::tm tm = *std::localtime(&t); std::ostringstream s; s << "fc2-" << serial << "-" << std::put_time(&tm, "%Y%m%d-%H%M%S") << ".png"; return s.str(); } int main() { BusManager busMgr; unsigned int numCameras = 0; Error error = busMgr.GetNumOfCameras(&numCameras); if (error != PGRERROR_OK) { printError(error); return 1; } if (numCameras == 0) { std::cerr << "No FlyCapture2 cameras detected. Check `lsusb` for " "1e10:xxxx and your 'flirimaging' group membership.\n"; return 1; } PGRGuid guid; error = busMgr.GetCameraFromIndex(0, &guid); if (error != PGRERROR_OK) { printError(error); return 1; } Camera cam; error = cam.Connect(&guid); if (error != PGRERROR_OK) { printError(error); return 1; } CameraInfo camInfo; if (cam.GetCameraInfo(&camInfo) == PGRERROR_OK) { std::cout << "Connected: " << camInfo.modelName << " serial " << camInfo.serialNumber << " (" << camInfo.sensorResolution << ")\n"; } error = cam.StartCapture(); if (error != PGRERROR_OK) { printError(error); cam.Disconnect(); return 1; } const std::string win = "fc2view"; cv::namedWindow(win, cv::WINDOW_NORMAL); std::cout << "Streaming. Keys: 'q'/Esc quit, 's' save snapshot.\n"; Image rawImage, bgrImage; while (true) { error = cam.RetrieveBuffer(&rawImage); if (error != PGRERROR_OK) { printError(error); continue; } // Convert whatever the sensor delivers (mono, Bayer, ...) to 8-bit BGR // so it maps straight onto an OpenCV CV_8UC3 Mat with no reordering. error = rawImage.Convert(PIXEL_FORMAT_BGR, &bgrImage); if (error != PGRERROR_OK) { printError(error); continue; } cv::Mat frame(bgrImage.GetRows(), bgrImage.GetCols(), CV_8UC3, bgrImage.GetData(), bgrImage.GetStride()); if (frame.empty()) continue; cv::imshow(win, frame); int key = cv::waitKey(1) & 0xFF; if (key == 'q' || key == 27) break; // q or Esc if (key == 's') { // Save the raw frame so native bit depth (e.g. Mono16 on a SWIR // sensor) is preserved, not the 8-bit display copy. std::string name = snapshotName(camInfo.serialNumber); PNGOption png; if (rawImage.Save(name.c_str(), &png) == PGRERROR_OK) std::cout << "Saved " << name << "\n"; else std::cerr << "Failed to save " << name << "\n"; } } cam.StopCapture(); cam.Disconnect(); cv::destroyAllWindows(); return 0; }