尝试将相机采集图像流程封装成相机采图类
封装相机采集模块,GrabOnce.cpp下面是一个完整的相机采集图像的流程(控制台模式),要求把这个流程封装成一个相机采图类,类接口要求:
1. 三个对外接口,相机初始化,开始采图,停止采图
2. 类的构造,析构函数要完整,成员变量(私有,公有)定义完善,私有函数和接口函数区分开
3. 界面需要有三个按钮,初始化相机按钮,开始采图按钮,停止采图按钮
4. 语言C++, 界面Qt
一、1. 相机采集类封装(C++/Qt)
//--------------------------- CameraCapture.h ---------------------------
#pragma once
#include <QObject>
#include <QImage>
#include <atomic>
#include "IKapBoard.h"
#include "IKapC.h"
class CameraCapture : public QObject {
Q_OBJECT
public:
explicit CameraCapture(QObject *parent = nullptr);
~CameraCapture();
// 对外接口
bool initCamera();
void startGrabbing();
void stopGrabbing();
signals:
void imageGrabbed(const QImage &image); // 图像采集信号
void errorOccurred(const QString &msg); // 错误信号
private:
// IKapC 和 IKapBoard 资源
ITKDEVICE m_cameraHandle = nullptr;
HANDLE m_boardHandle = INVALID_HANDLE_VALUE;
std::atomic_bool m_isGrabbing{false};
bool m_isInitialized = false;
// 私有方法
bool configureCamera();
bool configureFrameGrabber();
void registerCallbacks();
void releaseResources();
// 回调函数包装器
static void CALLBACK OnFrameReadyWrapper(void *context);
void handleFrameReady();
};
//--------------------------- CameraCapture.cpp ---------------------------
#include "CameraCapture.h"
#include <QDebug>
CameraCapture::CameraCapture(QObject *parent) : QObject(parent) {}
CameraCapture::~CameraCapture() {
stopGrabbing();
releaseResources();
}
bool CameraCapture::initCamera() {
if (m_isInitialized) return true;
// 初始化 IKapC
ITKSTATUS res = ItkManInitialize();
if (res != ITKSTATUS_OK) {
emit errorOccurred("IKapC initialization failed");
return false;
}
// 配置相机和采集卡
if (!configureCamera() || !configureFrameGrabber()) {
releaseResources();
return false;
}
m_isInitialized = true;
return true;
}
void CameraCapture::startGrabbing() {
if (!m_isInitialized || m_isGrabbing) return;
ITKSTATUS res = ItkDevExecuteCommand(m_cameraHandle, "AcquisitionStart");
if (res != ITKSTATUS_OK) {
emit errorOccurred("Failed to start acquisition");
return;
}
int ret = IKapStartGrab(m_boardHandle, 1);
if (ret != 1) {
emit errorOccurred("Failed to start grabbing");
return;
}
m_isGrabbing = true;
}
void CameraCapture::stopGrabbing() {
if (!m_isGrabbing) return;
int ret = IKapStopGrab(m_boardHandle);
if (ret != 1) {
emit errorOccurred("Failed to stop grabbing");
}
m_isGrabbing = false;
}
//--------------------------- 私有方法实现 ---------------------------
bool CameraCapture::configureCamera() {
// ... (参考 GrabOnce.cpp 中的 ConfigureCamera 实现)
// 枚举设备、打开相机和采集卡
return true;
}
bool CameraCapture::configureFrameGrabber() {
// ... (参考 GrabOnce.cpp 中的 ConfigureFrameGrabber 实现)
// 配置缓冲区、超时、注册回调
registerCallbacks();
return true;
}
void CameraCapture::registerCallbacks() {
// 注册回调函数,传递 this 指针作为上下文
IKapRegisterCallback(m_boardHandle, IKEvent_FrameReady, &CameraCapture::OnFrameReadyWrapper, this);
}
void CameraCapture::releaseResources() {
if (m_boardHandle != INVALID_HANDLE_VALUE) {
IKapClose(m_boardHandle);
m_boardHandle = INVALID_HANDLE_VALUE;
}
if (m_cameraHandle != nullptr) {
ItkDevClose(m_cameraHandle);
m_cameraHandle = nullptr;
}
ItkManTerminate();
m_isInitialized = false;
}
//--------------------------- 回调函数包装器 ---------------------------
void CALLBACK CameraCapture::OnFrameReadyWrapper(void *context) {
CameraCapture *self = static_cast<CameraCapture*>(context);
self->handleFrameReady();
}
void CameraCapture::handleFrameReady() {
unsigned char *buffer = nullptr;
int frameSize = 0;
IKAPBUFFERSTATUS status;
// 获取图像数据
IKapGetBufferStatus(m_boardHandle, 0, &status);
if (status.uFull == 1) {
IKapGetInfo(m_boardHandle, IKP_FRAME_SIZE, &frameSize);
IKapGetBufferAddress(m_boardHandle, 0, (void**)&buffer);
// 转换为 QImage(假设图像格式为 RGB888)
QImage img(buffer, status.uWidth, status.uHeight, QImage::Format_RGB888);
emit imageGrabbed(img); // 发送图像信号
}
}
二、QT界面实现
//--------------------------- MainWindow.h ---------------------------
#include <QMainWindow>
#include "CameraCapture.h"
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void onInitClicked();
void onStartClicked();
void onStopClicked();
void updateImage(const QImage &img);
void handleError(const QString &msg);
private:
Ui::MainWindow *ui;
CameraCapture *m_camera;
};
//--------------------------- MainWindow.cpp ---------------------------
#include "MainWindow.h"
#include "ui_MainWindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow), m_camera(new CameraCapture(this)) {
ui->setupUi(this);
// 初始化按钮状态
ui->startButton->setEnabled(false);
ui->stopButton->setEnabled(false);
// 连接信号槽
connect(ui->initButton, &QPushButton::clicked, this, &MainWindow::onInitClicked);
connect(ui->startButton, &QPushButton::clicked, this, &MainWindow::onStartClicked);
connect(ui->stopButton, &QPushButton::clicked, this, &MainWindow::onStopClicked);
connect(m_camera, &CameraCapture::imageGrabbed, this, &MainWindow::updateImage);
connect(m_camera, &CameraCapture::errorOccurred, this, &MainWindow::handleError);
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::onInitClicked() {
if (m_camera->initCamera()) {
ui->startButton->setEnabled(true);
ui->initButton->setEnabled(false);
}
}
void MainWindow::onStartClicked() {
m_camera->startGrabbing();
ui->startButton->setEnabled(false);
ui->stopButton->setEnabled(true);
}
void MainWindow::onStopClicked() {
m_camera->stopGrabbing();
ui->startButton->setEnabled(true);
ui->stopButton->setEnabled(false);
}
void MainWindow::updateImage(const QImage &img) {
ui->imageLabel->setPixmap(QPixmap::fromImage(img).scaled(
ui->imageLabel->size(), Qt::KeepAspectRatio));
}
void MainWindow::handleError(const QString &msg) {
QMessageBox::critical(this, "Error", msg);
}
三、Qt 界面文件(MainWindow.ui)
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout">
<item>
<widget class="QLabel" name="imageLabel">
<property name="minimumSize">
<size>
<width>640</width>
<height>480</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QPushButton" name="initButton">
<property name="text">
<string>Initialize</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="startButton">
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stopButton">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</ui>