112 lines
3.7 KiB
C++
112 lines
3.7 KiB
C++
//=============================================================================
|
|
// 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 <opencv2/opencv.hpp>
|
|
|
|
#include <ctime>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
using namespace FlyCapture2;
|
|
|
|
static void printError(const Error &e) { e.PrintErrorTrace(); }
|
|
|
|
// Timestamped filename like fc2-<serial>-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;
|
|
}
|