diff --git a/imageringlist.cpp b/imageringlist.cpp index 0d5c287..c62efd6 100644 --- a/imageringlist.cpp +++ b/imageringlist.cpp @@ -47,7 +47,7 @@ QPixmap Image::pixmap() const return m_pixmap; } -RawImageAbs *Image::rawImage() +RawImage *Image::rawImage() { return m_rawImage.get(); } @@ -68,13 +68,13 @@ void Image::imageLoaded(QImage img, void *rawImage, ImageInfoData info) if(!m_released) { m_pixmap = QPixmap::fromImage(img); - m_rawImage.reset(static_cast(rawImage)); + m_rawImage.reset(static_cast(rawImage)); m_info = info; emit pixmapLoaded(this); } else { - delete static_cast(rawImage); + delete static_cast(rawImage); } } diff --git a/imageringlist.h b/imageringlist.h index 36fc1b7..cf88838 100644 --- a/imageringlist.h +++ b/imageringlist.h @@ -18,7 +18,7 @@ class Image : public QObject bool m_released; bool m_current; QPixmap m_pixmap; - std::unique_ptr m_rawImage; + std::unique_ptr m_rawImage; QString m_name; ImageInfoData m_info; ImageRingList *m_ringList; @@ -28,7 +28,7 @@ public: void release(); QString name() const; QPixmap pixmap() const; - RawImageAbs* rawImage(); + RawImage* rawImage(); ImageInfoData info() const; bool isCurrent() const; signals: diff --git a/imagescrollareagl.cpp b/imagescrollareagl.cpp index 8e3adad..0a9d5ce 100644 --- a/imagescrollareagl.cpp +++ b/imagescrollareagl.cpp @@ -3,6 +3,7 @@ #include #include #include +#include ImageScrollAreaGL::ImageScrollAreaGL(QWidget *parent) : QOpenGLWidget(parent) { @@ -17,32 +18,41 @@ ImageScrollAreaGL::~ImageScrollAreaGL() makeCurrent(); } -void ImageScrollAreaGL::setImage(RawImageAbs *image) +void ImageScrollAreaGL::setImage(RawImage *image) { + if(image == nullptr)return; + 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)) + 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; - } - else if(RawImage *i16 = dynamic_cast*>(image)) - { - m_image->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt16, i16->data()); + break; + case RawImage::UINT16: + m_image->setData(0, QOpenGLTexture::Red, QOpenGLTexture::UInt16, image->data(), m_transferOptions.get()); m_range = UINT16_MAX; - } - else if(RawImage *i32 = dynamic_cast*>(image)) - { - m_image->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt32, i32->data()); - m_range = UINT32_MAX; + break; + case RawImage::FLOAT32: + break; } m_image->generateMipMaps(); repaint(); } +void ImageScrollAreaGL::setImage(const QPixmap &pixmap) +{ + QImage img = pixmap.toImage(); + + m_image->destroy(); + m_image->setData(img); + repaint(); +} + void ImageScrollAreaGL::setLow(int low) { m_low = low/m_range; @@ -127,4 +137,7 @@ void ImageScrollAreaGL::initializeGL() m_image->bind(0); m_image->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_image->setMagnificationFilter(QOpenGLTexture::Linear); + + m_transferOptions = std::unique_ptr(new QOpenGLPixelTransferOptions); + m_transferOptions->setAlignment(1); } diff --git a/imagescrollareagl.h b/imagescrollareagl.h index 3e812a6..1c97838 100644 --- a/imagescrollareagl.h +++ b/imagescrollareagl.h @@ -28,6 +28,7 @@ class ImageScrollAreaGL : public QOpenGLWidget std::unique_ptr m_buffer; std::unique_ptr m_image; std::unique_ptr m_vao; + std::unique_ptr m_transferOptions; int m_width, m_height; float m_low; float m_high; @@ -35,7 +36,8 @@ class ImageScrollAreaGL : public QOpenGLWidget public: explicit ImageScrollAreaGL(QWidget *parent = nullptr); ~ImageScrollAreaGL(); - void setImage(RawImageAbs *image); + void setImage(RawImage *image); + void setImage(const QPixmap &pixmap); public slots: void setLow(int low); void setHigh(int high); diff --git a/loadrunable.cpp b/loadrunable.cpp index 70e2a9e..8982f4b 100644 --- a/loadrunable.cpp +++ b/loadrunable.cpp @@ -75,7 +75,7 @@ void printStarModel(int radius, const std::vector &data, const Star &sta 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) return false; @@ -108,7 +108,8 @@ bool loadRAW(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qi out[d++] = p; } } - *image = new RawImage(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) @@ -143,7 +144,7 @@ bool loadRAW(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qi 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) return false; @@ -188,7 +189,11 @@ bool loadFITS(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qi for(size_t i=0; iscanLine(i), &bits8[i*w], w*sizeof(uint8_t)); } - if(image)*image = new RawImage(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; case SHORT_IMG: bits16.resize(size); @@ -203,10 +208,14 @@ bool loadFITS(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qi scanline[o] = bits16[i*w+o] >> 8; } } - if(image)*image = new RawImage(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; case LONG_IMG: - bits32.resize(size); + /*bits32.resize(size); fits_read_pix(file, TUINT, fpixel, size, NULL, &bits32[0], NULL, &status); if(status)break; if(qimage) @@ -218,7 +227,11 @@ bool loadFITS(QString path, ImageInfoData &info, RawImageAbs **image, QImage *qi scanline[o] = bits32[i*w+o] >> 24; } } - if(image)*image = new RawImage(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; } } @@ -259,7 +272,7 @@ void LoadRunable::run() info.append(StringPair(QObject::tr("Filename"), finfo.fileName())); QImage img; - RawImageAbs *rawImage = nullptr; + RawImage *rawImage = nullptr; bool raw = false; if(m_file.endsWith(".CR2", Qt::CaseInsensitive)) { @@ -288,7 +301,7 @@ void LoadRunable::run() if(rawImage && m_analyzeLevel >= Statistics) { - uint64_t mean, median, min, max; + double mean, median, min, max; double stdDev; timer.start(); rawImage->imageStats(&mean, &stdDev, &median, &min, &max); @@ -306,9 +319,9 @@ void LoadRunable::run() rawImage->quarter(); qDebug() << "quarter" << timer.restart(); } - RawImageAbs *medianImage = rawImage->medianFilter(); + RawImage *medianImage = rawImage->medianFilter(); qDebug() << "median" << timer.restart(); - int numPeaks = medianImage->findPeaks(median+stdDev, 20, peaks); + int numPeaks = medianImage->findPeaks(median+stdDev*2, 20, peaks); delete medianImage; qDebug() << "peaks" << timer.restart(); if(m_analyzeLevel == Peaks) diff --git a/mainwindow.cpp b/mainwindow.cpp index f9b27e3..66f02cf 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -27,7 +27,7 @@ int MainWindow::socketPair[2] = {0, 0}; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { qRegisterMetaType("ImageInfoData"); - qRegisterMetaType("RawImageAbs"); + qRegisterMetaType("RawImage"); m_info = new ImageInfo(this); QDockWidget *infoDock = new QDockWidget(tr("Image info"), this); @@ -206,7 +206,14 @@ void MainWindow::socketNotify() void MainWindow::pixmapLoaded(Image *image) { 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() diff --git a/rawimage.cpp b/rawimage.cpp new file mode 100644 index 0000000..a23558f --- /dev/null +++ b/rawimage.cpp @@ -0,0 +1,171 @@ +#include "rawimage.h" +#include +#include + +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(0, i); + if(medianSum >= halfImageSize) + { + *median = i; + break; + } + } + } + + return true; +} + +void RawImage::rect(int &x, int &y, int w, int h, std::vector &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(doubleMat.begin(), doubleMat.end()); +} + +int RawImage::findPeaks(double background, double distance, std::vector &peaks) const +{ + std::vector> 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(); +} diff --git a/rawimage.h b/rawimage.h index 2d0f7d9..1323a68 100644 --- a/rawimage.h +++ b/rawimage.h @@ -6,6 +6,7 @@ #include #include #include +#include class Peak { @@ -29,204 +30,32 @@ public: } }; -class RawImageAbs +class RawImage { protected: - uint32_t m_width,m_height; + cv::Mat m_img; public: - virtual ~RawImageAbs(){} - 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 &r) const = 0; - 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 + enum ImgType { - return m_width; - } - uint32_t height() const - { - return m_height; - } -}; - -template -class RawImage : public RawImageAbs -{ - std::vector m_img; - bool checkPixel(T c, uint32_t x, uint32_t y) const - { - T d = pixel(x, y); - return c>=d; - } -public: - RawImage() - { - 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 &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 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>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 &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 &peaks) const - { - std::vector tmpPeaks; - const int r = 1; - for(uint32_t i=r; ibackground && 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 *ret = new RawImage; - std::vector tmp; - tmp.resize(m_width*m_height); - #pragma omp parallel for - for(uint32_t y=0;ym_width = m_width; - ret->m_height = m_height; - ret->m_img = std::move(tmp); - return ret; - } - void quarter() - { - std::vector tmp; - tmp.resize(m_width*m_height); - uint32_t d = 0; - for(uint32_t i=0;i &r) const; + int findPeaks(double background, double distance, std::vector &peaks) const; + RawImage* medianFilter() const; + void quarter(); + uint32_t width() const; + uint32_t height() const; + uint32_t size() const; + ImgType type() const; + void* data(); + const void* data() const; }; #endif // RAWIMAGE_H diff --git a/tenmon.pro b/tenmon.pro index 7944dce..2c2ebd4 100644 --- a/tenmon.pro +++ b/tenmon.pro @@ -15,8 +15,10 @@ CONFIG += c++11 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:INCLUDEPATH += C:\msys64\mingw64\include\ C:\msys64\mingw64\include\cfitsio @@ -31,7 +33,8 @@ SOURCES += main.cpp\ phd.cpp \ photocapture.cpp \ imagescrollareagl.cpp \ - stretchpanel.cpp + stretchpanel.cpp \ + rawimage.cpp HEADERS += mainwindow.h \ imagescrollarea.h \