Compare commits
2 Commits
511802bdbd
...
bc29dc7d34
Author | SHA1 | Date | |
---|---|---|---|
bc29dc7d34 | |||
ff5053b626 |
@ -84,7 +84,7 @@ if(UNIX AND NOT APPLE)
|
||||
target_include_directories(tenmon PRIVATE ${GIO_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(tenmon PRIVATE Qt6::Widgets Qt6::Sql Qt6::OpenGLWidgets Qt6::Qml ${GSL_LIB} ${GSLCBLAS_LIB} ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB} ${WCS_LIB} XISF)
|
||||
target_link_libraries(tenmon PRIVATE Qt6::Widgets Qt6::Sql Qt6::OpenGLWidgets Qt6::Qml ${GSL_LIB} ${GSLCBLAS_LIB} ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB} ${WCS_LIB} XISF lcms2)
|
||||
if(APPLE)
|
||||
target_link_libraries(tenmon PRIVATE Qt6::DBus "-framework CoreFoundation")
|
||||
elseif(UNIX)
|
||||
|
@ -14,9 +14,12 @@
|
||||
#include <QFileInfo>
|
||||
#include <cmath>
|
||||
#include <QElapsedTimer>
|
||||
#include <QFloat16>
|
||||
#include <lcms2.h>
|
||||
|
||||
int FILTERING = 1;
|
||||
bool OpenGLES = false;
|
||||
const int LUT_SIZE = 32;
|
||||
|
||||
struct RawImageType
|
||||
{
|
||||
@ -32,7 +35,7 @@ RawImageType getRawImageType(const RawImage *img)
|
||||
{
|
||||
case RawImage::UINT8:
|
||||
if(img->channels() >= 3)
|
||||
type.textureFormat = QOpenGLTexture::SRGB8_Alpha8;
|
||||
type.textureFormat = QOpenGLTexture::RGBA8_UNorm;
|
||||
else
|
||||
type.textureFormat = QOpenGLTexture::R8_UNorm;
|
||||
type.dataType = QOpenGLTexture::UInt8;
|
||||
@ -123,9 +126,14 @@ void ImageWidget::setImage(std::shared_ptr<RawImage> image, int index)
|
||||
if(!m_image)return;
|
||||
|
||||
RawImageType rawImageType = getRawImageType(image.get());
|
||||
m_srgb = rawImageType.textureFormat == QOpenGLTexture::SRGB8_Alpha8;
|
||||
m_srgb = image->getLUT().size() > 0;
|
||||
m_bwImg = image->channels() == 1;
|
||||
|
||||
if(m_srgb)
|
||||
{
|
||||
m_lut->setData(0, 0, 0, LUT_SIZE, LUT_SIZE, LUT_SIZE, 0, QOpenGLTexture::RGBA, QOpenGLTexture::RGBA, QOpenGLTexture::Float16, image->getLUT().data());
|
||||
}
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
m_image->destroy();
|
||||
@ -216,6 +224,7 @@ void ImageWidget::allocateThumbnails(const QStringList &paths)
|
||||
m_thumbnailTexture->setFormat(QOpenGLTexture::RGBA16F);
|
||||
m_thumbnailTexture->setSize(THUMB_SIZE, THUMB_SIZE);
|
||||
m_thumbnailTexture->setLayers(std::min((int)paths.size(), m_maxArrayLayers));
|
||||
m_thumbnailTexture->setWrapMode(QOpenGLTexture::ClampToEdge);
|
||||
m_thumbnailTexture->allocateStorage();
|
||||
}
|
||||
|
||||
@ -364,14 +373,16 @@ void ImageWidget::paintGL()
|
||||
QMatrix4x4 mvp;
|
||||
mvp.ortho(rect());
|
||||
m_thumbnailProgram->setUniformValue("mvp", mvp);
|
||||
fx->glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, m_thumbnailCount);
|
||||
m_vaoThumb->release();
|
||||
|
||||
QPainter painter(this);
|
||||
const int w = width()/THUMB_SIZE_BORDER;
|
||||
const int off = (THUMB_SIZE_BORDER - THUMB_SIZE) / 2;
|
||||
int start = std::max((int)(m_dy / THUMB_SIZE_BORDER_Y * w - w), 0);
|
||||
int end = std::min((int)(m_dy + m_height) / THUMB_SIZE_BORDER_Y * w + w, m_thumbnailCount);
|
||||
|
||||
fx->glDrawArraysInstanced(GL_TRIANGLE_STRIP, start*4, 4, (end - start) * 4);
|
||||
m_vaoThumb->release();
|
||||
|
||||
QPainter painter(this);
|
||||
for(int i=start; i < end; i++)
|
||||
{
|
||||
float x = (i % w) * THUMB_SIZE_BORDER;
|
||||
@ -424,9 +435,8 @@ void ImageWidget::paintGL()
|
||||
m_program->setUniformValue("false_color", m_falseColor && m_bwImg);
|
||||
m_program->setUniformValue("invert", m_invert);
|
||||
m_program->setUniformValue("filtering", m_scale > 1.0f ? FILTERING : 1);
|
||||
#ifdef COLOR_MANAGMENT
|
||||
m_program->setUniformValue("lut_table", 2);
|
||||
m_program->setUniformValue("srgb", m_srgb);
|
||||
#endif
|
||||
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
m_vao->release();
|
||||
}
|
||||
@ -462,7 +472,9 @@ void ImageWidget::initializeGL()
|
||||
{
|
||||
src = "#version 300 es\n"
|
||||
"precision highp float;\n"
|
||||
"precision highp sampler2D;\n"
|
||||
"precision highp sampler2DArray;\n"
|
||||
"precision highp sampler3D;\n"
|
||||
"#line 1\n";
|
||||
}
|
||||
else
|
||||
@ -525,6 +537,7 @@ void ImageWidget::initializeGL()
|
||||
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("lut_table", (GLuint)2);
|
||||
m_program->setUniformValue("scale", 1.0f, 0.0f);
|
||||
|
||||
m_debayerProgram = std::unique_ptr<QOpenGLShaderProgram>(new QOpenGLShaderProgram);
|
||||
@ -588,6 +601,14 @@ void ImageWidget::initializeGL()
|
||||
m_transferOptions = std::unique_ptr<QOpenGLPixelTransferOptions>(new QOpenGLPixelTransferOptions);
|
||||
m_transferOptions->setAlignment(1);
|
||||
|
||||
m_lut = std::make_unique<QOpenGLTexture>(QOpenGLTexture::Target3D);
|
||||
m_lut->setSize(LUT_SIZE, LUT_SIZE, LUT_SIZE);
|
||||
m_lut->setMipLevelRange(0, 0);
|
||||
m_lut->setFormat(QOpenGLTexture::TextureFormat::RGBA16F);
|
||||
m_lut->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
|
||||
m_lut->allocateStorage();
|
||||
m_lut->bind(2);
|
||||
|
||||
if(m_rawImage)
|
||||
setImage(m_rawImage, m_currentImg);
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ class ImageWidget : public QOpenGLWidget
|
||||
std::unique_ptr<QOpenGLVertexArrayObject> m_vaoThumb;
|
||||
std::unique_ptr<QOpenGLPixelTransferOptions> m_transferOptions;
|
||||
std::unique_ptr<QOpenGLTexture> m_thumbnailTexture;
|
||||
std::unique_ptr<QOpenGLTexture> m_lut;
|
||||
GLuint m_debayerTex = 0;
|
||||
std::shared_ptr<RawImage> m_rawImage;
|
||||
std::shared_ptr<WCSData> m_wcs;
|
||||
|
@ -13,10 +13,7 @@
|
||||
#include <libxisf.h>
|
||||
#include "rawimage.h"
|
||||
#include "starfit.h"
|
||||
|
||||
#ifdef COLOR_MANAGMENT
|
||||
#include <QColorSpace>
|
||||
#endif
|
||||
#include <lcms2.h>
|
||||
|
||||
LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail) :
|
||||
m_file(file),
|
||||
@ -339,11 +336,13 @@ bool loadXISF(const QString &path, ImageInfoData &info, std::shared_ptr<RawImage
|
||||
{
|
||||
image = std::make_shared<RawImage>(tmpImage.width(), tmpImage.height(), 1, type);
|
||||
std::memcpy(image->data(), tmpImage.imageData(), tmpImage.imageDataSize() / tmpImage.channelCount());
|
||||
image->setICCProfile(tmpImage.iccProfile());
|
||||
return true;
|
||||
}
|
||||
else if(tmpImage.channelCount() == 3 || tmpImage.channelCount() == 4)
|
||||
{
|
||||
image = RawImage::fromPlanar(tmpImage.imageData(), tmpImage.width(), tmpImage.height(), tmpImage.channelCount(), type);
|
||||
image->setICCProfile(tmpImage.iccProfile());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -380,6 +379,10 @@ void LoadRunable::run()
|
||||
{
|
||||
rawImage->convertToGLFormat();
|
||||
timer.start();
|
||||
rawImage->generateLUT();
|
||||
qDebug() << "generate LUT" << timer.restart();
|
||||
//rawImage->convertTosRGB();
|
||||
//qDebug() << "convert" << timer.restart();
|
||||
rawImage->calcStats();
|
||||
const RawImage::Stats &stats = rawImage->imageStats();
|
||||
qDebug() << "image stats" << timer.restart();
|
||||
@ -426,7 +429,12 @@ void LoadRunable::run()
|
||||
}
|
||||
catch(std::exception e)
|
||||
{
|
||||
qDebug() << m_file << e.what();
|
||||
qDebug() << m_file << e.what();
|
||||
std::shared_ptr<RawImage> rawImage;
|
||||
if(m_thumbnail)
|
||||
QMetaObject::invokeMethod(m_receiver, "thumbnailLoadFinish", Qt::QueuedConnection, Q_ARG(std::shared_ptr<RawImage>, rawImage));
|
||||
else
|
||||
QMetaObject::invokeMethod(m_receiver, "imageLoaded", Qt::QueuedConnection, Q_ARG(std::shared_ptr<RawImage>, rawImage), Q_ARG(ImageInfoData, ImageInfoData()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -497,10 +505,6 @@ bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImag
|
||||
else
|
||||
{
|
||||
QImage img(path);
|
||||
#ifdef COLOR_MANAGMENT
|
||||
if(img.colorSpace().isValid() && img.colorSpace() != QColorSpace::SRgb)
|
||||
img.convertToColorSpace(QColorSpace::SRgb);
|
||||
#endif
|
||||
|
||||
ExifData *exif = exif_data_new_from_file(path.toLocal8Bit().constData());
|
||||
info.info.append({QObject::tr("Width"), QString::number(img.width())});
|
||||
|
6
main.cpp
6
main.cpp
@ -4,12 +4,6 @@
|
||||
#include <QTranslator>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*float h2f(unsigned short h)
|
||||
{
|
||||
unsigned int
|
||||
return f;
|
||||
}*/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef __linux__
|
||||
|
125
rawimage.cpp
125
rawimage.cpp
@ -3,6 +3,7 @@
|
||||
#include <cstring>
|
||||
#include <QElapsedTimer>
|
||||
#include <QFloat16>
|
||||
#include <lcms2.h>
|
||||
|
||||
using F16 = qfloat16;
|
||||
|
||||
@ -79,6 +80,7 @@ RawImage::RawImage(RawImage &&d)
|
||||
RawImage::RawImage(const QImage &img)
|
||||
{
|
||||
qDebug() << img;
|
||||
setICCProfile(img.colorSpace().iccProfile());
|
||||
if(img.format() == QImage::Format_RGBX8888)
|
||||
{
|
||||
allocate(img.width(), img.height(), 3, UINT8);
|
||||
@ -755,6 +757,9 @@ std::shared_ptr<RawImage> RawImage::fromPlanar(const void *pixels, uint32_t w, u
|
||||
convert(static_cast<const uint16_t*>(pixels), static_cast<uint16_t*>(image->data()), UINT16_MAX);
|
||||
#endif
|
||||
break;
|
||||
case FLOAT16:
|
||||
convert(static_cast<const F16*>(pixels), static_cast<F16*>(image->data()), (F16)1.0f);
|
||||
break;
|
||||
case UINT32:
|
||||
#ifdef __SSE2__
|
||||
if(ch==3)
|
||||
@ -804,6 +809,7 @@ std::vector<RawImage> RawImage::split() const
|
||||
case UINT8:
|
||||
extract(static_cast<const uint8_t*>(data()), static_cast<uint8_t*>(planes[i].data()), i);
|
||||
break;
|
||||
case FLOAT16:
|
||||
case UINT16:
|
||||
extract(static_cast<const uint16_t*>(data()), static_cast<uint16_t*>(planes[i].data()), i);
|
||||
break;
|
||||
@ -824,3 +830,122 @@ bool RawImage::valid() const
|
||||
{
|
||||
return m_width > 0 && m_height > 0;
|
||||
}
|
||||
|
||||
void RawImage::setICCProfile(const QByteArray &icc)
|
||||
{
|
||||
if(icc.size())
|
||||
m_iccProfile = std::vector<uint8_t>(icc.begin(), icc.end());
|
||||
}
|
||||
|
||||
void RawImage::setICCProfile(const LibXISF::ByteArray &icc)
|
||||
{
|
||||
if(icc.size())
|
||||
m_iccProfile = std::vector<uint8_t>(icc.data(), icc.data() + icc.size());
|
||||
}
|
||||
|
||||
void RawImage::convertTosRGB()
|
||||
{
|
||||
if(m_channels == 1 || m_iccProfile.empty())
|
||||
return;
|
||||
|
||||
cmsUInt32Number type = TYPE_RGBA_8;
|
||||
switch(m_type)
|
||||
{
|
||||
case UINT8:
|
||||
type = TYPE_RGBA_8;
|
||||
break;
|
||||
case UINT16:
|
||||
type = TYPE_RGBA_16;
|
||||
break;
|
||||
case FLOAT16:
|
||||
type = TYPE_RGBA_HALF_FLT;
|
||||
break;
|
||||
case FLOAT32:
|
||||
type = TYPE_RGBA_FLT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
cmsHPROFILE inProfile = cmsOpenProfileFromMem(m_iccProfile.data(), m_iccProfile.size());
|
||||
cmsHPROFILE outProfile = cmsCreate_sRGBProfile();
|
||||
if(inProfile && outProfile)
|
||||
{
|
||||
cmsHTRANSFORM transform = cmsCreateTransform(inProfile, type, outProfile, type, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
|
||||
|
||||
std::unique_ptr<PixelType[]> tmp = std::move(m_pixels);
|
||||
allocate(m_width, m_height, m_channels, m_type);
|
||||
if(transform)
|
||||
{
|
||||
cmsDoTransform(transform, tmp.get(), m_pixels.get(), size());
|
||||
cmsDeleteTransform(transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Failed to create color transform";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Failed to open icc profile";
|
||||
}
|
||||
|
||||
cmsCloseProfile(inProfile);
|
||||
cmsCloseProfile(outProfile);
|
||||
}
|
||||
|
||||
void RawImage::generateLUT()
|
||||
{
|
||||
if(m_channels == 1 || m_iccProfile.empty())
|
||||
return;
|
||||
|
||||
const int LUT_SIZE = 32;
|
||||
const float LUT_SIZEF = LUT_SIZE - 1;
|
||||
std::vector<qfloat16> lut(LUT_SIZE * LUT_SIZE * LUT_SIZE * 4);
|
||||
m_lut.resize(lut.size());
|
||||
for(int z = 0; z < LUT_SIZE; z++)
|
||||
{
|
||||
for(int y = 0; y < LUT_SIZE; y++)
|
||||
{
|
||||
qfloat16 *line = &lut[(z*LUT_SIZE*LUT_SIZE + y*LUT_SIZE) * 4];
|
||||
for(int x = 0; x < LUT_SIZE; x++)
|
||||
{
|
||||
line[x*4 + 0] = x / LUT_SIZEF;
|
||||
line[x*4 + 1] = y / LUT_SIZEF;
|
||||
line[x*4 + 2] = z / LUT_SIZEF;
|
||||
line[x*4 + 3] = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmsHPROFILE inProfile = cmsOpenProfileFromMem(m_iccProfile.data(), m_iccProfile.size());
|
||||
cmsHPROFILE outProfile = cmsCreate_sRGBProfile();
|
||||
if(inProfile && outProfile)
|
||||
{
|
||||
cmsHTRANSFORM transform = cmsCreateTransform(inProfile, TYPE_RGBA_HALF_FLT, outProfile, TYPE_RGBA_HALF_FLT, INTENT_PERCEPTUAL, cmsFLAGS_COPY_ALPHA);
|
||||
|
||||
if(transform)
|
||||
{
|
||||
cmsDoTransform(transform, &lut[0], &m_lut[0], lut.size()/4);
|
||||
cmsDeleteTransform(transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Failed to create color transform";
|
||||
m_lut.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Failed to open icc profile";
|
||||
m_lut.clear();
|
||||
}
|
||||
|
||||
cmsCloseProfile(inProfile);
|
||||
cmsCloseProfile(outProfile);
|
||||
}
|
||||
|
||||
const std::vector<uint16_t> &RawImage::getLUT() const
|
||||
{
|
||||
return m_lut;
|
||||
}
|
||||
|
11
rawimage.h
11
rawimage.h
@ -1,13 +1,14 @@
|
||||
#ifndef RAWIMAGE_H
|
||||
#define RAWIMAGE_H
|
||||
|
||||
#include "libxisf.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <QImage>
|
||||
#include <QColorSpace>
|
||||
|
||||
extern int THUMB_SIZE;
|
||||
extern int THUMB_SIZE_BORDER;
|
||||
@ -73,6 +74,8 @@ protected:
|
||||
float m_thumbAspect = 0.0;
|
||||
Stats m_stats;
|
||||
bool m_planar = false;
|
||||
std::vector<uint8_t> m_iccProfile;
|
||||
std::vector<uint16_t> m_lut;// actually qfloat16
|
||||
void allocate(uint32_t w, uint32_t h, uint32_t ch, DataType type);
|
||||
public:
|
||||
RawImage();
|
||||
@ -112,6 +115,12 @@ public:
|
||||
static size_t typeSize(DataType type);
|
||||
std::vector<RawImage> split() const;
|
||||
bool valid() const;
|
||||
void setICCProfile(const QByteArray &icc);
|
||||
void setICCProfile(const LibXISF::ByteArray &icc);
|
||||
void convertTosRGB();
|
||||
void generateLUT();
|
||||
const std::vector<uint16_t>& getLUT() const;
|
||||
|
||||
};
|
||||
|
||||
//Q_DECLARE_SMART_POINTER_METATYPE(std::shared_ptr);
|
||||
|
@ -1,4 +1,5 @@
|
||||
uniform sampler2D qt_Texture0;
|
||||
uniform sampler3D lut_table;
|
||||
uniform vec3 mtf_param[3];
|
||||
uniform vec2 unit_scale;
|
||||
uniform bool bw;
|
||||
@ -151,7 +152,14 @@ void main(void)
|
||||
|
||||
color.rgb = mix(checker(), color.rgb, color.a);
|
||||
|
||||
if(srgb)color.rgb = Linear2sRGB(color.rgb);
|
||||
if(srgb)
|
||||
{
|
||||
color.rgb *= 31.0 / 32.0;
|
||||
color.rgb += 0.5 / 32.0;
|
||||
vec4 lut = texture(lut_table, vec3(color.rgb));
|
||||
color.rgb = lut.rgb;
|
||||
//color.rgb = Linear2sRGB(lut.rgb);
|
||||
}
|
||||
|
||||
if(any(lessThan(qt_TexCoord0, vec2(0.0))) || any(greaterThan(qt_TexCoord0, vec2(1.0))))
|
||||
color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user