From 6aa52236a8f8a530f5948cc4a3d6b33061338146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Poizl?= Date: Wed, 23 Oct 2019 08:53:19 +0200 Subject: [PATCH] First version OpenGL drawing --- image.frag | 13 +++++ image.vert | 11 ++++ imageringlist.cpp | 16 +++++- imageringlist.h | 7 ++- imagescrollareagl.cpp | 130 ++++++++++++++++++++++++++++++++++++++++++ imagescrollareagl.h | 48 ++++++++++++++++ loadrunable.cpp | 8 +-- main.cpp | 7 +++ mainwindow.cpp | 23 ++++++-- mainwindow.h | 4 +- rawimage.h | 11 +++- resources.qrc | 6 ++ stretchpanel.cpp | 21 +++++++ stretchpanel.h | 19 ++++++ tenmon.pro | 11 +++- 15 files changed, 318 insertions(+), 17 deletions(-) create mode 100644 image.frag create mode 100644 image.vert create mode 100644 imagescrollareagl.cpp create mode 100644 imagescrollareagl.h create mode 100644 resources.qrc create mode 100644 stretchpanel.cpp create mode 100644 stretchpanel.h diff --git a/image.frag b/image.frag new file mode 100644 index 0000000..2f6dc88 --- /dev/null +++ b/image.frag @@ -0,0 +1,13 @@ +#version 130 + +uniform sampler2D qt_Texture0; +varying vec2 qt_TexCoord0; +uniform vec2 scale; + +void main(void) +{ + float c = texture2D(qt_Texture0, qt_TexCoord0).r; + c = c*scale.x + scale.y; + float color = pow(c, 0.4545); + gl_FragColor = vec4(color, color, color, 1.0); +} diff --git a/image.vert b/image.vert new file mode 100644 index 0000000..10da880 --- /dev/null +++ b/image.vert @@ -0,0 +1,11 @@ +#version 130 + +attribute vec2 qt_Vertex; +attribute vec2 qt_MultiTexCoord0; +varying vec2 qt_TexCoord0; + +void main(void) +{ + gl_Position = vec4(qt_Vertex, 0.0, 1.0); + qt_TexCoord0 = qt_MultiTexCoord0; +} diff --git a/imageringlist.cpp b/imageringlist.cpp index 0361e08..8d58742 100644 --- a/imageringlist.cpp +++ b/imageringlist.cpp @@ -2,6 +2,7 @@ #include #include #include "loadrunable.h" +#include "rawimage.h" using namespace std; @@ -31,6 +32,7 @@ void Image::load() void Image::release() { m_pixmap = QPixmap(); + m_rawImage.reset(); m_released = true; m_loading = false; } @@ -45,6 +47,11 @@ QPixmap Image::pixmap() const return m_pixmap; } +RawImageAbs *Image::rawImage() +{ + return m_rawImage.get(); +} + ImageInfoData Image::info() const { return m_info; @@ -55,15 +62,20 @@ bool Image::isCurrent() const return !m_released; } -void Image::imageLoaded(QImage img, ImageInfoData info) +void Image::imageLoaded(QImage img, void *rawImage, ImageInfoData info) { m_loading = false; if(!m_released) { m_pixmap = QPixmap::fromImage(img); + m_rawImage.reset(static_cast(rawImage)); m_info = info; emit pixmapLoaded(this); } + else + { + delete rawImage; + } } ImageRingList::ImageRingList(QObject *parent) : QObject(parent) @@ -223,7 +235,7 @@ void ImageRingList::imageLoaded(Image *image) { if(image->name() == (*m_currImage)->name()) { - emit pixmapLoaded(image->pixmap()); + emit pixmapLoaded(image); emit infoLoaded(image->info()); } } diff --git a/imageringlist.h b/imageringlist.h index edff926..36fc1b7 100644 --- a/imageringlist.h +++ b/imageringlist.h @@ -7,6 +7,7 @@ #include #include #include "imageinfo.h" +#include "rawimage.h" class ImageRingList; @@ -17,6 +18,7 @@ class Image : public QObject bool m_released; bool m_current; QPixmap m_pixmap; + std::unique_ptr m_rawImage; QString m_name; ImageInfoData m_info; ImageRingList *m_ringList; @@ -26,12 +28,13 @@ public: void release(); QString name() const; QPixmap pixmap() const; + RawImageAbs* rawImage(); ImageInfoData info() const; bool isCurrent() const; signals: void pixmapLoaded(Image *ptr); protected slots: - void imageLoaded(QImage img, ImageInfoData info); + void imageLoaded(QImage img, void *rawImage, ImageInfoData info); }; typedef std::shared_ptr ImagePtr; @@ -65,7 +68,7 @@ protected: QList::iterator increment(QList::iterator iter); QList::iterator decrement(QList::iterator iter); signals: - void pixmapLoaded(QPixmap pix); + void pixmapLoaded(Image *image); void infoLoaded(ImageInfoData info); void currentImageChanged(); protected slots: diff --git a/imagescrollareagl.cpp b/imagescrollareagl.cpp new file mode 100644 index 0000000..8e3adad --- /dev/null +++ b/imagescrollareagl.cpp @@ -0,0 +1,130 @@ +#include "imagescrollareagl.h" +#include +#include +#include +#include + +ImageScrollAreaGL::ImageScrollAreaGL(QWidget *parent) : QOpenGLWidget(parent) +{ + setFocusPolicy(Qt::ClickFocus); + m_range = UINT16_MAX; + m_low = 0; + m_high = 1; +} + +ImageScrollAreaGL::~ImageScrollAreaGL() +{ + makeCurrent(); +} + +void ImageScrollAreaGL::setImage(RawImageAbs *image) +{ + m_image->destroy(); + m_image->setFormat(QOpenGLTexture::R16_UNorm); + m_image->setSize(image->width(), image->height()); + m_image->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear); + m_image->allocateStorage(); + if(RawImage *i8 = dynamic_cast*>(image)) + { + m_image->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, i8->data()); + m_range = UINT8_MAX; + } + else if(RawImage *i16 = dynamic_cast*>(image)) + { + m_image->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt16, i16->data()); + m_range = UINT16_MAX; + } + else if(RawImage *i32 = dynamic_cast*>(image)) + { + m_image->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt32, i32->data()); + m_range = UINT32_MAX; + } + m_image->generateMipMaps(); + repaint(); +} + +void ImageScrollAreaGL::setLow(int low) +{ + m_low = low/m_range; + repaint(); +} + +void ImageScrollAreaGL::setHigh(int high) +{ + m_high = high/m_range; + repaint(); +} + +void ImageScrollAreaGL::paintGL() +{ + float s = 1.0f/(m_high-m_low); + m_program->bind(); + m_program->setUniformValue("scale", s, -m_low*s); + + m_image->bind(0); + f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +} + +void ImageScrollAreaGL::resizeGL(int w, int h) +{ + m_width = w; + m_height = h; + f->glViewport(0, 0, w, h); +} + +void ImageScrollAreaGL::initializeGL() +{ + f = context()->functions(); + f->glClearColor(0.5f, 0.5f, 0.5f, 1.0f); + + m_vao = std::unique_ptr(new QOpenGLVertexArrayObject); + m_vao->create(); + m_vao->bind(); + + QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + logger->initialize(); + logger->startLogging(); + connect(logger, &QOpenGLDebugLogger::messageLogged, [](const QOpenGLDebugMessage &message) + { + qDebug() << message; + }); + + qDebug() << (char*)f->glGetString(GL_VENDOR); + qDebug() << (char*)f->glGetString(GL_RENDERER); + qDebug() << (char*)f->glGetString(GL_VERSION); + + qDebug() << context()->format(); + + // each vertex is x,y 2D position and s,t texture coordinates + float vertexs[] = {-1.0f, -1.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f,}; + m_buffer = std::unique_ptr(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer)); + m_buffer->setUsagePattern(QOpenGLBuffer::StaticDraw); + m_buffer->create(); + m_buffer->bind(); + m_buffer->allocate(vertexs, sizeof(vertexs)); + f->glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(float)*4, 0); + + m_program = std::unique_ptr(new QOpenGLShaderProgram); + m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/image.vert"); + m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/image.frag"); + if(!m_program->link()) + { + qDebug() << "Link failed" << m_program->log(); + } + + m_program->bind(); + m_program->enableAttributeArray("qt_Vertex"); + m_program->setAttributeBuffer("qt_Vertex", GL_FLOAT, 0, 2, sizeof(float)*4); + m_program->enableAttributeArray("qt_MultiTexCoord0"); + m_program->setAttributeBuffer("qt_MultiTexCoord0", GL_FLOAT, sizeof(float)*2, 2, sizeof(float)*4); + m_program->setUniformValue("qt_Texture0", (GLuint)0); + m_program->setUniformValue("scale", 1.0f, 0.0f); + + m_image = std::unique_ptr(new QOpenGLTexture(QImage("/home/nou/Obrázky/1p6yap.jpg"))); + m_image->bind(0); + m_image->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); + m_image->setMagnificationFilter(QOpenGLTexture::Linear); +} diff --git a/imagescrollareagl.h b/imagescrollareagl.h new file mode 100644 index 0000000..3e812a6 --- /dev/null +++ b/imagescrollareagl.h @@ -0,0 +1,48 @@ +#ifndef IMAGESCROLLAREAGL_H +#define IMAGESCROLLAREAGL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rawimage.h" + +typedef enum +{ + Linear, + Log, + Sqrt, + Power, + Asinh, +}StretchFunc; + +class ImageScrollAreaGL : public QOpenGLWidget +{ + Q_OBJECT + QOpenGLFunctions *f; + std::unique_ptr m_program; + std::unique_ptr m_buffer; + std::unique_ptr m_image; + std::unique_ptr m_vao; + int m_width, m_height; + float m_low; + float m_high; + float m_range; +public: + explicit ImageScrollAreaGL(QWidget *parent = nullptr); + ~ImageScrollAreaGL(); + void setImage(RawImageAbs *image); +public slots: + void setLow(int low); + void setHigh(int high); +protected: + void paintGL(); + void resizeGL(int w, int h); + void initializeGL(); +}; + +#endif // IMAGESCROLLAREAGL_H diff --git a/loadrunable.cpp b/loadrunable.cpp index 6e32bb7..70e2a9e 100644 --- a/loadrunable.cpp +++ b/loadrunable.cpp @@ -264,13 +264,13 @@ void LoadRunable::run() if(m_file.endsWith(".CR2", Qt::CaseInsensitive)) { timer.start(); - loadRAW(m_file, info, m_analyzeLevel != None ? &rawImage : nullptr, &img); + loadRAW(m_file, info, &rawImage, &img); raw = true; qDebug() << "LoadRaw" << timer.elapsed(); } else if(m_file.endsWith(".FIT", Qt::CaseInsensitive) || m_file.endsWith(".FITS", Qt::CaseInsensitive)) { - loadFITS(m_file, info, m_analyzeLevel != None ? &rawImage : nullptr, &img); + loadFITS(m_file, info, &rawImage, &img); } else { @@ -350,7 +350,5 @@ void LoadRunable::run() } } - if(rawImage)delete rawImage; - - QMetaObject::invokeMethod(m_receiver, "imageLoaded", Qt::QueuedConnection, Q_ARG(QImage, img), Q_ARG(ImageInfoData, info)); + QMetaObject::invokeMethod(m_receiver, "imageLoaded", Qt::QueuedConnection, Q_ARG(QImage, img), Q_ARG(void*, rawImage), Q_ARG(ImageInfoData, info)); } diff --git a/main.cpp b/main.cpp index a74b0a3..123e8da 100644 --- a/main.cpp +++ b/main.cpp @@ -1,8 +1,15 @@ #include "mainwindow.h" #include +#include int main(int argc, char *argv[]) { + QSurfaceFormat format; + format.setMajorVersion(3); + format.setMinorVersion(0); + format.setOption(QSurfaceFormat::DebugContext); + QSurfaceFormat::setDefaultFormat(format); + QApplication a(argc, argv); a.setOrganizationName("nou"); a.setApplicationName("Tenmon"); diff --git a/mainwindow.cpp b/mainwindow.cpp index 268cf96..181d520 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,4 +1,5 @@ #include "mainwindow.h" +#include "stretchpanel.h" #include #include #include @@ -26,6 +27,7 @@ int MainWindow::socketPair[2] = {0, 0}; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { qRegisterMetaType("ImageInfoData"); + qRegisterMetaType("RawImageAbs"); m_info = new ImageInfo(this); QDockWidget *infoDock = new QDockWidget(tr("Image info"), this); @@ -33,7 +35,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) infoDock->setObjectName("infoDock"); addDockWidget(Qt::LeftDockWidgetArea, infoDock); m_image = new ImageScrollArea(this); - setCentralWidget(m_image); + m_image->resize(0,0); + //setCentralWidget(m_image); resize(800, 600); PhotoCapture *photoCapture = new PhotoCapture(this); @@ -42,10 +45,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) captureDock->setObjectName("captureDock"); addDockWidget(Qt::BottomDockWidgetArea, captureDock); + m_imageGL = new ImageScrollAreaGL(this); + setCentralWidget(m_imageGL); + setWindowTitle(tr("Tenmon")); m_ringList = new ImageRingList(this); - connect(m_ringList, SIGNAL(pixmapLoaded(QPixmap)), this, SLOT(pixmapLoaded(QPixmap))); + connect(m_ringList, SIGNAL(pixmapLoaded(Image*)), this, SLOT(pixmapLoaded(Image*))); connect(m_ringList, SIGNAL(currentImageChanged()), this, SLOT(updateWindowTitle())); connect(m_ringList, SIGNAL(infoLoaded(ImageInfoData)), m_info, SLOT(setInfo(ImageInfoData))); @@ -106,6 +112,14 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) dockMenu->addAction(captureDock->toggleViewAction()); menuBar()->addMenu(dockMenu); + StretchPanel *stretchPanel = new StretchPanel(this); + connect(stretchPanel, SIGNAL(lowChanged(int)), m_imageGL, SLOT(setLow(int))); + connect(stretchPanel, SIGNAL(highChanged(int)), m_imageGL, SLOT(setHigh(int))); + + QDockWidget *stretchDock = new QDockWidget(tr("Stretch"), this); + stretchDock->setWidget(stretchPanel); + addDockWidget(Qt::LeftDockWidgetArea, stretchDock); + setupSigterm(); QSettings settings; restoreGeometry(settings.value("mainwindow/geometry").toByteArray()); @@ -187,9 +201,10 @@ void MainWindow::socketNotify() socketNotifier->setEnabled(true); } -void MainWindow::pixmapLoaded(QPixmap pix) +void MainWindow::pixmapLoaded(Image *image) { - m_image->setImage(pix); + m_image->setImage(image->pixmap()); + m_imageGL->setImage(image->rawImage()); } void MainWindow::openFile() diff --git a/mainwindow.h b/mainwindow.h index b12f7cd..ece8e06 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -7,11 +7,13 @@ #include "imagescrollarea.h" #include "database.h" #include "imageinfo.h" +#include "imagescrollareagl.h" class MainWindow : public QMainWindow { Q_OBJECT ImageScrollArea *m_image; + ImageScrollAreaGL *m_imageGL; ImageRingList *m_ringList; Database *m_database; ImageInfo *m_info; @@ -30,7 +32,7 @@ protected: protected slots: void socketNotify(); void updateWindowTitle(); - void pixmapLoaded(QPixmap pix); + void pixmapLoaded(Image *image); void openFile(); void markImage(); void unmarkImage(); diff --git a/rawimage.h b/rawimage.h index 097a100..2d0f7d9 100644 --- a/rawimage.h +++ b/rawimage.h @@ -31,6 +31,8 @@ public: class RawImageAbs { +protected: + uint32_t m_width,m_height; public: virtual ~RawImageAbs(){} virtual bool imageStats(uint64_t *mean, double *stdDev, uint64_t *median, uint64_t *min, uint64_t *max) const = 0; @@ -38,12 +40,19 @@ public: virtual int findPeaks(uint64_t background, double distance, std::vector &peaks) const = 0; virtual RawImageAbs* medianFilter() const = 0; virtual void quarter() = 0; + uint32_t width() const + { + return m_width; + } + uint32_t height() const + { + return m_height; + } }; template class RawImage : public RawImageAbs { - uint32_t m_width,m_height; std::vector m_img; bool checkPixel(T c, uint32_t x, uint32_t y) const { diff --git a/resources.qrc b/resources.qrc new file mode 100644 index 0000000..f699043 --- /dev/null +++ b/resources.qrc @@ -0,0 +1,6 @@ + + + image.frag + image.vert + + diff --git a/stretchpanel.cpp b/stretchpanel.cpp new file mode 100644 index 0000000..4a8eff6 --- /dev/null +++ b/stretchpanel.cpp @@ -0,0 +1,21 @@ +#include "stretchpanel.h" +#include + +StretchPanel::StretchPanel(QWidget *parent) : QWidget(parent) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + setLayout(layout); + + m_lowSlider = new QSlider(Qt::Horizontal, this); + m_highSlider = new QSlider(Qt::Horizontal, this); + + m_lowSlider->setRange(0, UINT16_MAX); + m_highSlider->setRange(0, UINT16_MAX); + m_highSlider->setValue(UINT16_MAX); + + layout->addWidget(m_lowSlider); + layout->addWidget(m_highSlider); + + connect(m_lowSlider, SIGNAL(valueChanged(int)), this, SIGNAL(lowChanged(int))); + connect(m_highSlider, SIGNAL(valueChanged(int)), this, SIGNAL(highChanged(int))); +} diff --git a/stretchpanel.h b/stretchpanel.h new file mode 100644 index 0000000..86ac37a --- /dev/null +++ b/stretchpanel.h @@ -0,0 +1,19 @@ +#ifndef STRETCHPANEL_H +#define STRETCHPANEL_H + +#include +#include + +class StretchPanel : public QWidget +{ + Q_OBJECT + QSlider *m_lowSlider; + QSlider *m_highSlider; +public: + explicit StretchPanel(QWidget *parent = nullptr); +signals: + void lowChanged(int low); + void highChanged(int high); +}; + +#endif // STRETCHPANEL_H diff --git a/tenmon.pro b/tenmon.pro index 6ae294e..7944dce 100644 --- a/tenmon.pro +++ b/tenmon.pro @@ -29,7 +29,9 @@ SOURCES += main.cpp\ imageinfo.cpp \ starfit.cpp \ phd.cpp \ - photocapture.cpp + photocapture.cpp \ + imagescrollareagl.cpp \ + stretchpanel.cpp HEADERS += mainwindow.h \ imagescrollarea.h \ @@ -40,4 +42,9 @@ HEADERS += mainwindow.h \ rawimage.h \ starfit.h \ phd.h \ - photocapture.h + photocapture.h \ + imagescrollareagl.h \ + stretchpanel.h + +RESOURCES += \ + resources.qrc