Add thumbnails

This commit is contained in:
2022-04-18 07:16:46 +02:00
parent 2c95364fc4
commit 4e6230eef2
14 changed files with 347 additions and 39 deletions
+2 -2
View File
@@ -1,10 +1,10 @@
#version 130 #version 130
uniform sampler2D qt_Texture0; uniform sampler2D qt_Texture0;
in vec2 qt_TexCoord0;
uniform vec3 mtf_param; uniform vec3 mtf_param;
uniform bool bw; uniform bool bw;
uniform bool invert; uniform bool invert;
in vec2 qt_TexCoord0;
out vec4 color; out vec4 color;
vec4 MTF(vec4 x, vec3 m) vec4 MTF(vec4 x, vec3 m)
@@ -16,7 +16,7 @@ vec4 MTF(vec4 x, vec3 m)
void main(void) void main(void)
{ {
color = texture2D(qt_Texture0, qt_TexCoord0); color = texture(qt_Texture0, qt_TexCoord0);
if(bw)color = color.rrra; if(bw)color = color.rrra;
color = MTF(color, mtf_param); color = MTF(color, mtf_param);
+50 -4
View File
@@ -8,10 +8,11 @@ using namespace std;
const int DEFAULT_WIDTH = 2; const int DEFAULT_WIDTH = 2;
Image::Image(const QString name, ImageRingList *ringList) : Image::Image(const QString name, int number, ImageRingList *ringList) :
m_loading(false), m_loading(false),
m_released(true), m_released(true),
m_current(false), m_current(false),
m_number(number),
m_name(name), m_name(name),
m_ringList(ringList) m_ringList(ringList)
{ {
@@ -29,6 +30,14 @@ void Image::load()
emit pixmapLoaded(this); emit pixmapLoaded(this);
} }
void Image::loadThumbnail()
{
if(!m_thumbnail)
QThreadPool::globalInstance()->start(new LoadRunable(m_name, this, AnalyzeLevel::None, true));
else
emit thumbnailLoaded(this);
}
void Image::release() void Image::release()
{ {
m_rawImage.reset(); m_rawImage.reset();
@@ -46,6 +55,11 @@ RawImage *Image::rawImage()
return m_rawImage.get(); return m_rawImage.get();
} }
const RawImage *Image::thumbnail() const
{
return m_thumbnail.get();
}
ImageInfoData Image::info() const ImageInfoData Image::info() const
{ {
return m_info; return m_info;
@@ -56,6 +70,11 @@ bool Image::isCurrent() const
return !m_released; return !m_released;
} }
int Image::number() const
{
return m_number;
}
void Image::imageLoaded(void *rawImage, ImageInfoData info) void Image::imageLoaded(void *rawImage, ImageInfoData info)
{ {
m_loading = false; m_loading = false;
@@ -71,6 +90,13 @@ void Image::imageLoaded(void *rawImage, ImageInfoData info)
} }
} }
void Image::thumbnailLoadFinish(void *rawImage)
{
m_thumbnail.reset(static_cast<RawImage*>(rawImage));
if(m_thumbnail)
emit thumbnailLoaded(this);
}
ImageRingList::ImageRingList(QObject *parent) : QAbstractItemModel(parent) ImageRingList::ImageRingList(QObject *parent) : QAbstractItemModel(parent)
, m_liveMode(false) , m_liveMode(false)
, m_analyzeLevel(None) , m_analyzeLevel(None)
@@ -93,7 +119,7 @@ bool ImageRingList::setDir(const QString path, const QString &currentFile)
QStringList nameFilter; QStringList nameFilter;
nameFilter << "*.jpg" << "*.jpeg" << "*.png" << "*.cr2" << "*.fit" << "*.fits" << "*.xisf"; nameFilter << "*.jpg" << "*.jpeg" << "*.png" << "*.cr2" << "*.fit" << "*.fits" << "*.xisf";
QStringList list = dir.entryList(nameFilter, QDir::Files | QDir::Readable, m_liveMode ? QDir::Time : QDir::Name); QStringList list = dir.entryList(nameFilter, QDir::Files | QDir::Readable, m_liveMode ? QDir::Time : QDir::Name | QDir::IgnoreCase);
QStringList absolutePaths; QStringList absolutePaths;
foreach(const QString &file, list) foreach(const QString &file, list)
{ {
@@ -209,6 +235,24 @@ void ImageRingList::loadFile(int row)
} }
} }
void ImageRingList::loadThumbnails()
{
for(auto &img : m_images)
{
img->loadThumbnail();
}
}
void ImageRingList::stopLoading()
{
QThreadPool::globalInstance()->clear();
}
int ImageRingList::imageCount() const
{
return m_images.size();
}
QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const
{ {
return createIndex(row, column, m_images.at(row).get()); return createIndex(row, column, m_images.at(row).get());
@@ -261,10 +305,12 @@ void ImageRingList::setFiles(const QStringList files, const QString &currentFile
QThreadPool::globalInstance()->waitForDone(); QThreadPool::globalInstance()->waitForDone();
beginResetModel(); beginResetModel();
m_images.clear(); m_images.clear();
foreach(const QString &file, files) int i = 0;
for(const QString &file : files)
{ {
ImagePtr ptr = make_shared<Image>(file, this); ImagePtr ptr = make_shared<Image>(file, i++, this);
connect(ptr.get(), SIGNAL(pixmapLoaded(Image*)), this, SLOT(imageLoaded(Image*))); connect(ptr.get(), SIGNAL(pixmapLoaded(Image*)), this, SLOT(imageLoaded(Image*)));
connect(ptr.get(), SIGNAL(thumbnailLoaded(Image*)), this, SIGNAL(thumbnailLoaded(Image*)));
m_images.append(ptr); m_images.append(ptr);
} }
+12 -1
View File
@@ -17,22 +17,29 @@ class Image : public QObject
bool m_loading; bool m_loading;
bool m_released; bool m_released;
bool m_current; bool m_current;
int m_number;
std::unique_ptr<RawImage> m_rawImage; std::unique_ptr<RawImage> m_rawImage;
std::unique_ptr<RawImage> m_thumbnail;
QString m_name; QString m_name;
ImageInfoData m_info; ImageInfoData m_info;
ImageRingList *m_ringList; ImageRingList *m_ringList;
public: public:
explicit Image(const QString name, ImageRingList *ringList); explicit Image(const QString name, int number, ImageRingList *ringList);
void load(); void load();
void loadThumbnail();
void release(); void release();
QString name() const; QString name() const;
RawImage* rawImage(); RawImage* rawImage();
const RawImage* thumbnail() const;
ImageInfoData info() const; ImageInfoData info() const;
bool isCurrent() const; bool isCurrent() const;
int number() const;
signals: signals:
void pixmapLoaded(Image *ptr); void pixmapLoaded(Image *ptr);
void thumbnailLoaded(Image *ptr);
protected slots: protected slots:
void imageLoaded(void *rawImage, ImageInfoData info); void imageLoaded(void *rawImage, ImageInfoData info);
void thumbnailLoadFinish(void *rawImage);
}; };
typedef std::shared_ptr<Image> ImagePtr; typedef std::shared_ptr<Image> ImagePtr;
@@ -62,6 +69,9 @@ public:
void setFindStars(bool findStars); void setFindStars(bool findStars);
AnalyzeLevel analyzeLevel() const; AnalyzeLevel analyzeLevel() const;
void loadFile(int row); void loadFile(int row);
void loadThumbnails();
void stopLoading();
int imageCount() const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override; QModelIndex parent(const QModelIndex &child) const override;
@@ -75,6 +85,7 @@ protected:
QList<ImagePtr>::iterator decrement(QList<ImagePtr>::iterator iter); QList<ImagePtr>::iterator decrement(QList<ImagePtr>::iterator iter);
signals: signals:
void pixmapLoaded(Image *image); void pixmapLoaded(Image *image);
void thumbnailLoaded(Image *image);
void infoLoaded(ImageInfoData info); void infoLoaded(ImageInfoData info);
void currentImageChanged(int index); void currentImageChanged(int index);
protected slots: protected slots:
+154 -23
View File
@@ -55,6 +55,8 @@ ImageWidget::ImageWidget(QWidget *parent) : QOpenGLWidget(parent)
m_range = UINT16_MAX; m_range = UINT16_MAX;
m_imgWidth = m_imgHeight = -1; m_imgWidth = m_imgHeight = -1;
m_superpixel = m_invert = false; m_superpixel = m_invert = false;
m_showThumbnails = false;
m_thumbnailCount = 0;
setAcceptDrops(true); setAcceptDrops(true);
} }
@@ -115,6 +117,19 @@ void ImageWidget::blockRepaint(bool block)
if(!block)update(); if(!block)update();
} }
void ImageWidget::allocateThumbnails(int count)
{
m_thumbnailTexture->destroy();
m_thumbnailTexture->create();
m_thumbnailTexture->setFormat(QOpenGLTexture::RGB16_UNorm);
m_thumbnailTexture->setSize(THUMB_SIZE, THUMB_SIZE);
m_thumbnailTexture->setLayers(count);
m_thumbnailTexture->allocateStorage();
m_bufferSizes->bind();
m_bufferSizes->allocate(count * sizeof(float)*3);
m_thumbnailCount = count;
}
void ImageWidget::setMTFParams(float low, float mid, float high) void ImageWidget::setMTFParams(float low, float mid, float high)
{ {
m_low = low; m_low = low;
@@ -164,6 +179,23 @@ QImage ImageWidget::renderToImage()
return fbo.toImage(true); return fbo.toImage(true);
} }
void ImageWidget::thumbnailLoaded(const Image *image)
{
const RawImage *raw = image->thumbnail();
m_thumbnailTexture->setData(0, image->number(), QOpenGLTexture::RGB, QOpenGLTexture::UInt16, raw->data(), m_transferOptions.get());
float a = raw->thumbAspect();
int sizes[3] = { std::max(1, a > 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE * a)), std::max(1, a < 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE / a)), image->number() };
m_bufferSizes->bind();
m_bufferSizes->write(image->number() * sizeof(sizes), sizes, sizeof(sizes));
update();
}
void ImageWidget::showThumbnail(bool enable)
{
m_showThumbnails = enable;
update();
}
void ImageWidget::paintGL() void ImageWidget::paintGL()
{ {
if(m_blockRepaint)return; if(m_blockRepaint)return;
@@ -175,16 +207,35 @@ void ImageWidget::paintGL()
if(height() > m_image->height()*m_scale) if(height() > m_image->height()*m_scale)
dy = -height()*0.5f + m_image->height()*m_scale*0.5f; dy = -height()*0.5f + m_image->height()*m_scale*0.5f;
m_program->bind(); if(m_showThumbnails)
m_program->setUniformValue("viewport", (float)width(), (float)height()); {
m_program->setUniformValue("offset", dx, dy); m_vaoThumb->bind();
m_program->setUniformValue("mtf_param", m_low, m_mid, m_high); m_thumbnailTexture->bind(1);
m_program->setUniformValue("zoom", 1.0f/m_scale); m_thumbnailProgram->bind();
m_program->setUniformValue("bw", m_bwImg); f->glUniform3i(m_thumbnailProgram->uniformLocation("viewport_row"), width(), height(), width()/THUMB_SIZE_BORDER);
m_program->setUniformValue("invert", m_invert); m_thumbnailProgram->setUniformValue("mtf_param", m_low, m_mid, m_high);
m_thumbnailProgram->setUniformValue("invert", m_invert);
m_thumbnailProgram->setUniformValue("offset", m_dx, m_dy);
f3->glVertexAttribDivisor(m_thumbnailProgram->attributeLocation("imageSize_num"), 1);
QMatrix4x4 mvp;
mvp.ortho(rect());
m_thumbnailProgram->setUniformValue("mvp", mvp);
if(f3)f3->glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, m_thumbnailCount);
}
else
{
m_vao->bind();
m_image->bind(0);
m_program->bind();
m_program->setUniformValue("viewport", (float)width(), (float)height());
m_program->setUniformValue("offset", dx, dy);
m_program->setUniformValue("mtf_param", m_low, m_mid, m_high);
m_program->setUniformValue("zoom", 1.0f/m_scale);
m_program->setUniformValue("bw", m_bwImg);
m_program->setUniformValue("invert", m_invert);
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
m_image->bind(0);
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
} }
void ImageWidget::resizeGL(int w, int h) void ImageWidget::resizeGL(int w, int h)
@@ -198,10 +249,12 @@ void ImageWidget::initializeGL()
{ {
f = context()->functions(); f = context()->functions();
f->glClearColor(0.5f, 0.5f, 0.5f, 1.0f); f->glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
QOpenGLFunctions_3_2_Core *f3 = context()->versionFunctions<QOpenGLFunctions_3_2_Core>(); f3 = context()->versionFunctions<QOpenGLFunctions_3_3_Core>();
m_vao = std::unique_ptr<QOpenGLVertexArrayObject>(new QOpenGLVertexArrayObject); m_vao = std::unique_ptr<QOpenGLVertexArrayObject>(new QOpenGLVertexArrayObject);
m_vaoThumb = std::unique_ptr<QOpenGLVertexArrayObject>(new QOpenGLVertexArrayObject);
m_vao->create(); m_vao->create();
m_vaoThumb->create();
m_vao->bind(); m_vao->bind();
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
@@ -228,7 +281,7 @@ void ImageWidget::initializeGL()
m_buffer->create(); m_buffer->create();
m_buffer->bind(); m_buffer->bind();
m_buffer->allocate(vertexs, sizeof(vertexs)); m_buffer->allocate(vertexs, sizeof(vertexs));
f->glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(float)*4, 0); // f->glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(float)*4, 0);
m_program = std::unique_ptr<QOpenGLShaderProgram>(new QOpenGLShaderProgram); m_program = std::unique_ptr<QOpenGLShaderProgram>(new QOpenGLShaderProgram);
m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/image.vert"); m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/image.vert");
@@ -247,6 +300,33 @@ void ImageWidget::initializeGL()
m_program->setUniformValue("qt_Texture0", (GLuint)0); m_program->setUniformValue("qt_Texture0", (GLuint)0);
m_program->setUniformValue("scale", 1.0f, 0.0f); m_program->setUniformValue("scale", 1.0f, 0.0f);
m_vaoThumb->bind();
m_thumbnailProgram = std::unique_ptr<QOpenGLShaderProgram>(new QOpenGLShaderProgram);
m_thumbnailProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/thumb.vert");
m_thumbnailProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/thumb.frag");
if(f3)f3->glBindFragDataLocation(m_program->programId(), 0, "color");
m_thumbnailProgram->bind();
m_thumbnailProgram->enableAttributeArray("qt_Vertex");
m_thumbnailProgram->setAttributeBuffer("qt_Vertex", GL_FLOAT, 0, 2, sizeof(float)*4);
m_thumbnailProgram->enableAttributeArray("qt_MultiTexCoord0");
m_thumbnailProgram->setAttributeBuffer("qt_MultiTexCoord0", GL_FLOAT, sizeof(float)*2, 2, sizeof(float)*4);
if(!m_thumbnailProgram->link())
{
qDebug() << "Link failed" << m_thumbnailProgram->log();
}
m_thumbnailProgram->setUniformValue("qt_Texture0", (GLuint)1);
m_bufferSizes = std::unique_ptr<QOpenGLBuffer>(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer));
m_bufferSizes->setUsagePattern(QOpenGLBuffer::StaticDraw);
m_bufferSizes->create();
m_bufferSizes->bind();
m_bufferSizes->allocate(12);
m_thumbnailProgram->enableAttributeArray("imageSize_num");
m_thumbnailProgram->setAttributeBuffer("imageSize_num", GL_FLOAT, 0, 3);
f3->glVertexAttribDivisor(m_thumbnailProgram->attributeLocation("imageSize_num"), 1);
m_image = std::unique_ptr<QOpenGLTexture>(new QOpenGLTexture(QOpenGLTexture::Target2D)); m_image = std::unique_ptr<QOpenGLTexture>(new QOpenGLTexture(QOpenGLTexture::Target2D));
m_image->setFormat(QOpenGLTexture::RGB8U); m_image->setFormat(QOpenGLTexture::RGB8U);
m_image->allocateStorage(); m_image->allocateStorage();
@@ -254,6 +334,15 @@ void ImageWidget::initializeGL()
m_image->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_image->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
m_image->setMagnificationFilter(QOpenGLTexture::Linear); m_image->setMagnificationFilter(QOpenGLTexture::Linear);
m_thumbnailTexture = std::unique_ptr<QOpenGLTexture>(new QOpenGLTexture(QOpenGLTexture::Target2DArray));
m_thumbnailTexture->setFormat(QOpenGLTexture::RGB16_UNorm);
m_thumbnailTexture->setSize(THUMB_SIZE, THUMB_SIZE);
m_thumbnailTexture->setLayers(1);
m_thumbnailTexture->allocateStorage();
m_thumbnailTexture->bind(1);
m_thumbnailTexture->setMinificationFilter(QOpenGLTexture::Linear);
m_thumbnailTexture->setMinificationFilter(QOpenGLTexture::Linear);
m_transferOptions = std::unique_ptr<QOpenGLPixelTransferOptions>(new QOpenGLPixelTransferOptions); m_transferOptions = std::unique_ptr<QOpenGLPixelTransferOptions>(new QOpenGLPixelTransferOptions);
m_transferOptions->setAlignment(1); m_transferOptions->setAlignment(1);
} }
@@ -292,6 +381,7 @@ ImageScrollAreaGL::ImageScrollAreaGL(QWidget *parent) : QWidget(parent)
m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this); m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this);
m_scale = 1.0f; m_scale = 1.0f;
m_bestFit = false; m_bestFit = false;
m_thumbCount = 0;
layout->setSpacing(0); layout->setSpacing(0);
layout->addWidget(m_imageWidget, 0, 0); layout->addWidget(m_imageWidget, 0, 0);
@@ -330,32 +420,66 @@ ImageWidget *ImageScrollAreaGL::imageWidget()
return m_imageWidget; return m_imageWidget;
} }
void ImageScrollAreaGL::updateScrollbars(bool zoom) void ImageScrollAreaGL::setThumbnails(int count)
{ {
if(zoom) m_thumbCount = count;
if(m_thumbCount)
{ {
setScrollRange(m_verticalScrollBar, m_imgHeight*m_scale); m_verticalScrollBar->setRange(0, (m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) + 1) * THUMB_SIZE_BORDER);
setScrollRange(m_horizontalScrollBar, m_imgWidth*m_scale); m_verticalScrollBar->setPageStep(THUMB_SIZE);
} }
else else
{ {
m_verticalScrollBar->setRange(0, m_imgHeight*m_scale - m_verticalScrollBar->pageStep()); m_verticalScrollBar->setPageStep(m_imageWidget->height());
m_horizontalScrollBar->setRange(0, m_imgWidth*m_scale - m_horizontalScrollBar->pageStep()); m_horizontalScrollBar->setPageStep(m_imageWidget->width());
}
updateScrollbars();
}
void ImageScrollAreaGL::updateScrollbars(bool zoom)
{
if(m_thumbCount)
{
m_horizontalScrollBar->hide();
m_verticalScrollBar->show();
m_verticalScrollBar->setRange(0, (m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) + 1) * THUMB_SIZE_BORDER);
m_verticalScrollBar->setPageStep(128);
}
else
{
if(zoom)
{
setScrollRange(m_verticalScrollBar, m_imgHeight*m_scale);
setScrollRange(m_horizontalScrollBar, m_imgWidth*m_scale);
}
else
{
m_verticalScrollBar->setRange(0, m_imgHeight*m_scale - m_verticalScrollBar->pageStep());
m_horizontalScrollBar->setRange(0, m_imgWidth*m_scale - m_horizontalScrollBar->pageStep());
}
} }
} }
void ImageScrollAreaGL::resizeEvent(QResizeEvent *event) void ImageScrollAreaGL::resizeEvent(QResizeEvent *event)
{ {
QWidget::resizeEvent(event); QWidget::resizeEvent(event);
m_verticalScrollBar->setPageStep(m_imageWidget->height()); if(m_thumbCount)
m_horizontalScrollBar->setPageStep(m_imageWidget->width()); {
m_verticalScrollBar->setRange(0, (m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) + 1) * THUMB_SIZE_BORDER);
m_verticalScrollBar->setPageStep(128);
}
else
{
m_verticalScrollBar->setPageStep(m_imageWidget->height());
m_horizontalScrollBar->setPageStep(m_imageWidget->width());
}
updateScrollbars(); updateScrollbars();
} }
void ImageScrollAreaGL::mouseMoveEvent(QMouseEvent *event) void ImageScrollAreaGL::mouseMoveEvent(QMouseEvent *event)
{ {
QPoint delta = m_lastPos - event->pos(); QPoint delta = m_lastPos - event->pos();
m_horizontalScrollBar->setValue(m_horizontalScrollBar->value() + delta.x()); if(m_thumbCount == 0)m_horizontalScrollBar->setValue(m_horizontalScrollBar->value() + delta.x());
m_verticalScrollBar->setValue(m_verticalScrollBar->value() + delta.y()); m_verticalScrollBar->setValue(m_verticalScrollBar->value() + delta.y());
m_lastPos = event->pos(); m_lastPos = event->pos();
} }
@@ -367,9 +491,16 @@ void ImageScrollAreaGL::mousePressEvent(QMouseEvent *event)
void ImageScrollAreaGL::wheelEvent(QWheelEvent *event) void ImageScrollAreaGL::wheelEvent(QWheelEvent *event)
{ {
m_bestFit = false; if(m_thumbCount)
if(event->angleDelta().y() != 0) {
zoom(event->angleDelta().y() / 1200.0f); m_verticalScrollBar->setValue(m_verticalScrollBar->value() - event->angleDelta().y());
}
else
{
m_bestFit = false;
if(event->angleDelta().y() != 0)
zoom(event->angleDelta().y() / 1200.0f);
}
} }
void ImageScrollAreaGL::zoom(float delta) void ImageScrollAreaGL::zoom(float delta)
+14 -1
View File
@@ -4,13 +4,14 @@
#include <memory> #include <memory>
#include <QObject> #include <QObject>
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include <QOpenGLFunctions_3_2_Core> #include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QOpenGLBuffer> #include <QOpenGLBuffer>
#include <QOpenGLTexture> #include <QOpenGLTexture>
#include <QOpenGLVertexArrayObject> #include <QOpenGLVertexArrayObject>
#include <QScrollBar> #include <QScrollBar>
#include "rawimage.h" #include "rawimage.h"
#include "imageringlist.h"
typedef enum typedef enum
{ {
@@ -25,11 +26,16 @@ class ImageWidget : public QOpenGLWidget
{ {
Q_OBJECT Q_OBJECT
QOpenGLFunctions *f; QOpenGLFunctions *f;
QOpenGLFunctions_3_3_Core *f3;
std::unique_ptr<QOpenGLShaderProgram> m_program; std::unique_ptr<QOpenGLShaderProgram> m_program;
std::unique_ptr<QOpenGLShaderProgram> m_thumbnailProgram;
std::unique_ptr<QOpenGLBuffer> m_buffer; std::unique_ptr<QOpenGLBuffer> m_buffer;
std::unique_ptr<QOpenGLBuffer> m_bufferSizes;
std::unique_ptr<QOpenGLTexture> m_image; std::unique_ptr<QOpenGLTexture> m_image;
std::unique_ptr<QOpenGLVertexArrayObject> m_vao; std::unique_ptr<QOpenGLVertexArrayObject> m_vao;
std::unique_ptr<QOpenGLVertexArrayObject> m_vaoThumb;
std::unique_ptr<QOpenGLPixelTransferOptions> m_transferOptions; std::unique_ptr<QOpenGLPixelTransferOptions> m_transferOptions;
std::unique_ptr<QOpenGLTexture> m_thumbnailTexture;
int m_width, m_height; int m_width, m_height;
int m_imgWidth, m_imgHeight; int m_imgWidth, m_imgHeight;
float m_low; float m_low;
@@ -42,6 +48,8 @@ class ImageWidget : public QOpenGLWidget
bool m_bwImg; bool m_bwImg;
bool m_invert; bool m_invert;
bool m_superpixel; bool m_superpixel;
bool m_showThumbnails;
int m_thumbnailCount;
public: public:
explicit ImageWidget(QWidget *parent = nullptr); explicit ImageWidget(QWidget *parent = nullptr);
~ImageWidget(); ~ImageWidget();
@@ -49,12 +57,15 @@ public:
void setImage(const QPixmap &pixmap); void setImage(const QPixmap &pixmap);
void setScale(float scale); void setScale(float scale);
void blockRepaint(bool block); void blockRepaint(bool block);
void allocateThumbnails(int count);
public slots: public slots:
void setMTFParams(float low, float mid, float high); void setMTFParams(float low, float mid, float high);
void setOffset(int dx, int dy); void setOffset(int dx, int dy);
void superPixel(bool enable); void superPixel(bool enable);
void invert(bool enable); void invert(bool enable);
QImage renderToImage(); QImage renderToImage();
void thumbnailLoaded(const Image *image);
void showThumbnail(bool enable);
protected: protected:
void paintGL(); void paintGL();
void resizeGL(int w, int h); void resizeGL(int w, int h);
@@ -75,12 +86,14 @@ class ImageScrollAreaGL : public QWidget
QPoint m_lastPos; QPoint m_lastPos;
float m_scale; float m_scale;
bool m_bestFit; bool m_bestFit;
int m_thumbCount;
public: public:
explicit ImageScrollAreaGL(QWidget *parent = nullptr); explicit ImageScrollAreaGL(QWidget *parent = nullptr);
~ImageScrollAreaGL(); ~ImageScrollAreaGL();
void setImage(RawImage *image); void setImage(RawImage *image);
void setImage(const QPixmap &pixmap); void setImage(const QPixmap &pixmap);
ImageWidget* imageWidget(); ImageWidget* imageWidget();
void setThumbnails(int count);
protected: protected:
void updateScrollbars(bool zoom = false); void updateScrollbars(bool zoom = false);
void resizeEvent(QResizeEvent *event); void resizeEvent(QResizeEvent *event);
+20 -5
View File
@@ -12,11 +12,13 @@
#include <pcl/XISF.h> #include <pcl/XISF.h>
#include "rawimage.h" #include "rawimage.h"
#include "starfit.h" #include "starfit.h"
#include <opencv2/imgcodecs.hpp>
LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level) : LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail) :
m_file(file), m_file(file),
m_receiver(receiver), m_receiver(receiver),
m_analyzeLevel(level) m_analyzeLevel(level),
m_thumbnail(thumbnail)
{ {
} }
@@ -334,7 +336,7 @@ bool loadXISF(const QString &path, ImageInfoData &info, RawImage **image)
void LoadRunable::run() void LoadRunable::run()
{ {
if(!m_receiver->isCurrent()) if(!m_thumbnail && !m_receiver->isCurrent())
{ {
return; return;
} }
@@ -375,7 +377,7 @@ void LoadRunable::run()
rawImage = new RawImage(img); rawImage = new RawImage(img);
} }
if(rawImage && m_analyzeLevel >= Statistics) if(rawImage && m_analyzeLevel >= Statistics && !m_thumbnail)
{ {
double mean, median, min, max, mad; double mean, median, min, max, mad;
double stdDev; double stdDev;
@@ -440,7 +442,20 @@ void LoadRunable::run()
} }
} }
QMetaObject::invokeMethod(m_receiver, "imageLoaded", Qt::QueuedConnection, Q_ARG(void*, rawImage), Q_ARG(ImageInfoData, info)); if(m_thumbnail)
{
if(rawImage)
{
rawImage->convertToThumbnail();
QMetaObject::invokeMethod(m_receiver, "thumbnailLoadFinish", Qt::QueuedConnection, Q_ARG(void*, rawImage));
}
else
{
qDebug() << "failed";
}
}
else
QMetaObject::invokeMethod(m_receiver, "imageLoaded", Qt::QueuedConnection, Q_ARG(void*, rawImage), Q_ARG(ImageInfoData, info));
} }
bool readFITSHeader(const QString &path, ImageInfoData &info) bool readFITSHeader(const QString &path, ImageInfoData &info)
+2 -1
View File
@@ -15,8 +15,9 @@ class LoadRunable : public QRunnable
QString m_file; QString m_file;
Image *m_receiver; Image *m_receiver;
AnalyzeLevel m_analyzeLevel; AnalyzeLevel m_analyzeLevel;
bool m_thumbnail;
public: public:
LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level); LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail = false);
void run(); void run();
}; };
+1 -1
View File
@@ -6,7 +6,7 @@ int main(int argc, char *argv[])
{ {
QSurfaceFormat format; QSurfaceFormat format;
format.setMajorVersion(3); format.setMajorVersion(3);
format.setMinorVersion(2); format.setMinorVersion(3);
format.setOption(QSurfaceFormat::DebugContext); format.setOption(QSurfaceFormat::DebugContext);
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
QSurfaceFormat::setDefaultFormat(format); QSurfaceFormat::setDefaultFormat(format);
+9
View File
@@ -80,6 +80,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
connect(m_ringList, SIGNAL(currentImageChanged(int)), this, SLOT(updateWindowTitle())); connect(m_ringList, SIGNAL(currentImageChanged(int)), this, SLOT(updateWindowTitle()));
connect(m_ringList, SIGNAL(infoLoaded(ImageInfoData)), m_info, SLOT(setInfo(const ImageInfoData&))); connect(m_ringList, SIGNAL(infoLoaded(ImageInfoData)), m_info, SLOT(setInfo(const ImageInfoData&)));
connect(m_ringList, SIGNAL(currentImageChanged(int)), m_filesystem, SLOT(selectFile(int))); connect(m_ringList, SIGNAL(currentImageChanged(int)), m_filesystem, SLOT(selectFile(int)));
connect(m_ringList, &ImageRingList::thumbnailLoaded, m_imageGL->imageWidget(), &ImageWidget::thumbnailLoaded);
connect(m_imageGL->imageWidget(), &ImageWidget::fileDropped, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::loadFile)); connect(m_imageGL->imageWidget(), &ImageWidget::fileDropped, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::loadFile));
QMenu *fileMenu = new QMenu(tr("File"), this); QMenu *fileMenu = new QMenu(tr("File"), this);
@@ -98,6 +99,14 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
viewMenu->addAction(tr("Best Fit"), m_imageGL, SLOT(bestFit()), QKeySequence("Ctrl+1")); viewMenu->addAction(tr("Best Fit"), m_imageGL, SLOT(bestFit()), QKeySequence("Ctrl+1"));
viewMenu->addAction(tr("100%"), m_imageGL, SLOT(oneToOne())); viewMenu->addAction(tr("100%"), m_imageGL, SLOT(oneToOne()));
viewMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence::FullScreen); viewMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence::FullScreen);
QAction *thumbnailsAction = viewMenu->addAction(tr("Thumbnails"), [this](bool checked){
m_imageGL->imageWidget()->allocateThumbnails(m_ringList->imageCount());
m_imageGL->imageWidget()->showThumbnail(checked);
m_imageGL->setThumbnails(checked ? m_ringList->imageCount() : 0);
if(checked)m_ringList->loadThumbnails();
else m_ringList->stopLoading();
}, Qt::Key_F2);
thumbnailsAction->setCheckable(true);
menuBar()->addMenu(viewMenu); menuBar()->addMenu(viewMenu);
QMenu *selectMenu = new QMenu(tr("Select"), this); QMenu *selectMenu = new QMenu(tr("Select"), this);
+30 -1
View File
@@ -1,5 +1,4 @@
#include "rawimage.h" #include "rawimage.h"
#include <QDebug>
RawImage::ImgType CV2Type(int cvtype) RawImage::ImgType CV2Type(int cvtype)
{ {
@@ -259,3 +258,33 @@ const void *RawImage::data() const
{ {
return m_img.ptr(); return m_img.ptr();
} }
void RawImage::convertToThumbnail()
{
m_thumbAspect = (float)width() / height();
switch(CV_MAT_DEPTH(m_img.type()))
{
case CV_8U:
m_img.convertTo(m_img, CV_16U, 255);
break;
case CV_32F:
m_img.convertTo(m_img, CV_16U, 65535);
break;
case CV_16U:
break;
default:
break;
}
if(m_img.channels() == 1)
cv::cvtColor(m_img, m_img, cv::COLOR_GRAY2RGB);
if(m_img.channels() == 4)
cv::cvtColor(m_img, m_img, cv::COLOR_BGRA2RGB);
cv::Size dsize(THUMB_SIZE, THUMB_SIZE);
cv::resize(m_img, m_img, dsize, 0, 0, cv::INTER_NEAREST);
}
float RawImage::thumbAspect() const
{
return m_thumbAspect;
}
+6
View File
@@ -9,6 +9,9 @@
#include <opencv2/imgproc.hpp> #include <opencv2/imgproc.hpp>
#include <QImage> #include <QImage>
const int THUMB_SIZE = 128;
const int THUMB_SIZE_BORDER = 138;
class Peak class Peak
{ {
uint32_t m_v; uint32_t m_v;
@@ -42,6 +45,7 @@ protected:
double m_min; double m_min;
double m_max; double m_max;
double m_mad; double m_mad;
float m_thumbAspect;
public: public:
enum ImgType enum ImgType
{ {
@@ -72,6 +76,8 @@ public:
uint32_t norm() const; uint32_t norm() const;
void* data(); void* data();
const void* data() const; const void* data() const;
void convertToThumbnail();
float thumbAspect() const;
}; };
#endif // RAWIMAGE_H #endif // RAWIMAGE_H
+2
View File
@@ -2,6 +2,8 @@
<qresource prefix="/shaders"> <qresource prefix="/shaders">
<file>image.frag</file> <file>image.frag</file>
<file>image.vert</file> <file>image.vert</file>
<file>thumb.frag</file>
<file>thumb.vert</file>
</qresource> </qresource>
<qresource prefix="/"> <qresource prefix="/">
<file>icon.png</file> <file>icon.png</file>
+25
View File
@@ -0,0 +1,25 @@
#version 130
uniform sampler2DArray qt_Texture0;
uniform vec3 mtf_param;
uniform bool invert;
in vec3 qt_TexCoord0;
out vec4 color;
vec4 MTF(vec4 x, vec3 m)
{
x = (x - m.x) / (m.z - m.x);
x = clamp(x, vec4(0.0), vec4(1.0));
return ((m.y - 1) * x) / ((2 * m.y - 1) * x - m.y);
}
void main(void)
{
color = texture(qt_Texture0, qt_TexCoord0);
color = MTF(color, mtf_param);
if(invert)color = vec4(1.0) - color;
//color = vec4(qt_TexCoord0, 0.0, 0.0);
//color = vec4(mod(qt_TexCoord0.st, vec2(1.0)), 0, 1.0);
}
+20
View File
@@ -0,0 +1,20 @@
#version 130
in vec2 qt_Vertex;
in vec2 qt_MultiTexCoord0;
in ivec3 imageSize_num;
out vec3 qt_TexCoord0;
uniform ivec3 viewport_row;
uniform mat4 mvp;
uniform vec2 offset;
void main(void)
{
vec2 pos = qt_Vertex * 0.5;
pos.y *= -1.0;
pos = pos * imageSize_num.xy + 69;
ivec2 off = ivec2(imageSize_num.z % viewport_row.z, imageSize_num.z / viewport_row.z) * 138;
gl_Position = mvp * vec4(pos - offset + off, 0.0, 1.0);
qt_TexCoord0 = vec3(qt_MultiTexCoord0, imageSize_num.z + 0.1);
}