Reworked RawImage class to use OpenCV

This commit is contained in:
2020-05-10 17:02:16 +02:00
parent fcc1696c2c
commit 1e45a78b39
9 changed files with 265 additions and 227 deletions
+3 -3
View File
@@ -47,7 +47,7 @@ QPixmap Image::pixmap() const
return m_pixmap; return m_pixmap;
} }
RawImageAbs *Image::rawImage() RawImage *Image::rawImage()
{ {
return m_rawImage.get(); return m_rawImage.get();
} }
@@ -68,13 +68,13 @@ void Image::imageLoaded(QImage img, void *rawImage, ImageInfoData info)
if(!m_released) if(!m_released)
{ {
m_pixmap = QPixmap::fromImage(img); m_pixmap = QPixmap::fromImage(img);
m_rawImage.reset(static_cast<RawImageAbs*>(rawImage)); m_rawImage.reset(static_cast<RawImage*>(rawImage));
m_info = info; m_info = info;
emit pixmapLoaded(this); emit pixmapLoaded(this);
} }
else else
{ {
delete static_cast<RawImageAbs*>(rawImage); delete static_cast<RawImage*>(rawImage);
} }
} }
+2 -2
View File
@@ -18,7 +18,7 @@ class Image : public QObject
bool m_released; bool m_released;
bool m_current; bool m_current;
QPixmap m_pixmap; QPixmap m_pixmap;
std::unique_ptr<RawImageAbs> m_rawImage; std::unique_ptr<RawImage> m_rawImage;
QString m_name; QString m_name;
ImageInfoData m_info; ImageInfoData m_info;
ImageRingList *m_ringList; ImageRingList *m_ringList;
@@ -28,7 +28,7 @@ public:
void release(); void release();
QString name() const; QString name() const;
QPixmap pixmap() const; QPixmap pixmap() const;
RawImageAbs* rawImage(); RawImage* rawImage();
ImageInfoData info() const; ImageInfoData info() const;
bool isCurrent() const; bool isCurrent() const;
signals: signals:
+25 -12
View File
@@ -3,6 +3,7 @@
#include <QDebug> #include <QDebug>
#include <QKeyEvent> #include <QKeyEvent>
#include <QOpenGLDebugLogger> #include <QOpenGLDebugLogger>
#include <QOpenGLPixelTransferOptions>
ImageScrollAreaGL::ImageScrollAreaGL(QWidget *parent) : QOpenGLWidget(parent) ImageScrollAreaGL::ImageScrollAreaGL(QWidget *parent) : QOpenGLWidget(parent)
{ {
@@ -17,32 +18,41 @@ ImageScrollAreaGL::~ImageScrollAreaGL()
makeCurrent(); makeCurrent();
} }
void ImageScrollAreaGL::setImage(RawImageAbs *image) void ImageScrollAreaGL::setImage(RawImage *image)
{ {
if(image == nullptr)return;
m_image->destroy(); m_image->destroy();
m_image->setFormat(QOpenGLTexture::R16_UNorm); m_image->setFormat(QOpenGLTexture::R16_UNorm);
m_image->setSize(image->width(), image->height()); m_image->setSize(image->width(), image->height());
m_image->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear); m_image->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
m_image->allocateStorage(); m_image->allocateStorage();
if(RawImage<uint8_t> *i8 = dynamic_cast<RawImage<uint8_t>*>(image)) switch(image->type())
{ {
m_image->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, i8->data()); case RawImage::UINT8:
m_image->setData(0, QOpenGLTexture::Red, QOpenGLTexture::UInt8, image->data(), m_transferOptions.get());
m_range = UINT8_MAX; m_range = UINT8_MAX;
} break;
else if(RawImage<uint16_t> *i16 = dynamic_cast<RawImage<uint16_t>*>(image)) case RawImage::UINT16:
{ m_image->setData(0, QOpenGLTexture::Red, QOpenGLTexture::UInt16, image->data(), m_transferOptions.get());
m_image->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt16, i16->data());
m_range = UINT16_MAX; m_range = UINT16_MAX;
} break;
else if(RawImage<uint32_t> *i32 = dynamic_cast<RawImage<uint32_t>*>(image)) case RawImage::FLOAT32:
{ break;
m_image->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt32, i32->data());
m_range = UINT32_MAX;
} }
m_image->generateMipMaps(); m_image->generateMipMaps();
repaint(); repaint();
} }
void ImageScrollAreaGL::setImage(const QPixmap &pixmap)
{
QImage img = pixmap.toImage();
m_image->destroy();
m_image->setData(img);
repaint();
}
void ImageScrollAreaGL::setLow(int low) void ImageScrollAreaGL::setLow(int low)
{ {
m_low = low/m_range; m_low = low/m_range;
@@ -127,4 +137,7 @@ void ImageScrollAreaGL::initializeGL()
m_image->bind(0); m_image->bind(0);
m_image->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_image->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
m_image->setMagnificationFilter(QOpenGLTexture::Linear); m_image->setMagnificationFilter(QOpenGLTexture::Linear);
m_transferOptions = std::unique_ptr<QOpenGLPixelTransferOptions>(new QOpenGLPixelTransferOptions);
m_transferOptions->setAlignment(1);
} }
+3 -1
View File
@@ -28,6 +28,7 @@ class ImageScrollAreaGL : public QOpenGLWidget
std::unique_ptr<QOpenGLBuffer> m_buffer; std::unique_ptr<QOpenGLBuffer> m_buffer;
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<QOpenGLPixelTransferOptions> m_transferOptions;
int m_width, m_height; int m_width, m_height;
float m_low; float m_low;
float m_high; float m_high;
@@ -35,7 +36,8 @@ class ImageScrollAreaGL : public QOpenGLWidget
public: public:
explicit ImageScrollAreaGL(QWidget *parent = nullptr); explicit ImageScrollAreaGL(QWidget *parent = nullptr);
~ImageScrollAreaGL(); ~ImageScrollAreaGL();
void setImage(RawImageAbs *image); void setImage(RawImage *image);
void setImage(const QPixmap &pixmap);
public slots: public slots:
void setLow(int low); void setLow(int low);
void setHigh(int high); void setHigh(int high);
+24 -11
View File
@@ -75,7 +75,7 @@ void printStarModel(int radius, const std::vector<double> &data, const Star &sta
std::cout << m.toStdString() << std::endl << std::endl; std::cout << m.toStdString() << std::endl << std::endl;
} }
bool loadRAW(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qimage) bool loadRAW(QString path, ImageInfoData &info, RawImage **image, QImage *qimage)
{ {
if(!image && !qimage) if(!image && !qimage)
return false; return false;
@@ -108,7 +108,8 @@ bool loadRAW(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qi
out[d++] = p; out[d++] = p;
} }
} }
*image = new RawImage<uint16_t>(rawdata.sizes.width, rawdata.sizes.height, out); *image = new RawImage(rawdata.sizes.width, rawdata.sizes.height, RawImage::UINT16);
memcpy((*image)->data(), &out[0], sizeof(uint16_t)*w*h);
} }
if(qimage) if(qimage)
@@ -143,7 +144,7 @@ bool loadRAW(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qi
return true; return true;
} }
bool loadFITS(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qimage) bool loadFITS(QString path, ImageInfoData &info, RawImage **image, QImage *qimage)
{ {
if(!image && !qimage) if(!image && !qimage)
return false; return false;
@@ -188,7 +189,11 @@ bool loadFITS(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qi
for(size_t i=0; i<h; i++) for(size_t i=0; i<h; i++)
memcpy(qimage->scanLine(i), &bits8[i*w], w*sizeof(uint8_t)); memcpy(qimage->scanLine(i), &bits8[i*w], w*sizeof(uint8_t));
} }
if(image)*image = new RawImage<uint8_t>(naxes[0], naxes[1], bits8); if(image)
{
*image = new RawImage(naxes[0], naxes[1], RawImage::UINT8);
memcpy((*image)->data(), &bits8[0], sizeof(uint8_t)*h*w);
}
break; break;
case SHORT_IMG: case SHORT_IMG:
bits16.resize(size); bits16.resize(size);
@@ -203,10 +208,14 @@ bool loadFITS(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qi
scanline[o] = bits16[i*w+o] >> 8; scanline[o] = bits16[i*w+o] >> 8;
} }
} }
if(image)*image = new RawImage<uint16_t>(naxes[0], naxes[1], bits16); if(image)
{
*image = new RawImage(naxes[0], naxes[1], RawImage::UINT16);
memcpy((*image)->data(), &bits16[0], sizeof(uint16_t)*h*w);
}
break; break;
case LONG_IMG: case LONG_IMG:
bits32.resize(size); /*bits32.resize(size);
fits_read_pix(file, TUINT, fpixel, size, NULL, &bits32[0], NULL, &status); fits_read_pix(file, TUINT, fpixel, size, NULL, &bits32[0], NULL, &status);
if(status)break; if(status)break;
if(qimage) if(qimage)
@@ -218,7 +227,11 @@ bool loadFITS(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qi
scanline[o] = bits32[i*w+o] >> 24; scanline[o] = bits32[i*w+o] >> 24;
} }
} }
if(image)*image = new RawImage<uint32_t>(naxes[0], naxes[1], bits32); if(image)
{
*image = new RawImage(naxes[0], naxes[1], RawImage::FLOAT32);
memcpy((*image)->data(), &bits8[0], sizeof(uint32_t)*h*w);
}*/
break; break;
} }
} }
@@ -259,7 +272,7 @@ void LoadRunable::run()
info.append(StringPair(QObject::tr("Filename"), finfo.fileName())); info.append(StringPair(QObject::tr("Filename"), finfo.fileName()));
QImage img; QImage img;
RawImageAbs *rawImage = nullptr; RawImage *rawImage = nullptr;
bool raw = false; bool raw = false;
if(m_file.endsWith(".CR2", Qt::CaseInsensitive)) if(m_file.endsWith(".CR2", Qt::CaseInsensitive))
{ {
@@ -288,7 +301,7 @@ void LoadRunable::run()
if(rawImage && m_analyzeLevel >= Statistics) if(rawImage && m_analyzeLevel >= Statistics)
{ {
uint64_t mean, median, min, max; double mean, median, min, max;
double stdDev; double stdDev;
timer.start(); timer.start();
rawImage->imageStats(&mean, &stdDev, &median, &min, &max); rawImage->imageStats(&mean, &stdDev, &median, &min, &max);
@@ -306,9 +319,9 @@ void LoadRunable::run()
rawImage->quarter(); rawImage->quarter();
qDebug() << "quarter" << timer.restart(); qDebug() << "quarter" << timer.restart();
} }
RawImageAbs *medianImage = rawImage->medianFilter(); RawImage *medianImage = rawImage->medianFilter();
qDebug() << "median" << timer.restart(); qDebug() << "median" << timer.restart();
int numPeaks = medianImage->findPeaks(median+stdDev, 20, peaks); int numPeaks = medianImage->findPeaks(median+stdDev*2, 20, peaks);
delete medianImage; delete medianImage;
qDebug() << "peaks" << timer.restart(); qDebug() << "peaks" << timer.restart();
if(m_analyzeLevel == Peaks) if(m_analyzeLevel == Peaks)
+9 -2
View File
@@ -27,7 +27,7 @@ int MainWindow::socketPair[2] = {0, 0};
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{ {
qRegisterMetaType<ImageInfoData>("ImageInfoData"); qRegisterMetaType<ImageInfoData>("ImageInfoData");
qRegisterMetaType<RawImageAbs*>("RawImageAbs"); qRegisterMetaType<RawImage*>("RawImage");
m_info = new ImageInfo(this); m_info = new ImageInfo(this);
QDockWidget *infoDock = new QDockWidget(tr("Image info"), this); QDockWidget *infoDock = new QDockWidget(tr("Image info"), this);
@@ -206,7 +206,14 @@ void MainWindow::socketNotify()
void MainWindow::pixmapLoaded(Image *image) void MainWindow::pixmapLoaded(Image *image)
{ {
m_image->setImage(image->pixmap()); m_image->setImage(image->pixmap());
m_imageGL->setImage(image->rawImage()); if(image->rawImage())
{
m_imageGL->setImage(image->rawImage());
}
else
{
m_imageGL->setImage(image->pixmap());
}
} }
void MainWindow::openFile() void MainWindow::openFile()
+171
View File
@@ -0,0 +1,171 @@
#include "rawimage.h"
#include <QDebug>
#include <opencv2/highgui.hpp>
RawImage::ImgType CV2Type(int cvtype)
{
switch (cvtype)
{
case CV_8U:
return RawImage::UINT8;
case CV_16U:
return RawImage::UINT16;
case CV_32F:
return RawImage::FLOAT32;
default:
return RawImage::UNKNOWN;
}
}
int Type2CV(RawImage::ImgType type)
{
switch (type)
{
case RawImage::UINT8:
return CV_8U;
case RawImage::UINT16:
return CV_16U;
case RawImage::FLOAT32:
return CV_32F;
case RawImage::UNKNOWN:
return CV_8S;
}
}
RawImage::RawImage()
{
}
RawImage::RawImage(int w, int h, ImgType type)
{
m_img.create(h, w, Type2CV(type));
}
RawImage::RawImage(const RawImage &d)
{
d.m_img.copyTo(m_img);
}
bool RawImage::imageStats(double *mean, double *stdDev, double *median, double *min, double *max) const
{
cv::Scalar meanS, stdDevS;
qDebug() << m_img.type();
cv::meanStdDev(m_img, meanS, stdDevS);
if(min && max)cv::minMaxIdx(m_img, min, max);
int histSize = 256;
if(m_img.type() == CV_16U || m_img.type() == CV_32F)histSize = 65536;
float range[] = {0, (float)histSize};
const float *ranges[] = {range};
cv::Mat hist;
cv::calcHist(&m_img, 1, nullptr, cv::Mat(), hist, 1, &histSize, ranges);
if(mean)*mean = meanS[0];
if(stdDev)*stdDev = stdDevS[0];
size_t halfImageSize = size()/2;
if(median)
{
size_t medianSum = 0;
for(int i=0; i < histSize; i++)
{
medianSum += hist.at<float>(0, i);
if(medianSum >= halfImageSize)
{
*median = i;
break;
}
}
}
return true;
}
void RawImage::rect(int &x, int &y, int w, int h, std::vector<double> &r) const
{
r.resize(w*h);
x -= w/2;
y -= h/2;
if(x<0)x = 0;
if(y<0)y = 0;
if(x+w >= m_img.cols)x = m_img.cols-w;
if(y+h >= m_img.rows)y = m_img.rows-h;
cv::Mat roiImg(m_img, cv::Rect(x, y, w, h));
cv::Mat doubleMat;
roiImg.convertTo(doubleMat, CV_64F);
r = std::vector<double>(doubleMat.begin<double>(), doubleMat.end<double>());
}
int RawImage::findPeaks(double background, double distance, std::vector<Peak> &peaks) const
{
std::vector<std::vector<cv::Point>> contours;
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(distance, distance));
cv::Mat mask, dilate, locMax, result;
cv::dilate(m_img, dilate, kernel);
cv::compare(m_img, dilate, locMax, cv::CMP_GE);
cv::compare(m_img, cv::Scalar(background), mask, cv::CMP_GT);
cv::bitwise_and(locMax, mask, result);
cv::findContours(result, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
peaks.reserve(contours.size());
for(auto contour : contours)
{
peaks.push_back(Peak(1, contour[0].x, contour[0].y));
}
return peaks.size();
}
RawImage* RawImage::medianFilter() const
{
RawImage *ret = new RawImage();
cv::medianBlur(m_img, ret->m_img, 3);
return ret;
}
void RawImage::quarter()
{
}
uint32_t RawImage::width() const
{
return m_img.cols;
}
uint32_t RawImage::height() const
{
return m_img.rows;
}
uint32_t RawImage::size() const
{
return width()*height();
}
RawImage::ImgType RawImage::type() const
{
switch(m_img.type())
{
case CV_8U:
return UINT8;
case CV_16U:
return UINT16;
case CV_32F:
return FLOAT32;
default:
return UNKNOWN;
}
}
void* RawImage::data()
{
return m_img.ptr();
}
const void *RawImage::data() const
{
return m_img.ptr();
}
+23 -194
View File
@@ -6,6 +6,7 @@
#include <stdint.h> #include <stdint.h>
#include <math.h> #include <math.h>
#include <memory.h> #include <memory.h>
#include <opencv2/imgproc.hpp>
class Peak class Peak
{ {
@@ -29,204 +30,32 @@ public:
} }
}; };
class RawImageAbs class RawImage
{ {
protected: protected:
uint32_t m_width,m_height; cv::Mat m_img;
public: public:
virtual ~RawImageAbs(){} enum ImgType
virtual bool imageStats(uint64_t *mean, double *stdDev, uint64_t *median, uint64_t *min, uint64_t *max) const = 0;
virtual void rect(int &x, int &y, int w, int h, std::vector<double> &r) const = 0;
virtual int findPeaks(uint64_t background, double distance, std::vector<Peak> &peaks) const = 0;
virtual RawImageAbs* medianFilter() const = 0;
virtual void quarter() = 0;
uint32_t width() const
{ {
return m_width; UINT8,
} UINT16,
uint32_t height() const FLOAT32,
{ UNKNOWN,
return m_height; };
} RawImage();
}; RawImage(int w, int h, ImgType type);
RawImage(const RawImage &d);
template<typename T> bool imageStats(double *mean, double *stdDev, double *median, double *min, double *max) const;
class RawImage : public RawImageAbs void rect(int &x, int &y, int w, int h, std::vector<double> &r) const;
{ int findPeaks(double background, double distance, std::vector<Peak> &peaks) const;
std::vector<T> m_img; RawImage* medianFilter() const;
bool checkPixel(T c, uint32_t x, uint32_t y) const void quarter();
{ uint32_t width() const;
T d = pixel(x, y); uint32_t height() const;
return c>=d; uint32_t size() const;
} ImgType type() const;
public: void* data();
RawImage() const void* data() const;
{
m_width = m_height = 0;
}
RawImage(int w, int h)
{
m_width = w;
m_height = h;
m_img.resize(w*h);
}
RawImage(int w, int h, std::vector<T> &img)
{
m_width = w;
m_height = h;
img.resize(w*h);
m_img = std::move(img);
img.clear();
}
T* data()
{
return m_img.data();
}
std::vector<T> dataArray() const
{
return m_img;
}
bool imageStats(uint64_t *mean, double *stdDev, uint64_t *median, uint64_t *min, uint64_t *max) const
{
if(m_img.size()==0)return false;
uint64_t sum = 0;
uint64_t sqrSum = 0;
uint64_t tMin = UINT64_MAX;
uint64_t tMax = 0;
uint32_t histogram[65536];
memset(histogram, 0, sizeof(histogram));
const int shift = sizeof(T)>2 ? sizeof(T)*8 - 16 : 0;
for(T i : m_img)
{
sum += i;
sqrSum += i*i;
tMin = tMin>i ? i : tMin;
tMax = tMax<i ? i : tMax;
histogram[i>>shift]++;
}
if(mean)*mean = sum/m_img.size();
if(min)*min = tMin;
if(max)*max = tMax;
if(stdDev)*stdDev = sqrt((sqrSum - (double)sum*sum/m_img.size()) / (double)(m_img.size()-1));
if(median)
{
size_t medianSum = 0;
for(int i=0;i<65536;i++)
{
medianSum += histogram[i];
if(medianSum>=m_img.size()/2)
{
*median = i;
break;
}
}
}
return true;
}
T pixel(uint32_t x, uint32_t y) const
{
if(x>=m_width)x=0;
if(y>=m_height)y=0;
return m_img[y*m_width+x];
}
void rect(int &x, int &y, int w, int h, std::vector<double> &r) const
{
r.resize(w*h);
x -= w/2;
y -= h/2;
if(x<0)x = 0;
if(y<0)y = 0;
if(x+w >= m_width)x = m_width-w;
if(y+h >= m_height)y = m_height-h;
uint32_t d = 0;
for(int i=y;i<y+h;i++)
for(int o=x;o<x+w;o++)
r[d++] = pixel(o, i);
}
int findPeaks(uint64_t background, double distance, std::vector<Peak> &peaks) const
{
std::vector<Peak> tmpPeaks;
const int r = 1;
for(uint32_t i=r; i<m_height-r; i++)
{
for(uint32_t o=r; o<m_width-r; o++)
{
T c = pixel(o, i);
if(c>background && checkPixel(c, o-r, i-r) && checkPixel(c, o, i-r) &&
checkPixel(c, o+r, i-r) && checkPixel(c, o-r, i) && checkPixel(c, o+r, i)
&& checkPixel(c, o-r, i+r) && checkPixel(c, o, i+r) && checkPixel(c, o+r, i+r))
{
tmpPeaks.push_back(Peak(c, o, i));
}
}
}
int num = tmpPeaks.size();
std::sort(tmpPeaks.begin(), tmpPeaks.end());
tmpPeaks.resize(std::min(num, 10000));
uint32_t d = distance*distance;
for(const Peak &p : tmpPeaks)
{
bool pass = true;
for(const Peak &k : peaks)
{
if(p.distance(k) < d)
{
pass = false;
break;
}
}
if(pass)
{
peaks.push_back(p);
}
}
return num;
}
RawImageAbs* medianFilter() const
{
RawImage<T> *ret = new RawImage<T>;
std::vector<T> tmp;
tmp.resize(m_width*m_height);
#pragma omp parallel for
for(uint32_t y=0;y<m_height;y++)
{
for(uint32_t x=0;x<m_width;x++)
{
T array[9] = { pixel(x-1, y-1), pixel(x, y-1), pixel(x+1, y-1),
pixel(x-1, y), pixel(x, y), pixel(x+1, y),
pixel(x-1, y+1), pixel(x, y+1), pixel(x+1, y+1)};
std::nth_element(std::begin(array), array+4, std::end(array));
tmp[y*m_width+x] = array[4];
}
}
ret->m_width = m_width;
ret->m_height = m_height;
ret->m_img = std::move(tmp);
return ret;
}
void quarter()
{
std::vector<T> tmp;
tmp.resize(m_width*m_height);
uint32_t d = 0;
for(uint32_t i=0;i<m_height;i+=2)
{
for(uint32_t o=0;o<m_width;o+=2)
{
tmp[d++] = m_img[i*m_width+o];
}
}
m_img = tmp;
m_width /= 2;
m_height /= 2;
}
}; };
#endif // RAWIMAGE_H #endif // RAWIMAGE_H
+5 -2
View File
@@ -15,8 +15,10 @@ CONFIG += c++11
QMAKE_CXXFLAGS += -fopenmp QMAKE_CXXFLAGS += -fopenmp
LIBS += -lraw -lexif -lcfitsio -lgsl -lgslcblas -fopenmp unix: CONFIG += link_pkgconfig
unix: PKGCONFIG += libraw_r cfitsio gsl libexif opencv
win32:LIBS += -lraw -lexif -lcfitsio -lgsl -lgslcblas -lopencv_imgproc -lopencv_core -fopenmp
win32:LIBS += -LC:\msys64\mingw64\lib -LC:\msys64\mingw64\bin win32:LIBS += -LC:\msys64\mingw64\lib -LC:\msys64\mingw64\bin
win32:INCLUDEPATH += C:\msys64\mingw64\include\ C:\msys64\mingw64\include\cfitsio win32:INCLUDEPATH += C:\msys64\mingw64\include\ C:\msys64\mingw64\include\cfitsio
@@ -31,7 +33,8 @@ SOURCES += main.cpp\
phd.cpp \ phd.cpp \
photocapture.cpp \ photocapture.cpp \
imagescrollareagl.cpp \ imagescrollareagl.cpp \
stretchpanel.cpp stretchpanel.cpp \
rawimage.cpp
HEADERS += mainwindow.h \ HEADERS += mainwindow.h \
imagescrollarea.h \ imagescrollarea.h \