이미지의 생산자는 새로운 이미지를 생성 및 신호를 통해를 방출한다. QImage
은 암시 적으로 공유되므로 새로운 할당을 피하기 위해 프레임을 자동으로 재활용합니다. 생산자 쓰레드가 디스플레이 쓰레드를 out-run 할 때만 이미지 사본이 만들어집니다.
Camera
개체에서 명시 적 루프를 사용하는 대신 제로 지속 시간 타이머를 사용하여 캡처를 실행하고 이벤트 루프에서 호출하도록 할 수 있습니다. 그렇게하면 카메라 객체가 이벤트를 처리 할 수 있습니다. 타이머, 크로스 스레드 슬롯 호출 등.
명시 적 뮤텍스 나 차단 연결이 필요 없습니다. Qt의 이벤트 루프는 스레드 간 동기화를 제공합니다. 마지막으로, QtOpenCVViewerGl 프로젝트는 CPU에서 이미지 스케일링을 수행하며 실제 수행하지 않는 방법의 예입니다. 쿼드에서 이미지를 그리면 고정 파이프 라인 시대의 구식 기법이기는하지만 이미지 스케일링을 무료로 얻을 수 있습니다.하지만 정상적으로 작동합니다. 다음과 같이
ASICamera
클래스는 거의 같을 것이다
// https://github.com/KubaO/stackoverflown/tree/master/questions/asi-astro-cam-39968889
#include <QtOpenGL>
#include <QOpenGLFunctions_2_0>
#include "ASICamera2.h"
class ASICamera : public QObject {
Q_OBJECT
ASI_ERROR_CODE m_error;
ASI_CAMERA_INFO m_info;
QImage m_frame{640, 480, QImage::Format_RGB888};
QTimer m_timer{this};
int m_exposure_ms = 0;
inline int id() const { return m_info.CameraID; }
void capture() {
m_error = ASIGetVideoData(id(), m_frame.bits(), m_frame.byteCount(),
m_exposure_ms*2 + 500);
if (m_error == ASI_SUCCESS)
emit newFrame(m_frame);
else
qDebug() << "capture error" << m_error;
}
public:
explicit ASICamera(QObject * parent = nullptr) : QObject{parent} {
connect(&m_timer, &QTimer::timeout, this, &ASICamera::capture);
}
ASI_ERROR_CODE error() const { return m_error; }
bool open(int index) {
m_error = ASIGetCameraProperty(&m_info, index);
if (m_error != ASI_SUCCESS)
return false;
m_error = ASIOpenCamera(id());
if (m_error != ASI_SUCCESS)
return false;
m_error = ASIInitCamera(id());
if (m_error != ASI_SUCCESS)
return false;
m_error = ASISetROIFormat(id(), m_frame.width(), m_frame.height(), 1, ASI_IMG_RGB24);
if (m_error != ASI_SUCCESS)
return false;
return true;
}
bool close() {
m_error = ASICloseCamera(id());
return m_error == ASI_SUCCESS;
}
Q_SIGNAL void newFrame(const QImage &);
QImage frame() const { return m_frame; }
Q_SLOT bool start() {
m_error = ASIStartVideoCapture(id());
if (m_error == ASI_SUCCESS)
m_timer.start(0);
return m_error == ASI_SUCCESS;
}
Q_SLOT bool stop() {
m_error = ASIStopVideoCapture(id());
return m_error == ASI_SUCCESS;
m_timer.stop();
}
~ASICamera() {
stop();
close();
}
};
내가 더미 ASI의 API 구현을 사용하고 있기 때문에, 위가 충분하다. 실제 ASI 카메라의 코드는 노출과 같은 적절한 컨트롤을 설정해야합니다.
는 OpenGL 뷰어도 매우 간단하다 :
class GLViewer : public QOpenGLWidget, protected QOpenGLFunctions_2_0 {
Q_OBJECT
QImage m_image;
void ck() {
for(GLenum err; (err = glGetError()) != GL_NO_ERROR;) qDebug() << "gl error" << err;
}
void initializeGL() override {
initializeOpenGLFunctions();
glClearColor(0.2f, 0.2f, 0.25f, 1.f);
}
void resizeGL(int width, int height) override {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
update();
}
// From http://stackoverflow.com/a/8774580/1329652
void paintGL() override {
auto scaled = m_image.size().scaled(this->size(), Qt::KeepAspectRatio);
GLuint texID;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glGenTextures(1, &texID);
glEnable(GL_TEXTURE_RECTANGLE);
glBindTexture(GL_TEXTURE_RECTANGLE, texID);
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGB, m_image.width(), m_image.height(), 0,
GL_RGB, GL_UNSIGNED_BYTE, m_image.constBits());
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(m_image.width(), 0);
glVertex2f(scaled.width(), 0);
glTexCoord2f(m_image.width(), m_image.height());
glVertex2f(scaled.width(), scaled.height());
glTexCoord2f(0, m_image.height());
glVertex2f(0, scaled.height());
glEnd();
glDisable(GL_TEXTURE_RECTANGLE);
glDeleteTextures(1, &texID);
ck();
}
public:
GLViewer(QWidget * parent = nullptr) : QOpenGLWidget{parent} {}
void setImage(const QImage & image) {
Q_ASSERT(image.format() == QImage::Format_RGB888);
m_image = image;
update();
}
};
마지막으로, 우리가 함께 카메라와 뷰어 후크.카메라 초기화에는 시간이 걸리기 때문에 카메라의 스레드에서 수행합니다.
UI는 카메라를 제어하는 신호를 내야합니다 (예 : 카메라를 열거 나 획득을 시작/중지 할 수 있으며 카메라에서 피드백을 제공하는 슬롯 (예 : 상태 변경)을 가질 수 있습니다. 독립적 인 함수는 UI를 특정 카메라에 적용하기 위해 펑터를 적절히 사용하여 두 객체를 가져 와서 연결합니다. 어댑터 코드가 광범위하다면 도우미 QObject
을 사용하지만 일반적으로 함수가 충분해야합니다 (아래 에서처럼).
는
class Thread : public QThread { public: ~Thread() { quit(); wait(); } };
// See http://stackoverflow.com/q/21646467/1329652
template <typename F>
static void postToThread(F && fun, QObject * obj = qApp) {
QObject src;
QObject::connect(&src, &QObject::destroyed, obj, std::forward<F>(fun),
Qt::QueuedConnection);
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
GLViewer viewer;
viewer.setMinimumSize(200, 200);
ASICamera camera;
Thread thread;
QObject::connect(&camera, &ASICamera::newFrame, &viewer, &GLViewer::setImage);
QObject::connect(&thread, &QThread::destroyed, [&]{ camera.moveToThread(app.thread()); });
camera.moveToThread(&thread);
thread.start();
postToThread([&]{
camera.open(0);
camera.start();
}, &camera);
viewer.show();
return app.exec();
}
#include "main.moc"
GitHub의 프로젝트는 아주 기본적인 ASI 카메라 API 테스트 하네스를 포함하고 완료 : 당신이 그것을 실행하고 실시간으로 렌더링 테스트 영상을 볼 수 있습니다.
자세한 답변을 보내 주셔서 감사합니다. 그것은 내가 기대했던 것보다 훨씬 더 많았다 :) – MonsterMax