summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJasem Mutlaq <mutlaqja@ikarustech.com>2016-11-05 22:17:33 (GMT)
committerJasem Mutlaq <mutlaqja@ikarustech.com>2016-11-05 22:17:33 (GMT)
commitb2c8887e2f408c4dedf20b1f1b4e7cda468ce59a (patch)
tree06ce744df75d495510ff91ba07a0e13614d9a9dc
parentf7a9269f8d53c445167748addff8ba8bda7d52ef (diff)
Use templated functions to reduce memory footprint of FITS operations
-rw-r--r--kstars/ekos/align/align.cpp18
-rw-r--r--kstars/ekos/align/onlineastrometryparser.cpp73
-rw-r--r--kstars/ekos/auxiliary/darklibrary.cpp73
-rw-r--r--kstars/ekos/auxiliary/darklibrary.h2
-rw-r--r--kstars/ekos/ekosmanager.cpp4
-rw-r--r--kstars/ekos/guide/guide.cpp4
-rw-r--r--kstars/ekos/guide/internalguide/gmath.cpp39
-rw-r--r--kstars/ekos/guide/internalguide/gmath.h3
-rw-r--r--kstars/ekos/guide/internalguide/internalguider.cpp1
-rw-r--r--kstars/ekos/opsekos.ui12
-rw-r--r--kstars/fitsviewer/bayer.c1980
-rw-r--r--kstars/fitsviewer/bayer.h210
-rw-r--r--kstars/fitsviewer/fitsdata.cpp836
-rw-r--r--kstars/fitsviewer/fitsdata.h48
-rw-r--r--kstars/fitsviewer/fitshistogram.cpp81
-rw-r--r--kstars/fitsviewer/fitshistogram.h6
-rw-r--r--kstars/fitsviewer/fitsview.cpp96
-rw-r--r--kstars/fitsviewer/fitsview.h7
-rw-r--r--kstars/indi/indidevice.cpp7
-rw-r--r--kstars/kstars.kcfg4
-rw-r--r--kstars/options/opsadvanced.ui168
21 files changed, 2929 insertions, 743 deletions
diff --git a/kstars/ekos/align/align.cpp b/kstars/ekos/align/align.cpp
index 913d3d1..6fa4f2c 100644
--- a/kstars/ekos/align/align.cpp
+++ b/kstars/ekos/align/align.cpp
@@ -733,7 +733,23 @@ void Align::newFITS(IBLOB *bp)
void Align::setCaptureComplete()
{
- DarkLibrary::Instance()->disconnect(this);
+ DarkLibrary::Instance()->disconnect(this);
+
+ if (solverTypeGroup->checkedId() == SOLVER_ONLINE && Options::astrometryUseJPEG())
+ {
+ ISD::CCDChip *targetChip = currentCCD->getChip(useGuideHead ? ISD::CCDChip::GUIDE_CCD : ISD::CCDChip::PRIMARY_CCD);
+ if (targetChip)
+ {
+ FITSView *view = targetChip->getImageView(FITS_ALIGN);
+ if (view)
+ {
+ QString jpegFile = blobFileName + ".jpg";
+ bool rc = view->getDisplayImage()->save(jpegFile, "JPG");
+ if (rc)
+ blobFileName = jpegFile;
+ }
+ }
+ }
startSolving(blobFileName);
}
diff --git a/kstars/ekos/align/onlineastrometryparser.cpp b/kstars/ekos/align/onlineastrometryparser.cpp
index c03d15e..a741ed7 100644
--- a/kstars/ekos/align/onlineastrometryparser.cpp
+++ b/kstars/ekos/align/onlineastrometryparser.cpp
@@ -88,79 +88,8 @@ bool OnlineAstrometryParser::startSovler(const QString &in_filename, const QStri
return false;
}
- QString finalFileName(in_filename);
+ filename = in_filename;
- if (Options::astrometryUseJPEG() && in_filename.endsWith(".jpg") == false && in_filename.endsWith(".jpeg") == false)
- {
- QFile fitsFile(in_filename);
- bool rc = fitsFile.open(QIODevice::ReadOnly);
- if (rc == false)
- {
- align->appendLogText(i18n("Failed to open file %1. %2", filename, fitsFile.errorString()));
- emit solverFailed();
- return false;
- }
-
- FITSData *image_data = new FITSData();
- rc = image_data->loadFITS(in_filename);
- if (rc)
- {
- uint16_t image_width,image_height;
- double bscale, bzero;
- double min, max;
- int val;
-
- image_data->getDimensions(&image_width, &image_height);
- QImage *display_image = new QImage(image_width, image_height, QImage::Format_Indexed8);
-
- display_image->setColorCount(256);
- for (int i=0; i < 256; i++)
- display_image->setColor(i, qRgb(i,i,i));
-
- image_data->getMinMax(&min, &max);
- float *image_buffer = image_data->getImageBuffer();
-
- bscale = 255. / (max - min);
- bzero = (-min) * (255. / (max - min));
-
- int w = image_width;
- int h = image_height;
-
- /* Fill in pixel values using indexed map, linear scale */
- for (int j = 0; j < h; j++)
- for (int i = 0; i < w; i++)
- {
- val = image_buffer[j * w + i];
- display_image->setPixel(i, j, ((int) (val * bscale + bzero)));
- }
-
- finalFileName.remove(finalFileName.lastIndexOf('.'), finalFileName.length());
- finalFileName.append(".jpg");
- bool isFileSaved = display_image->save(finalFileName, "JPG");
- if (isFileSaved == false)
- {
- align->appendLogText(i18n("Warning: Converting FITS to JPEG failed. Uploading original FITS image."));
- finalFileName = in_filename;
- }
- else
- {
- if (isGenerated)
- QFile::remove(in_filename);
- else
- isGenerated = true;
- }
-
- delete (display_image);
- }
- else
- {
- align->appendLogText(i18n("Warning: Converting FITS to JPEG failed. Uploading original FITS image."));
- }
-
- delete (image_data);
- }
-
- filename = finalFileName;
for (int i=0; i < args.count(); i++)
{
if (args[i] == "-L")
diff --git a/kstars/ekos/auxiliary/darklibrary.cpp b/kstars/ekos/auxiliary/darklibrary.cpp
index 42df81a..14b2b50 100644
--- a/kstars/ekos/auxiliary/darklibrary.cpp
+++ b/kstars/ekos/auxiliary/darklibrary.cpp
@@ -164,38 +164,60 @@ bool DarkLibrary::subtract(FITSData *darkData, FITSView *lightImage, FITSScale f
Q_ASSERT(darkData);
Q_ASSERT(lightImage);
- FITSData *lightData = lightImage->getImageData();
-
- float *darkBuffer = darkData->getImageBuffer();
- float *lightBuffer = lightData->getImageBuffer();
+ switch (darkData->getDataType())
+ {
+ case TBYTE:
+ return subtract<uint8_t>(darkData, lightImage, filter, offsetX, offsetY);
+ break;
- int darkoffset = offsetX + offsetY * darkData->getWidth();
- int darkW = darkData->getWidth();
+ case TUSHORT:
+ return subtract<uint16_t>(darkData, lightImage, filter, offsetX, offsetY);
+ break;
- int lightOffset = 0;
- int lightW = lightData->getWidth();
- int lightH = lightData->getHeight();
+ default:
+ return false;
- for (int i=0; i < lightH; i++)
- {
- for (int j=0; j < lightW; j++)
- {
- lightBuffer[j+lightOffset] -= darkBuffer[j+darkoffset];
- if (lightBuffer[j+lightOffset] < 0)
- lightBuffer[j+lightOffset] = 0;
- }
-
- lightOffset += lightW;
- darkoffset += darkW;
}
+}
- lightData->applyFilter(filter);
- lightImage->rescale(ZOOM_KEEP_LEVEL);
- lightImage->updateFrame();
+template<typename T> bool DarkLibrary::subtract(FITSData *darkData, FITSView *lightImage, FITSScale filter, uint16_t offsetX, uint16_t offsetY)
+{
+ FITSData *lightData = lightImage->getImageData();
- emit darkFrameCompleted(true);
+ T *darkBuffer = reinterpret_cast<T*>(darkData->getImageBuffer());
+ T *lightBuffer = reinterpret_cast<T*>(lightData->getImageBuffer());
+
+ int darkoffset = offsetX + offsetY * darkData->getWidth();
+ int darkW = darkData->getWidth();
+
+ int lightOffset = 0;
+ int lightW = lightData->getWidth();
+ int lightH = lightData->getHeight();
+
+ for (int i=0; i < lightH; i++)
+ {
+ for (int j=0; j < lightW; j++)
+ {
+ if (lightBuffer[j+lightOffset] > darkBuffer[j+darkoffset])
+ lightBuffer[j+lightOffset] -= darkBuffer[j+darkoffset];
+ else
+ lightBuffer[j+lightOffset] = 0;
+ }
+
+ lightOffset += lightW;
+ darkoffset += darkW;
+ }
+
+ lightData->applyFilter(filter);
+ if (filter == FITS_NONE)
+ lightData->calculateStats(true);
+ lightImage->rescale(ZOOM_KEEP_LEVEL);
+ lightImage->updateFrame();
+
+ emit darkFrameCompleted(true);
+
+ return true;
- return true;
}
void DarkLibrary::captureAndSubtract(ISD::CCDChip *targetChip, FITSView*targetImage, double duration, uint16_t offsetX, uint16_t offsetY)
@@ -233,6 +255,7 @@ void DarkLibrary::captureAndSubtract(ISD::CCDChip *targetChip, FITSView*targetIm
== KMessageBox::Cancel)
{
emit newLog(i18n("Dark frame capture cancelled."));
+ disconnect(targetChip->getCCD(), SIGNAL(BLOBUpdated(IBLOB*)), this, SLOT(newFITS(IBLOB*)));
emit darkFrameCompleted(false);
}
}
diff --git a/kstars/ekos/auxiliary/darklibrary.h b/kstars/ekos/auxiliary/darklibrary.h
index 67a4692..c28af37 100644
--- a/kstars/ekos/auxiliary/darklibrary.h
+++ b/kstars/ekos/auxiliary/darklibrary.h
@@ -55,6 +55,8 @@ private:
bool loadDarkFile(const QString &filename);
bool saveDarkFile(FITSData *darkData);
+ template<typename T> bool subtract(FITSData *darkData, FITSView *lightImage, FITSScale filter, uint16_t offsetX, uint16_t offsetY);
+
QList<QVariantMap> darkFrames;
QHash<QString, FITSData *> darkFiles;
diff --git a/kstars/ekos/ekosmanager.cpp b/kstars/ekos/ekosmanager.cpp
index e846f1a..e45d3f3 100644
--- a/kstars/ekos/ekosmanager.cpp
+++ b/kstars/ekos/ekosmanager.cpp
@@ -199,6 +199,8 @@ EkosManager::~EkosManager()
delete previewPixmap;
delete focusStarPixmap;
delete guideStarPixmap;
+
+ qDeleteAll(profiles);
}
void EkosManager::closeEvent(QCloseEvent * /*event*/)
@@ -1277,7 +1279,7 @@ void EkosManager::processTabChange()
//if (focusProcess && currentWidget != focusProcess)
//focusProcess->resetFrame();
- if (alignProcess && currentWidget == alignProcess)
+ if (alignProcess && alignProcess == currentWidget)
{
if (alignProcess->isEnabled() == false && captureProcess->isEnabled())
{
diff --git a/kstars/ekos/guide/guide.cpp b/kstars/ekos/guide/guide.cpp
index bbd9765..eb20059 100644
--- a/kstars/ekos/guide/guide.cpp
+++ b/kstars/ekos/guide/guide.cpp
@@ -248,10 +248,10 @@ Guide::Guide() : QWidget()
internalGuider->setGuideView(guideView);
+ state = GUIDE_IDLE;
+
// Set current guide type
setGuiderType(-1);
-
- state = GUIDE_IDLE;
}
Guide::~Guide()
diff --git a/kstars/ekos/guide/internalguide/gmath.cpp b/kstars/ekos/guide/internalguide/gmath.cpp
index 19eec4f..42fa238 100644
--- a/kstars/ekos/guide/internalguide/gmath.cpp
+++ b/kstars/ekos/guide/internalguide/gmath.cpp
@@ -536,24 +536,45 @@ void cgmath::setLostStar(bool is_lost)
Vector cgmath::findLocalStarPosition( void ) const
{
+ if (useRapidGuide)
+ {
+ return Vector(rapidDX , rapidDY, 0);
+ }
+
+ FITSData *imageData = guideView->getImageData();
+
+ switch (imageData->getDataType())
+ {
+ case TBYTE:
+ return findLocalStarPosition<uint8_t>();
+
+ case TUSHORT:
+ return findLocalStarPosition<uint16_t>();
+
+ default:
+ break;
+ }
+
+ return Vector(-1,-1,-1);
+}
+
+template<typename T> Vector cgmath::findLocalStarPosition( void ) const
+{
static double P0 = 0.906, P1 = 0.584, P2 = 0.365, P3 = 0.117, P4 = 0.049, P5 = -0.05, P6 = -0.064, P7 = -0.074, P8 = -0.094;
Vector ret;
int i, j;
double resx, resy, mass, threshold, pval;
- float *psrc = NULL, *porigin = NULL;
- float *pptr;
-
- if (useRapidGuide)
- {
- return (ret = Vector(rapidDX , rapidDY, 0));
- }
+ T *psrc = NULL, *porigin = NULL;
+ T *pptr;
QRect trackingBox = guideView->getTrackingBox();
+
if (trackingBox.isValid() == false)
return Vector(-1,-1,-1);
FITSData *imageData = guideView->getImageData();
+
if (imageData == NULL)
{
if (Options::guideLogging())
@@ -561,7 +582,7 @@ Vector cgmath::findLocalStarPosition( void ) const
return Vector(-1,-1,-1);
}
- float *pdata = imageData->getImageBuffer();
+ T *pdata = reinterpret_cast<T*>(imageData->getImageBuffer());
if (Options::guideLogging())
qDebug() << "Guide: Tracking Square " << trackingBox;
@@ -583,7 +604,7 @@ Vector cgmath::findLocalStarPosition( void ) const
float i0, i1, i2, i3, i4, i5, i6, i7, i8;
int ix = 0, iy = 0;
int xM4;
- float *p;
+ T *p;
double average, fit, bestFit = 0;
int minx = 0;
int maxx = width;
diff --git a/kstars/ekos/guide/internalguide/gmath.h b/kstars/ekos/guide/internalguide/gmath.h
index 266a3f2..7354761 100644
--- a/kstars/ekos/guide/internalguide/gmath.h
+++ b/kstars/ekos/guide/internalguide/gmath.h
@@ -173,6 +173,9 @@ signals:
void newStarPosition(QVector3D, bool);
private:
+
+ // Templated functions
+ template<typename T> Vector findLocalStarPosition( void ) const;
// sys...
uint32_t ticks; // global channel ticker
QPointer<FITSView> guideView; // pointer to image
diff --git a/kstars/ekos/guide/internalguide/internalguider.cpp b/kstars/ekos/guide/internalguide/internalguider.cpp
index 8b42e37..eab29d2 100644
--- a/kstars/ekos/guide/internalguide/internalguider.cpp
+++ b/kstars/ekos/guide/internalguide/internalguider.cpp
@@ -51,6 +51,7 @@ InternalGuider::InternalGuider()
InternalGuider::~InternalGuider()
{
+ delete (pmath);
}
bool InternalGuider::guide()
diff --git a/kstars/ekos/opsekos.ui b/kstars/ekos/opsekos.ui
index e51fb28..3604f7e 100644
--- a/kstars/ekos/opsekos.ui
+++ b/kstars/ekos/opsekos.ui
@@ -14,7 +14,7 @@
<string>TabWidget</string>
</property>
<property name="currentIndex">
- <number>1</number>
+ <number>0</number>
</property>
<widget class="QWidget" name="generalTab">
<attribute name="title">
@@ -324,16 +324,6 @@
</widget>
</item>
<item>
- <widget class="QCheckBox" name="kcfg_AutoStretch">
- <property name="toolTip">
- <string>Always apply auto stretch to captured images in FITS Viewer</string>
- </property>
- <property name="text">
- <string>Auto Stretch</string>
- </property>
- </widget>
- </item>
- <item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/kstars/fitsviewer/bayer.c b/kstars/fitsviewer/bayer.c
index d7cfb5e..1100053 100644
--- a/kstars/fitsviewer/bayer.c
+++ b/kstars/fitsviewer/bayer.c
@@ -25,22 +25,48 @@
#include <math.h>
#include <stdlib.h>
#include <string.h>
-#include <float.h>
-#include <inttypes.h>
#include "bayer.h"
+#define CLIP(in, out)\
+ in = in < 0 ? 0 : in;\
+ in = in > 255 ? 255 : in;\
+ out=in;
-#define CLIP_FLOAT(in, out)\
- in = in < FLT_MIN ? FLT_MIN : in;\
- in = in > FLT_MAX ? FLT_MAX : in;\
- out=in;
+#define CLIP16(in, out, bits)\
+ in = in < 0 ? 0 : in;\
+ in = in > ((1<<bits)-1) ? ((1<<bits)-1) : in;\
+ out=in;
void
-ClearBorders_float(float * rgb, int sx, int sy, int w)
+ClearBorders(uint8_t *rgb, int sx, int sy, int w)
{
int i, j;
+ /* black edges are added with a width w: */
+ i = 3 * sx * w - 1;
+ j = 3 * sx * sy - 1;
+ while (i >= 0) {
+ rgb[i--] = 0;
+ rgb[j--] = 0;
+ }
- /* black edges:*/
+ int low = sx * (w - 1) * 3 - 1 + w * 3;
+ i = low + sx * (sy - w * 2 + 1) * 3;
+ while (i > low) {
+ j = 6 * w;
+ while (j > 0) {
+ rgb[i--] = 0;
+ j--;
+ }
+ i -= (sx - 2 * w) * 3;
+ }
+}
+
+void
+ClearBorders_uint16(uint16_t * rgb, int sx, int sy, int w)
+{
+ int i, j;
+
+ /* black edges: */
i = 3 * sx * w - 1;
j = 3 * sx * sy - 1;
while (i >= 0) {
@@ -70,24 +96,753 @@ ClearBorders_float(float * rgb, int sx, int sy, int w)
* patterns. *
**************************************************************/
+/* 8-bits versions */
/* insprired by OpenCV's Bayer decoding */
+
dc1394error_t
-dc1394_bayer_NearestNeighbor_float(const float * bayer, float * rgb, int sx, int sy, int offsetX, int offsetY, dc1394color_filter_t tile)
+dc1394_bayer_NearestNeighbor(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
+{
+ const int bayerStep = sx;
+ const int rgbStep = 3 * sx;
+ int width = sx;
+ int height = sy;
+ int blue = tile == DC1394_COLOR_FILTER_BGGR
+ || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
+ int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
+ || tile == DC1394_COLOR_FILTER_GRBG;
+ int i, imax, iinc;
+
+ if ((tile>DC1394_COLOR_FILTER_MAX)||(tile<DC1394_COLOR_FILTER_MIN))
+ return DC1394_INVALID_COLOR_FILTER;
+
+ /* add black border */
+ imax = sx * sy * 3;
+ for (i = sx * (sy - 1) * 3; i < imax; i++) {
+ rgb[i] = 0;
+ }
+ iinc = (sx - 1) * 3;
+ for (i = (sx - 1) * 3; i < imax; i += iinc) {
+ rgb[i++] = 0;
+ rgb[i++] = 0;
+ rgb[i++] = 0;
+ }
+
+ rgb += 1;
+ width -= 1;
+ height -= 1;
+
+ for (; height--; bayer += bayerStep, rgb += rgbStep) {
+ const uint8_t *bayerEnd = bayer + width;
+
+ if (start_with_green) {
+ rgb[-blue] = bayer[1];
+ rgb[0] = bayer[bayerStep + 1];
+ rgb[blue] = bayer[bayerStep];
+ bayer++;
+ rgb += 3;
+ }
+
+ if (blue > 0)
+ {
+ for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6)
+ {
+ rgb[-1] = bayer[0];
+ rgb[0] = bayer[1];
+ rgb[1] = bayer[bayerStep + 1];
+
+ rgb[2] = bayer[2];
+ rgb[3] = bayer[bayerStep + 2];
+ rgb[4] = bayer[bayerStep + 1];
+ }
+ }
+ else {
+ for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6) {
+ rgb[1] = bayer[0];
+ rgb[0] = bayer[1];
+ rgb[-1] = bayer[bayerStep + 1];
+
+ rgb[4] = bayer[2];
+ rgb[3] = bayer[bayerStep + 2];
+ rgb[2] = bayer[bayerStep + 1];
+ }
+ }
+
+ if (bayer < bayerEnd) {
+ rgb[-blue] = bayer[0];
+ rgb[0] = bayer[1];
+ rgb[blue] = bayer[bayerStep + 1];
+ bayer++;
+ rgb += 3;
+ }
+
+ bayer -= width;
+ rgb -= width * 3;
+
+ blue = -blue;
+ start_with_green = !start_with_green;
+ }
+
+ return DC1394_SUCCESS;
+}
+
+/* OpenCV's Bayer decoding */
+dc1394error_t
+dc1394_bayer_Bilinear(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
{
const int bayerStep = sx;
const int rgbStep = 3 * sx;
int width = sx;
int height = sy;
+ /*
+ the two letters of the OpenCV name are respectively
+ the 4th and 3rd letters from the blinky name,
+ and we also have to switch R and B (OpenCV is BGR)
+
+ CV_BayerBG2BGR <-> DC1394_COLOR_FILTER_BGGR
+ CV_BayerGB2BGR <-> DC1394_COLOR_FILTER_GBRG
+ CV_BayerGR2BGR <-> DC1394_COLOR_FILTER_GRBG
+
+ int blue = tile == CV_BayerBG2BGR || tile == CV_BayerGB2BGR ? -1 : 1;
+ int start_with_green = tile == CV_BayerGB2BGR || tile == CV_BayerGR2BGR;
+ */
int blue = tile == DC1394_COLOR_FILTER_BGGR
|| tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
|| tile == DC1394_COLOR_FILTER_GRBG;
+ if ((tile>DC1394_COLOR_FILTER_MAX)||(tile<DC1394_COLOR_FILTER_MIN))
+ return DC1394_INVALID_COLOR_FILTER;
+
+ ClearBorders(rgb, sx, sy, 1);
+ rgb += rgbStep + 3 + 1;
+ height -= 2;
+ width -= 2;
+
+ for (; height--; bayer += bayerStep, rgb += rgbStep) {
+ int t0, t1;
+ const uint8_t *bayerEnd = bayer + width;
+
+ if (start_with_green) {
+ /* OpenCV has a bug in the next line, which was
+ t0 = (bayer[0] + bayer[bayerStep * 2] + 1) >> 1; */
+ t0 = (bayer[1] + bayer[bayerStep * 2 + 1] + 1) >> 1;
+ t1 = (bayer[bayerStep] + bayer[bayerStep + 2] + 1) >> 1;
+ rgb[-blue] = (uint8_t) t0;
+ rgb[0] = bayer[bayerStep + 1];
+ rgb[blue] = (uint8_t) t1;
+ bayer++;
+ rgb += 3;
+ }
+
+ if (blue > 0) {
+ for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6) {
+ t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
+ bayer[bayerStep * 2 + 2] + 2) >> 2;
+ t1 = (bayer[1] + bayer[bayerStep] +
+ bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
+ 2) >> 2;
+ rgb[-1] = (uint8_t) t0;
+ rgb[0] = (uint8_t) t1;
+ rgb[1] = bayer[bayerStep + 1];
+
+ t0 = (bayer[2] + bayer[bayerStep * 2 + 2] + 1) >> 1;
+ t1 = (bayer[bayerStep + 1] + bayer[bayerStep + 3] +
+ 1) >> 1;
+ rgb[2] = (uint8_t) t0;
+ rgb[3] = bayer[bayerStep + 2];
+ rgb[4] = (uint8_t) t1;
+ }
+ } else {
+ for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6) {
+ t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
+ bayer[bayerStep * 2 + 2] + 2) >> 2;
+ t1 = (bayer[1] + bayer[bayerStep] +
+ bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
+ 2) >> 2;
+ rgb[1] = (uint8_t) t0;
+ rgb[0] = (uint8_t) t1;
+ rgb[-1] = bayer[bayerStep + 1];
+
+ t0 = (bayer[2] + bayer[bayerStep * 2 + 2] + 1) >> 1;
+ t1 = (bayer[bayerStep + 1] + bayer[bayerStep + 3] +
+ 1) >> 1;
+ rgb[4] = (uint8_t) t0;
+ rgb[3] = bayer[bayerStep + 2];
+ rgb[2] = (uint8_t) t1;
+ }
+ }
+
+ if (bayer < bayerEnd) {
+ t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
+ bayer[bayerStep * 2 + 2] + 2) >> 2;
+ t1 = (bayer[1] + bayer[bayerStep] +
+ bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
+ 2) >> 2;
+ rgb[-blue] = (uint8_t) t0;
+ rgb[0] = (uint8_t) t1;
+ rgb[blue] = bayer[bayerStep + 1];
+ bayer++;
+ rgb += 3;
+ }
+
+ bayer -= width;
+ rgb -= width * 3;
+
+ blue = -blue;
+ start_with_green = !start_with_green;
+ }
+ return DC1394_SUCCESS;
+}
+
+/* High-Quality Linear Interpolation For Demosaicing Of
+ Bayer-Patterned Color Images, by Henrique S. Malvar, Li-wei He, and
+ Ross Cutler, in ICASSP'04 */
+dc1394error_t
+dc1394_bayer_HQLinear(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
+{
+ const int bayerStep = sx;
+ const int rgbStep = 3 * sx;
+ int width = sx;
+ int height = sy;
+ int blue = tile == DC1394_COLOR_FILTER_BGGR
+ || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
+ int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
+ || tile == DC1394_COLOR_FILTER_GRBG;
if ((tile>DC1394_COLOR_FILTER_MAX)||(tile<DC1394_COLOR_FILTER_MIN))
return DC1394_INVALID_COLOR_FILTER;
- int i, iinc, imax;
+ ClearBorders(rgb, sx, sy, 2);
+ rgb += 2 * rgbStep + 6 + 1;
+ height -= 4;
+ width -= 4;
+
+ /* We begin with a (+1 line,+1 column) offset with respect to bilinear decoding, so start_with_green is the same, but blue is opposite */
+ blue = -blue;
+
+ for (; height--; bayer += bayerStep, rgb += rgbStep) {
+ int t0, t1;
+ const uint8_t *bayerEnd = bayer + width;
+ const int bayerStep2 = bayerStep * 2;
+ const int bayerStep3 = bayerStep * 3;
+ const int bayerStep4 = bayerStep * 4;
+
+ if (start_with_green) {
+ /* at green pixel */
+ rgb[0] = bayer[bayerStep2 + 2];
+ t0 = rgb[0] * 5
+ + ((bayer[bayerStep + 2] + bayer[bayerStep3 + 2]) << 2)
+ - bayer[2]
+ - bayer[bayerStep + 1]
+ - bayer[bayerStep + 3]
+ - bayer[bayerStep3 + 1]
+ - bayer[bayerStep3 + 3]
+ - bayer[bayerStep4 + 2]
+ + ((bayer[bayerStep2] + bayer[bayerStep2 + 4] + 1) >> 1);
+ t1 = rgb[0] * 5 +
+ ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 3]) << 2)
+ - bayer[bayerStep2]
+ - bayer[bayerStep + 1]
+ - bayer[bayerStep + 3]
+ - bayer[bayerStep3 + 1]
+ - bayer[bayerStep3 + 3]
+ - bayer[bayerStep2 + 4]
+ + ((bayer[2] + bayer[bayerStep4 + 2] + 1) >> 1);
+ t0 = (t0 + 4) >> 3;
+ CLIP(t0, rgb[-blue]);
+ t1 = (t1 + 4) >> 3;
+ CLIP(t1, rgb[blue]);
+ bayer++;
+ rgb += 3;
+ }
+
+ if (blue > 0) {
+ for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6) {
+ /* B at B */
+ rgb[1] = bayer[bayerStep2 + 2];
+ /* R at B */
+ t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
+ bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) << 1)
+ -
+ (((bayer[2] + bayer[bayerStep2] +
+ bayer[bayerStep2 + 4] + bayer[bayerStep4 +
+ 2]) * 3 + 1) >> 1)
+ + rgb[1] * 6;
+ /* G at B */
+ t1 = ((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
+ bayer[bayerStep2 + 3] + bayer[bayerStep3 + 2]) << 1)
+ - (bayer[2] + bayer[bayerStep2] +
+ bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
+ + (rgb[1] << 2);
+ t0 = (t0 + 4) >> 3;
+ CLIP(t0, rgb[-1]);
+ t1 = (t1 + 4) >> 3;
+ CLIP(t1, rgb[0]);
+ /* at green pixel */
+ rgb[3] = bayer[bayerStep2 + 3];
+ t0 = rgb[3] * 5
+ + ((bayer[bayerStep + 3] + bayer[bayerStep3 + 3]) << 2)
+ - bayer[3]
+ - bayer[bayerStep + 2]
+ - bayer[bayerStep + 4]
+ - bayer[bayerStep3 + 2]
+ - bayer[bayerStep3 + 4]
+ - bayer[bayerStep4 + 3]
+ +
+ ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 5] +
+ 1) >> 1);
+ t1 = rgb[3] * 5 +
+ ((bayer[bayerStep2 + 2] + bayer[bayerStep2 + 4]) << 2)
+ - bayer[bayerStep2 + 1]
+ - bayer[bayerStep + 2]
+ - bayer[bayerStep + 4]
+ - bayer[bayerStep3 + 2]
+ - bayer[bayerStep3 + 4]
+ - bayer[bayerStep2 + 5]
+ + ((bayer[3] + bayer[bayerStep4 + 3] + 1) >> 1);
+ t0 = (t0 + 4) >> 3;
+ CLIP(t0, rgb[2]);
+ t1 = (t1 + 4) >> 3;
+ CLIP(t1, rgb[4]);
+ }
+ } else {
+ for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6) {
+ /* R at R */
+ rgb[-1] = bayer[bayerStep2 + 2];
+ /* B at R */
+ t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
+ bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) << 1)
+ -
+ (((bayer[2] + bayer[bayerStep2] +
+ bayer[bayerStep2 + 4] + bayer[bayerStep4 +
+ 2]) * 3 + 1) >> 1)
+ + rgb[-1] * 6;
+ /* G at R */
+ t1 = ((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
+ bayer[bayerStep2 + 3] + bayer[bayerStep * 3 +
+ 2]) << 1)
+ - (bayer[2] + bayer[bayerStep2] +
+ bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
+ + (rgb[-1] << 2);
+ t0 = (t0 + 4) >> 3;
+ CLIP(t0, rgb[1]);
+ t1 = (t1 + 4) >> 3;
+ CLIP(t1, rgb[0]);
+
+ /* at green pixel */
+ rgb[3] = bayer[bayerStep2 + 3];
+ t0 = rgb[3] * 5
+ + ((bayer[bayerStep + 3] + bayer[bayerStep3 + 3]) << 2)
+ - bayer[3]
+ - bayer[bayerStep + 2]
+ - bayer[bayerStep + 4]
+ - bayer[bayerStep3 + 2]
+ - bayer[bayerStep3 + 4]
+ - bayer[bayerStep4 + 3]
+ +
+ ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 5] +
+ 1) >> 1);
+ t1 = rgb[3] * 5 +
+ ((bayer[bayerStep2 + 2] + bayer[bayerStep2 + 4]) << 2)
+ - bayer[bayerStep2 + 1]
+ - bayer[bayerStep + 2]
+ - bayer[bayerStep + 4]
+ - bayer[bayerStep3 + 2]
+ - bayer[bayerStep3 + 4]
+ - bayer[bayerStep2 + 5]
+ + ((bayer[3] + bayer[bayerStep4 + 3] + 1) >> 1);
+ t0 = (t0 + 4) >> 3;
+ CLIP(t0, rgb[4]);
+ t1 = (t1 + 4) >> 3;
+ CLIP(t1, rgb[2]);
+ }
+ }
+
+ if (bayer < bayerEnd) {
+ /* B at B */
+ rgb[blue] = bayer[bayerStep2 + 2];
+ /* R at B */
+ t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
+ bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) << 1)
+ -
+ (((bayer[2] + bayer[bayerStep2] +
+ bayer[bayerStep2 + 4] + bayer[bayerStep4 +
+ 2]) * 3 + 1) >> 1)
+ + rgb[blue] * 6;
+ /* G at B */
+ t1 = (((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
+ bayer[bayerStep2 + 3] + bayer[bayerStep3 + 2])) << 1)
+ - (bayer[2] + bayer[bayerStep2] +
+ bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
+ + (rgb[blue] << 2);
+ t0 = (t0 + 4) >> 3;
+ CLIP(t0, rgb[-blue]);
+ t1 = (t1 + 4) >> 3;
+ CLIP(t1, rgb[0]);
+ bayer++;
+ rgb += 3;
+ }
+
+ bayer -= width;
+ rgb -= width * 3;
+
+ blue = -blue;
+ start_with_green = !start_with_green;
+ }
+
+ return DC1394_SUCCESS;
+
+}
+
+/* coriander's Bayer decoding */
+/* Edge Sensing Interpolation II from http://www-ise.stanford.edu/~tingchen/ */
+/* (Laroche,Claude A. "Apparatus and method for adaptively
+ interpolating a full color image utilizing chrominance gradients"
+ U.S. Patent 5,373,322) */
+dc1394error_t
+dc1394_bayer_EdgeSense(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
+{
+ uint8_t *outR, *outG, *outB;
+ register int i3, j3, base;
+ int i, j;
+ int dh, dv;
+ int tmp;
+ int sx3=sx*3;
+
+ /* sx and sy should be even */
+ switch (tile) {
+ case DC1394_COLOR_FILTER_GRBG:
+ case DC1394_COLOR_FILTER_BGGR:
+ outR = &rgb[0];
+ outG = &rgb[1];
+ outB = &rgb[2];
+ break;
+ case DC1394_COLOR_FILTER_GBRG:
+ case DC1394_COLOR_FILTER_RGGB:
+ outR = &rgb[2];
+ outG = &rgb[1];
+ outB = &rgb[0];
+ break;
+ default:
+ return DC1394_INVALID_COLOR_FILTER;
+ }
+
+ switch (tile) {
+ case DC1394_COLOR_FILTER_GRBG:
+ case DC1394_COLOR_FILTER_GBRG:
+ /* copy original RGB data to output images */
+ for (i = 0, i3=0; i < sy*sx; i += (sx<<1), i3 += (sx3<<1)) {
+ for (j = 0, j3=0; j < sx; j += 2, j3+=6) {
+ base=i3+j3;
+ outG[base] = bayer[i + j];
+ outG[base + sx3 + 3] = bayer[i + j + sx + 1];
+ outR[base + 3] = bayer[i + j + 1];
+ outB[base + sx3] = bayer[i + j + sx];
+ }
+ }
+ /* process GREEN channel */
+ for (i3= 3*sx3; i3 < (sy - 2)*sx3; i3 += (sx3<<1)) {
+ for (j3=6; j3 < sx3 - 9; j3+=6) {
+ base=i3+j3;
+ dh = abs(((outB[base - 6] +
+ outB[base + 6]) >> 1) -
+ outB[base]);
+ dv = abs(((outB[base - (sx3<<1)] +
+ outB[base + (sx3<<1)]) >> 1) -
+ outB[base]);
+ tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh<=dv) +
+ ((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh>dv));
+ CLIP(tmp, outG[base]);
+ }
+ }
+
+ for (i3=2*sx3; i3 < (sy - 3)*sx3; i3 += (sx3<<1)) {
+ for (j3=9; j3 < sx3 - 6; j3+=6) {
+ base=i3+j3;
+ dh = abs(((outR[base - 6] +
+ outR[base + 6]) >>1 ) -
+ outR[base]);
+ dv = abs(((outR[base - (sx3<<1)] +
+ outR[base + (sx3<<1)]) >>1 ) -
+ outR[base]);
+ tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh<=dv) +
+ ((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh>dv));
+ CLIP(tmp, outG[base]);
+ }
+ }
+ /* process RED channel */
+ for (i3=0; i3 < (sy - 1)*sx3; i3 += (sx3<<1)) {
+ for (j3=6; j3 < sx3 - 3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - 3] -
+ outG[base - 3] +
+ outR[base + 3] -
+ outG[base + 3]) >> 1);
+ CLIP(tmp, outR[base]);
+ }
+ }
+ for (i3=sx3; i3 < (sy - 2)*sx3; i3 += (sx3<<1)) {
+ for (j3=3; j3 < sx3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - sx3] -
+ outG[base - sx3] +
+ outR[base + sx3] -
+ outG[base + sx3]) >> 1);
+ CLIP(tmp, outR[base]);
+ }
+ for (j3=6; j3 < sx3 - 3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - sx3 - 3] -
+ outG[base - sx3 - 3] +
+ outR[base - sx3 + 3] -
+ outG[base - sx3 + 3] +
+ outR[base + sx3 - 3] -
+ outG[base + sx3 - 3] +
+ outR[base + sx3 + 3] -
+ outG[base + sx3 + 3]) >> 2);
+ CLIP(tmp, outR[base]);
+ }
+ }
+
+ /* process BLUE channel */
+ for (i3=sx3; i3 < sy*sx3; i3 += (sx3<<1)) {
+ for (j3=3; j3 < sx3 - 6; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - 3] -
+ outG[base - 3] +
+ outB[base + 3] -
+ outG[base + 3]) >> 1);
+ CLIP(tmp, outB[base]);
+ }
+ }
+ for (i3=2*sx3; i3 < (sy - 1)*sx3; i3 += (sx3<<1)) {
+ for (j3=0; j3 < sx3 - 3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - sx3] -
+ outG[base - sx3] +
+ outB[base + sx3] -
+ outG[base + sx3]) >> 1);
+ CLIP(tmp, outB[base]);
+ }
+ for (j3=3; j3 < sx3 - 6; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - sx3 - 3] -
+ outG[base - sx3 - 3] +
+ outB[base - sx3 + 3] -
+ outG[base - sx3 + 3] +
+ outB[base + sx3 - 3] -
+ outG[base + sx3 - 3] +
+ outB[base + sx3 + 3] -
+ outG[base + sx3 + 3]) >> 2);
+ CLIP(tmp, outB[base]);
+ }
+ }
+ break;
+
+ case DC1394_COLOR_FILTER_BGGR:
+ case DC1394_COLOR_FILTER_RGGB:
+ /* copy original RGB data to output images */
+ for (i = 0, i3=0; i < sy*sx; i += (sx<<1), i3 += (sx3<<1)) {
+ for (j = 0, j3=0; j < sx; j += 2, j3+=6) {
+ base=i3+j3;
+ outB[base] = bayer[i + j];
+ outR[base + sx3 + 3] = bayer[i + sx + (j + 1)];
+ outG[base + 3] = bayer[i + j + 1];
+ outG[base + sx3] = bayer[i + sx + j];
+ }
+ }
+ /* process GREEN channel */
+ for (i3=2*sx3; i3 < (sy - 2)*sx3; i3 += (sx3<<1)) {
+ for (j3=6; j3 < sx3 - 9; j3+=6) {
+ base=i3+j3;
+ dh = abs(((outB[base - 6] +
+ outB[base + 6]) >> 1) -
+ outB[base]);
+ dv = abs(((outB[base - (sx3<<1)] +
+ outB[base + (sx3<<1)]) >> 1) -
+ outB[base]);
+ tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh<=dv) +
+ ((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh>dv));
+ CLIP(tmp, outG[base]);
+ }
+ }
+ for (i3=3*sx3; i3 < (sy - 3)*sx3; i3 += (sx3<<1)) {
+ for (j3=9; j3 < sx3 - 6; j3+=6) {
+ base=i3+j3;
+ dh = abs(((outR[base - 6] +
+ outR[base + 6]) >> 1) -
+ outR[base]);
+ dv = abs(((outR[base - (sx3<<1)] +
+ outR[base + (sx3<<1)]) >> 1) -
+ outR[base]);
+ tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh<=dv) +
+ ((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh>dv));
+ CLIP(tmp, outG[base]);
+ }
+ }
+ /* process RED channel */
+ for (i3=sx3; i3 < (sy - 1)*sx3; i3 += (sx3<<1)) { /* G-points (1/2) */
+ for (j3=6; j3 < sx3 - 3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - 3] -
+ outG[base - 3] +
+ outR[base + 3] -
+ outG[base + 3]) >>1);
+ CLIP(tmp, outR[base]);
+ }
+ }
+ for (i3=2*sx3; i3 < (sy - 2)*sx3; i3 += (sx3<<1)) {
+ for (j3=3; j3 < sx3; j3+=6) { /* G-points (2/2) */
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - sx3] -
+ outG[base - sx3] +
+ outR[base + sx3] -
+ outG[base + sx3]) >> 1);
+ CLIP(tmp, outR[base]);
+ }
+ for (j3=6; j3 < sx3 - 3; j3+=6) { /* B-points */
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - sx3 - 3] -
+ outG[base - sx3 - 3] +
+ outR[base - sx3 + 3] -
+ outG[base - sx3 + 3] +
+ outR[base + sx3 - 3] -
+ outG[base + sx3 - 3] +
+ outR[base + sx3 + 3] -
+ outG[base + sx3 + 3]) >> 2);
+ CLIP(tmp, outR[base]);
+ }
+ }
+
+ /* process BLUE channel */
+ for (i = 0,i3=0; i < sy*sx; i += (sx<<1), i3 += (sx3<<1)) {
+ for (j = 1, j3=3; j < sx - 2; j += 2, j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - 3] -
+ outG[base - 3] +
+ outB[base + 3] -
+ outG[base + 3]) >> 1);
+ CLIP(tmp, outB[base]);
+ }
+ }
+ for (i3=sx3; i3 < (sy - 1)*sx3; i3 += (sx3<<1)) {
+ for (j3=0; j3 < sx3 - 3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - sx3] -
+ outG[base - sx3] +
+ outB[base + sx3] -
+ outG[base + sx3]) >> 1);
+ CLIP(tmp, outB[base]);
+ }
+ for (j3=3; j3 < sx3 - 6; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - sx3 - 3] -
+ outG[base - sx3 - 3] +
+ outB[base - sx3 + 3] -
+ outG[base - sx3 + 3] +
+ outB[base + sx3 - 3] -
+ outG[base + sx3 - 3] +
+ outB[base + sx3 + 3] -
+ outG[base + sx3 + 3]) >> 2);
+ CLIP(tmp, outB[base]);
+ }
+ }
+ break;
+ }
+
+ ClearBorders(rgb, sx, sy, 3);
+
+ return DC1394_SUCCESS;
+}
+
+/* coriander's Bayer decoding */
+dc1394error_t
+dc1394_bayer_Downsample(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
+{
+ uint8_t *outR, *outG, *outB;
+ register int i, j;
+ int tmp;
+
+ switch (tile) {
+ case DC1394_COLOR_FILTER_GRBG:
+ case DC1394_COLOR_FILTER_BGGR:
+ outR = &rgb[0];
+ outG = &rgb[1];
+ outB = &rgb[2];
+ break;
+ case DC1394_COLOR_FILTER_GBRG:
+ case DC1394_COLOR_FILTER_RGGB:
+ outR = &rgb[2];
+ outG = &rgb[1];
+ outB = &rgb[0];
+ break;
+ default:
+ return DC1394_INVALID_COLOR_FILTER;
+ }
+
+ switch (tile) {
+ case DC1394_COLOR_FILTER_GRBG:
+ case DC1394_COLOR_FILTER_GBRG:
+ for (i = 0; i < sy*sx; i += (sx<<1)) {
+ for (j = 0; j < sx; j += 2) {
+ tmp = ((bayer[i + j] + bayer[i + sx + j + 1]) >> 1);
+ CLIP(tmp, outG[((i >> 2) + (j >> 1)) * 3]);
+ tmp = bayer[i + j + 1];
+ CLIP(tmp, outR[((i >> 2) + (j >> 1)) * 3]);
+ tmp = bayer[i + sx + j];
+ CLIP(tmp, outB[((i >> 2) + (j >> 1)) * 3]);
+ }
+ }
+ break;
+ case DC1394_COLOR_FILTER_BGGR:
+ case DC1394_COLOR_FILTER_RGGB:
+ for (i = 0; i < sy*sx; i += (sx<<1)) {
+ for (j = 0; j < sx; j += 2) {
+ tmp = ((bayer[i + sx + j] + bayer[i + j + 1]) >> 1);
+ CLIP(tmp, outG[((i >> 2) + (j >> 1)) * 3]);
+ tmp = bayer[i + sx + j + 1];
+ CLIP(tmp, outR[((i >> 2) + (j >> 1)) * 3]);
+ tmp = bayer[i + j];
+ CLIP(tmp, outB[((i >> 2) + (j >> 1)) * 3]);
+ }
+ }
+ break;
+ }
+
+ return DC1394_SUCCESS;
+
+}
+
+/* this is the method used inside AVT cameras. See AVT docs. */
+dc1394error_t
+dc1394_bayer_Simple(const uint8_t *restrict bayer, uint8_t *restrict rgb, int sx, int sy, int tile)
+{
+ const int bayerStep = sx;
+ const int rgbStep = 3 * sx;
+ int width = sx;
+ int height = sy;
+ int blue = tile == DC1394_COLOR_FILTER_BGGR
+ || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
+ int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
+ || tile == DC1394_COLOR_FILTER_GRBG;
+ int i, imax, iinc;
+
+ if ((tile>DC1394_COLOR_FILTER_MAX)||(tile<DC1394_COLOR_FILTER_MIN))
+ return DC1394_INVALID_COLOR_FILTER;
+
+ /* add black border */
imax = sx * sy * 3;
for (i = sx * (sy - 1) * 3; i < imax; i++) {
rgb[i] = 0;
@@ -100,23 +855,98 @@ dc1394_bayer_NearestNeighbor_float(const float * bayer, float * rgb, int sx, int
}
rgb += 1;
- height -= 1;
width -= 1;
+ height -= 1;
- if (offsetY == 1)
- {
- bayer += bayerStep;
- height--;
+ for (; height--; bayer += bayerStep, rgb += rgbStep) {
+ const uint8_t *bayerEnd = bayer + width;
+
+ if (start_with_green) {
+ rgb[-blue] = bayer[1];
+ rgb[0] = (bayer[0] + bayer[bayerStep + 1] + 1) >> 1;
+ rgb[blue] = bayer[bayerStep];
+ bayer++;
+ rgb += 3;
+ }
+
+ if (blue > 0) {
+ for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6) {
+ rgb[-1] = bayer[0];
+ rgb[0] = (bayer[1] + bayer[bayerStep] + 1) >> 1;
+ rgb[1] = bayer[bayerStep + 1];
+
+ rgb[2] = bayer[2];
+ rgb[3] = (bayer[1] + bayer[bayerStep + 2] + 1) >> 1;
+ rgb[4] = bayer[bayerStep + 1];
+ }
+ } else {
+ for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6) {
+ rgb[1] = bayer[0];
+ rgb[0] = (bayer[1] + bayer[bayerStep] + 1) >> 1;
+ rgb[-1] = bayer[bayerStep + 1];
+
+ rgb[4] = bayer[2];
+ rgb[3] = (bayer[1] + bayer[bayerStep + 2] + 1) >> 1;
+ rgb[2] = bayer[bayerStep + 1];
+ }
+ }
+
+ if (bayer < bayerEnd) {
+ rgb[-blue] = bayer[0];
+ rgb[0] = (bayer[1] + bayer[bayerStep] + 1) >> 1;
+ rgb[blue] = bayer[bayerStep + 1];
+ bayer++;
+ rgb += 3;
+ }
+
+ bayer -= width;
+ rgb -= width * 3;
+
+ blue = -blue;
+ start_with_green = !start_with_green;
}
- if (offsetX == 1)
- {
- bayer++;
+ return DC1394_SUCCESS;
+
+}
+
+/* 16-bits versions */
+
+/* insprired by OpenCV's Bayer decoding */
+dc1394error_t
+dc1394_bayer_NearestNeighbor_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
+{
+ const int bayerStep = sx;
+ const int rgbStep = 3 * sx;
+ int width = sx;
+ int height = sy;
+ int blue = tile == DC1394_COLOR_FILTER_BGGR
+ || tile == DC1394_COLOR_FILTER_GBRG ? -1 : 1;
+ int start_with_green = tile == DC1394_COLOR_FILTER_GBRG
+ || tile == DC1394_COLOR_FILTER_GRBG;
+ int i, iinc, imax;
+
+ if ((tile>DC1394_COLOR_FILTER_MAX)||(tile<DC1394_COLOR_FILTER_MIN))
+ return DC1394_INVALID_COLOR_FILTER;
+
+ /* add black border */
+ imax = sx * sy * 3;
+ for (i = sx * (sy - 1) * 3; i < imax; i++) {
+ rgb[i] = 0;
+ }
+ iinc = (sx - 1) * 3;
+ for (i = (sx - 1) * 3; i < imax; i += iinc) {
+ rgb[i++] = 0;
+ rgb[i++] = 0;
+ rgb[i++] = 0;
}
+ rgb += 1;
+ height -= 1;
+ width -= 1;
+
for (; height--; bayer += bayerStep, rgb += rgbStep) {
- /*int t0, t1;*/
- const float *bayerEnd = bayer + width;
+ const uint16_t *bayerEnd = bayer + width;
if (start_with_green) {
rgb[-blue] = bayer[1];
@@ -168,7 +998,7 @@ dc1394_bayer_NearestNeighbor_float(const float * bayer, float * rgb, int sx, int
}
/* OpenCV's Bayer decoding */
dc1394error_t
-dc1394_bayer_Bilinear_float(const float * bayer, float * rgb, int sx, int sy, int offsetX, int offsetY, dc1394color_filter_t tile)
+dc1394_bayer_Bilinear_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
{
const int bayerStep = sx;
const int rgbStep = 3 * sx;
@@ -186,29 +1016,18 @@ dc1394_bayer_Bilinear_float(const float * bayer, float * rgb, int sx, int sy, in
height -= 2;
width -= 2;
- if (offsetY == 1)
- {
- bayer += bayerStep;
- height--;
- }
-
- if (offsetX == 1)
- {
- bayer++;
- }
-
for (; height--; bayer += bayerStep, rgb += rgbStep) {
int t0, t1;
- const float *bayerEnd = bayer + width;
+ const uint16_t *bayerEnd = bayer + width;
if (start_with_green) {
/* OpenCV has a bug in the next line, which was
- t0 = (bayer[0] + bayer[bayerStep * 2] + 1) / 2; */
- t0 = (bayer[1] + bayer[bayerStep * 2 + 1] + 1) / 2;
- t1 = (bayer[bayerStep] + bayer[bayerStep + 2] + 1) / 2;
- rgb[-blue] = (float) t0;
+ t0 = (bayer[0] + bayer[bayerStep * 2] + 1) >> 1; */
+ t0 = (bayer[1] + bayer[bayerStep * 2 + 1] + 1) >> 1;
+ t1 = (bayer[bayerStep] + bayer[bayerStep + 2] + 1) >> 1;
+ rgb[-blue] = (uint16_t) t0;
rgb[0] = bayer[bayerStep + 1];
- rgb[blue] = (float) t1;
+ rgb[blue] = (uint16_t) t1;
bayer++;
rgb += 3;
}
@@ -216,49 +1035,49 @@ dc1394_bayer_Bilinear_float(const float * bayer, float * rgb, int sx, int sy, in
if (blue > 0) {
for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6) {
t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
- bayer[bayerStep * 2 + 2] + 2) / 4;
+ bayer[bayerStep * 2 + 2] + 2) >> 2;
t1 = (bayer[1] + bayer[bayerStep] +
bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
- 2) / 4;
- rgb[-1] = (float) t0;
- rgb[0] = (float) t1;
+ 2) >> 2;
+ rgb[-1] = (uint16_t) t0;
+ rgb[0] = (uint16_t) t1;
rgb[1] = bayer[bayerStep + 1];
- t0 = (bayer[2] + bayer[bayerStep * 2 + 2] + 1) / 2;
+ t0 = (bayer[2] + bayer[bayerStep * 2 + 2] + 1) >> 1;
t1 = (bayer[bayerStep + 1] + bayer[bayerStep + 3] +
- 1) / 2;
- rgb[2] = (float) t0;
+ 1) >> 1;
+ rgb[2] = (uint16_t) t0;
rgb[3] = bayer[bayerStep + 2];
- rgb[4] = (float) t1;
+ rgb[4] = (uint16_t) t1;
}
} else {
for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6) {
t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
- bayer[bayerStep * 2 + 2] + 2) / 4;
+ bayer[bayerStep * 2 + 2] + 2) >> 2;
t1 = (bayer[1] + bayer[bayerStep] +
bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
- 2) / 4;
- rgb[1] = (float) t0;
- rgb[0] = (float) t1;
+ 2) >> 2;
+ rgb[1] = (uint16_t) t0;
+ rgb[0] = (uint16_t) t1;
rgb[-1] = bayer[bayerStep + 1];
- t0 = (bayer[2] + bayer[bayerStep * 2 + 2] + 1) / 2;
+ t0 = (bayer[2] + bayer[bayerStep * 2 + 2] + 1) >> 1;
t1 = (bayer[bayerStep + 1] + bayer[bayerStep + 3] +
- 1) / 2;
- rgb[4] = (float) t0;
+ 1) >> 1;
+ rgb[4] = (uint16_t) t0;
rgb[3] = bayer[bayerStep + 2];
- rgb[2] = (float) t1;
+ rgb[2] = (uint16_t) t1;
}
}
if (bayer < bayerEnd) {
t0 = (bayer[0] + bayer[2] + bayer[bayerStep * 2] +
- bayer[bayerStep * 2 + 2] + 2) / 4;
+ bayer[bayerStep * 2 + 2] + 2) >> 2;
t1 = (bayer[1] + bayer[bayerStep] +
bayer[bayerStep + 2] + bayer[bayerStep * 2 + 1] +
- 2) / 4;
- rgb[-blue] = (float) t0;
- rgb[0] = (float) t1;
+ 2) >> 2;
+ rgb[-blue] = (uint16_t) t0;
+ rgb[0] = (uint16_t) t1;
rgb[blue] = bayer[bayerStep + 1];
bayer++;
rgb += 3;
@@ -279,7 +1098,7 @@ dc1394_bayer_Bilinear_float(const float * bayer, float * rgb, int sx, int sy, in
Bayer-Patterned Color Images, by Henrique S. Malvar, Li-wei He, and
Ross Cutler, in ICASSP'04 */
dc1394error_t
-dc1394_bayer_HQLinear_float(const float * bayer, float * rgb, int sx, int sy, int offsetX, int offsetY, dc1394color_filter_t tile)
+dc1394_bayer_HQLinear_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
{
const int bayerStep = sx;
const int rgbStep = 3 * sx;
@@ -305,28 +1124,17 @@ dc1394_bayer_HQLinear_float(const float * bayer, float * rgb, int sx, int sy, in
if ((tile>DC1394_COLOR_FILTER_MAX)||(tile<DC1394_COLOR_FILTER_MIN))
return DC1394_INVALID_COLOR_FILTER;
- ClearBorders_float(rgb, sx, sy, 2);
+ ClearBorders_uint16(rgb, sx, sy, 2);
rgb += 2 * rgbStep + 6 + 1;
height -= 4;
width -= 4;
- if (offsetY == 1)
- {
- bayer += bayerStep;
- height--;
- }
-
- if (offsetX == 1)
- {
- bayer++;
- }
-
/* We begin with a (+1 line,+1 column) offset with respect to bilinear decoding, so start_with_green is the same, but blue is opposite */
blue = -blue;
for (; height--; bayer += bayerStep, rgb += rgbStep) {
int t0, t1;
- const float *bayerEnd = bayer + width;
+ const uint16_t *bayerEnd = bayer + width;
const int bayerStep2 = bayerStep * 2;
const int bayerStep3 = bayerStep * 3;
const int bayerStep4 = bayerStep * 4;
@@ -335,27 +1143,27 @@ dc1394_bayer_HQLinear_float(const float * bayer, float * rgb, int sx, int sy, in
/* at green pixel */
rgb[0] = bayer[bayerStep2 + 2];
t0 = rgb[0] * 5
- + ((bayer[bayerStep + 2] + bayer[bayerStep3 + 2]) * 4)
+ + ((bayer[bayerStep + 2] + bayer[bayerStep3 + 2]) << 2)
- bayer[2]
- bayer[bayerStep + 1]
- bayer[bayerStep + 3]
- bayer[bayerStep3 + 1]
- bayer[bayerStep3 + 3]
- bayer[bayerStep4 + 2]
- + ((bayer[bayerStep2] + bayer[bayerStep2 + 4] + 1) / 2);
+ + ((bayer[bayerStep2] + bayer[bayerStep2 + 4] + 1) >> 1);
t1 = rgb[0] * 5 +
- ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 3]) * 4)
+ ((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 3]) << 2)
- bayer[bayerStep2]
- bayer[bayerStep + 1]
- bayer[bayerStep + 3]
- bayer[bayerStep3 + 1]
- bayer[bayerStep3 + 3]
- bayer[bayerStep2 + 4]
- + ((bayer[2] + bayer[bayerStep4 + 2] + 1) / 2);
+ + ((bayer[2] + bayer[bayerStep4 + 2] + 1) >> 1);
t0 = (t0 + 4) >> 3;
- CLIP_FLOAT(t0, rgb[-blue]);
+ CLIP16(t0, rgb[-blue], bits);
t1 = (t1 + 4) >> 3;
- CLIP_FLOAT(t1, rgb[blue]);
+ CLIP16(t1, rgb[blue], bits);
bayer++;
rgb += 3;
}
@@ -366,27 +1174,27 @@ dc1394_bayer_HQLinear_float(const float * bayer, float * rgb, int sx, int sy, in
rgb[1] = bayer[bayerStep2 + 2];
/* R at B */
t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
- bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) * 2)
+ bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) << 1)
-
(((bayer[2] + bayer[bayerStep2] +
bayer[bayerStep2 + 4] + bayer[bayerStep4 +
- 2]) * 3 + 1) / 2)
+ 2]) * 3 + 1) >> 1)
+ rgb[1] * 6;
/* G at B */
t1 = ((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
bayer[bayerStep2 + 3] + bayer[bayerStep * 3 +
- 2]) * 2)
+ 2]) << 1)
- (bayer[2] + bayer[bayerStep2] +
bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
- + (rgb[1] * 4);
+ + (rgb[1] << 2);
t0 = (t0 + 4) >> 3;
- CLIP_FLOAT(t0, rgb[-1]);
+ CLIP16(t0, rgb[-1], bits);
t1 = (t1 + 4) >> 3;
- CLIP_FLOAT(t1, rgb[0]);
+ CLIP16(t1, rgb[0], bits);
/* at green pixel */
rgb[3] = bayer[bayerStep2 + 3];
t0 = rgb[3] * 5
- + ((bayer[bayerStep + 3] + bayer[bayerStep3 + 3]) * 4)
+ + ((bayer[bayerStep + 3] + bayer[bayerStep3 + 3]) << 2)
- bayer[3]
- bayer[bayerStep + 2]
- bayer[bayerStep + 4]
@@ -395,20 +1203,20 @@ dc1394_bayer_HQLinear_float(const float * bayer, float * rgb, int sx, int sy, in
- bayer[bayerStep4 + 3]
+
((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 5] +
- 1) / 2);
+ 1) >> 1);
t1 = rgb[3] * 5 +
- ((bayer[bayerStep2 + 2] + bayer[bayerStep2 + 4]) * 4)
+ ((bayer[bayerStep2 + 2] + bayer[bayerStep2 + 4]) << 2)
- bayer[bayerStep2 + 1]
- bayer[bayerStep + 2]
- bayer[bayerStep + 4]
- bayer[bayerStep3 + 2]
- bayer[bayerStep3 + 4]
- bayer[bayerStep2 + 5]
- + ((bayer[3] + bayer[bayerStep4 + 3] + 1) / 2);
+ + ((bayer[3] + bayer[bayerStep4 + 3] + 1) >> 1);
t0 = (t0 + 4) >> 3;
- CLIP_FLOAT(t0, rgb[2]);
+ CLIP16(t0, rgb[2], bits);
t1 = (t1 + 4) >> 3;
- CLIP_FLOAT(t1, rgb[4]);
+ CLIP16(t1, rgb[4], bits);
}
} else {
for (; bayer <= bayerEnd - 2; bayer += 2, rgb += 6) {
@@ -417,27 +1225,27 @@ dc1394_bayer_HQLinear_float(const float * bayer, float * rgb, int sx, int sy, in
/* B at R */
t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
bayer[bayerStep * 3 + 1] + bayer[bayerStep3 +
- 3]) * 2)
+ 3]) << 1)
-
(((bayer[2] + bayer[bayerStep2] +
bayer[bayerStep2 + 4] + bayer[bayerStep4 +
- 2]) * 3 + 1) / 2)
+ 2]) * 3 + 1) >> 1)
+ rgb[-1] * 6;
/* G at R */
t1 = ((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
- bayer[bayerStep2 + 3] + bayer[bayerStep3 + 2]) * 2)
+ bayer[bayerStep2 + 3] + bayer[bayerStep3 + 2]) << 1)
- (bayer[2] + bayer[bayerStep2] +
bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
- + (rgb[-1] * 4);
+ + (rgb[-1] << 2);
t0 = (t0 + 4) >> 3;
- CLIP_FLOAT(t0, rgb[1]);
+ CLIP16(t0, rgb[1], bits);
t1 = (t1 + 4) >> 3;
- CLIP_FLOAT(t1, rgb[0]);
+ CLIP16(t1, rgb[0], bits);
/* at green pixel */
rgb[3] = bayer[bayerStep2 + 3];
t0 = rgb[3] * 5
- + ((bayer[bayerStep + 3] + bayer[bayerStep3 + 3]) * 4)
+ + ((bayer[bayerStep + 3] + bayer[bayerStep3 + 3]) << 2)
- bayer[3]
- bayer[bayerStep + 2]
- bayer[bayerStep + 4]
@@ -446,20 +1254,20 @@ dc1394_bayer_HQLinear_float(const float * bayer, float * rgb, int sx, int sy, in
- bayer[bayerStep4 + 3]
+
((bayer[bayerStep2 + 1] + bayer[bayerStep2 + 5] +
- 1) / 2);
+ 1) >> 1);
t1 = rgb[3] * 5 +
- ((bayer[bayerStep2 + 2] + bayer[bayerStep2 + 4]) * 4)
+ ((bayer[bayerStep2 + 2] + bayer[bayerStep2 + 4]) << 2)
- bayer[bayerStep2 + 1]
- bayer[bayerStep + 2]
- bayer[bayerStep + 4]
- bayer[bayerStep3 + 2]
- bayer[bayerStep3 + 4]
- bayer[bayerStep2 + 5]
- + ((bayer[3] + bayer[bayerStep4 + 3] + 1) / 2);
+ + ((bayer[3] + bayer[bayerStep4 + 3] + 1) >> 1);
t0 = (t0 + 4) >> 3;
- CLIP_FLOAT(t0, rgb[4]);
+ CLIP16(t0, rgb[4], bits);
t1 = (t1 + 4) >> 3;
- CLIP_FLOAT(t1, rgb[2]);
+ CLIP16(t1, rgb[2], bits);
}
}
@@ -468,22 +1276,22 @@ dc1394_bayer_HQLinear_float(const float * bayer, float * rgb, int sx, int sy, in
rgb[blue] = bayer[bayerStep2 + 2];
/* R at B */
t0 = ((bayer[bayerStep + 1] + bayer[bayerStep + 3] +
- bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) * 2)
+ bayer[bayerStep3 + 1] + bayer[bayerStep3 + 3]) << 1)
-
(((bayer[2] + bayer[bayerStep2] +
bayer[bayerStep2 + 4] + bayer[bayerStep4 +
- 2]) * 3 + 1) / 2)
+ 2]) * 3 + 1) >> 1)
+ rgb[blue] * 6;
/* G at B */
t1 = (((bayer[bayerStep + 2] + bayer[bayerStep2 + 1] +
- bayer[bayerStep2 + 3] + bayer[bayerStep3 + 2])) * 2)
+ bayer[bayerStep2 + 3] + bayer[bayerStep3 + 2])) << 1)
- (bayer[2] + bayer[bayerStep2] +
bayer[bayerStep2 + 4] + bayer[bayerStep4 + 2])
- + (rgb[blue] * 4);
+ + (rgb[blue] << 2);
t0 = (t0 + 4) >> 3;
- CLIP_FLOAT(t0, rgb[-blue]);
+ CLIP16(t0, rgb[-blue], bits);
t1 = (t1 + 4) >> 3;
- CLIP_FLOAT(t1, rgb[0]);
+ CLIP16(t1, rgb[0], bits);
bayer++;
rgb += 3;
}
@@ -500,13 +1308,342 @@ dc1394_bayer_HQLinear_float(const float * bayer, float * rgb, int sx, int sy, in
/* coriander's Bayer decoding */
dc1394error_t
-dc1394_bayer_Simple_float(const float * bayer, float * rgb, int sx, int sy, int offsetX, int offsetY, dc1394color_filter_t tile)
+dc1394_bayer_EdgeSense_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
+{
+ uint16_t *outR, *outG, *outB;
+ register int i3, j3, base;
+ int i, j;
+ int dh, dv;
+ int tmp;
+ int sx3=sx*3;
+
+ /* sx and sy should be even */
+ switch (tile) {
+ case DC1394_COLOR_FILTER_GRBG:
+ case DC1394_COLOR_FILTER_BGGR:
+ outR = &rgb[0];
+ outG = &rgb[1];
+ outB = &rgb[2];
+ break;
+ case DC1394_COLOR_FILTER_GBRG:
+ case DC1394_COLOR_FILTER_RGGB:
+ outR = &rgb[2];
+ outG = &rgb[1];
+ outB = &rgb[0];
+ break;
+ default:
+ return DC1394_INVALID_COLOR_FILTER;
+ }
+
+ switch (tile) {
+ case DC1394_COLOR_FILTER_GRBG:
+ case DC1394_COLOR_FILTER_GBRG:
+ /* copy original RGB data to output images */
+ for (i = 0, i3=0; i < sy*sx; i += (sx<<1), i3 += (sx3<<1)) {
+ for (j = 0, j3=0; j < sx; j += 2, j3+=6) {
+ base=i3+j3;
+ outG[base] = bayer[i + j];
+ outG[base + sx3 + 3] = bayer[i + j + sx + 1];
+ outR[base + 3] = bayer[i + j + 1];
+ outB[base + sx3] = bayer[i + j + sx];
+ }
+ }
+ /* process GREEN channel */
+ for (i3= 3*sx3; i3 < (sy - 2)*sx3; i3 += (sx3<<1)) {
+ for (j3=6; j3 < sx3 - 9; j3+=6) {
+ base=i3+j3;
+ dh = abs(((outB[base - 6] +
+ outB[base + 6]) >> 1) -
+ outB[base]);
+ dv = abs(((outB[base - (sx3<<1)] +
+ outB[base + (sx3<<1)]) >> 1) -
+ outB[base]);
+ tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh<=dv) +
+ ((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh>dv));
+ CLIP16(tmp, outG[base], bits);
+ }
+ }
+
+ for (i3=2*sx3; i3 < (sy - 3)*sx3; i3 += (sx3<<1)) {
+ for (j3=9; j3 < sx3 - 6; j3+=6) {
+ base=i3+j3;
+ dh = abs(((outR[base - 6] +
+ outR[base + 6]) >>1 ) -
+ outR[base]);
+ dv = abs(((outR[base - (sx3<<1)] +
+ outR[base + (sx3<<1)]) >>1 ) -
+ outR[base]);
+ tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh<=dv) +
+ ((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh>dv));
+ CLIP16(tmp, outG[base], bits);
+ }
+ }
+ /* process RED channel */
+ for (i3=0; i3 < (sy - 1)*sx3; i3 += (sx3<<1)) {
+ for (j3=6; j3 < sx3 - 3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - 3] -
+ outG[base - 3] +
+ outR[base + 3] -
+ outG[base + 3]) >> 1);
+ CLIP16(tmp, outR[base], bits);
+ }
+ }
+ for (i3=sx3; i3 < (sy - 2)*sx3; i3 += (sx3<<1)) {
+ for (j3=3; j3 < sx3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - sx3] -
+ outG[base - sx3] +
+ outR[base + sx3] -
+ outG[base + sx3]) >> 1);
+ CLIP16(tmp, outR[base], bits);
+ }
+ for (j3=6; j3 < sx3 - 3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - sx3 - 3] -
+ outG[base - sx3 - 3] +
+ outR[base - sx3 + 3] -
+ outG[base - sx3 + 3] +
+ outR[base + sx3 - 3] -
+ outG[base + sx3 - 3] +
+ outR[base + sx3 + 3] -
+ outG[base + sx3 + 3]) >> 2);
+ CLIP16(tmp, outR[base], bits);
+ }
+ }
+
+ /* process BLUE channel */
+ for (i3=sx3; i3 < sy*sx3; i3 += (sx3<<1)) {
+ for (j3=3; j3 < sx3 - 6; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - 3] -
+ outG[base - 3] +
+ outB[base + 3] -
+ outG[base + 3]) >> 1);
+ CLIP16(tmp, outB[base], bits);
+ }
+ }
+ for (i3=2*sx3; i3 < (sy - 1)*sx3; i3 += (sx3<<1)) {
+ for (j3=0; j3 < sx3 - 3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - sx3] -
+ outG[base - sx3] +
+ outB[base + sx3] -
+ outG[base + sx3]) >> 1);
+ CLIP16(tmp, outB[base], bits);
+ }
+ for (j3=3; j3 < sx3 - 6; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - sx3 - 3] -
+ outG[base - sx3 - 3] +
+ outB[base - sx3 + 3] -
+ outG[base - sx3 + 3] +
+ outB[base + sx3 - 3] -
+ outG[base + sx3 - 3] +
+ outB[base + sx3 + 3] -
+ outG[base + sx3 + 3]) >> 2);
+ CLIP16(tmp, outB[base], bits);
+ }
+ }
+ break;
+
+ case DC1394_COLOR_FILTER_BGGR:
+ case DC1394_COLOR_FILTER_RGGB:
+ /* copy original RGB data to output images */
+ for (i = 0, i3=0; i < sy*sx; i += (sx<<1), i3 += (sx3<<1)) {
+ for (j = 0, j3=0; j < sx; j += 2, j3+=6) {
+ base=i3+j3;
+ outB[base] = bayer[i + j];
+ outR[base + sx3 + 3] = bayer[i + sx + (j + 1)];
+ outG[base + 3] = bayer[i + j + 1];
+ outG[base + sx3] = bayer[i + sx + j];
+ }
+ }
+ /* process GREEN channel */
+ for (i3=2*sx3; i3 < (sy - 2)*sx3; i3 += (sx3<<1)) {
+ for (j3=6; j3 < sx3 - 9; j3+=6) {
+ base=i3+j3;
+ dh = abs(((outB[base - 6] +
+ outB[base + 6]) >> 1) -
+ outB[base]);
+ dv = abs(((outB[base - (sx3<<1)] +
+ outB[base + (sx3<<1)]) >> 1) -
+ outB[base]);
+ tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh<=dv) +
+ ((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh>dv));
+ CLIP16(tmp, outG[base], bits);
+ }
+ }
+ for (i3=3*sx3; i3 < (sy - 3)*sx3; i3 += (sx3<<1)) {
+ for (j3=9; j3 < sx3 - 6; j3+=6) {
+ base=i3+j3;
+ dh = abs(((outR[base - 6] +
+ outR[base + 6]) >> 1) -
+ outR[base]);
+ dv = abs(((outR[base - (sx3<<1)] +
+ outR[base + (sx3<<1)]) >> 1) -
+ outR[base]);
+ tmp = (((outG[base - 3] + outG[base + 3]) >> 1) * (dh<=dv) +
+ ((outG[base - sx3] + outG[base + sx3]) >> 1) * (dh>dv));
+ CLIP16(tmp, outG[base], bits);
+ }
+ }
+ /* process RED channel */
+ for (i3=sx3; i3 < (sy - 1)*sx3; i3 += (sx3<<1)) { /* G-points (1/2) */
+ for (j3=6; j3 < sx3 - 3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - 3] -
+ outG[base - 3] +
+ outR[base + 3] -
+ outG[base + 3]) >>1);
+ CLIP16(tmp, outR[base], bits);
+ }
+ }
+ for (i3=2*sx3; i3 < (sy - 2)*sx3; i3 += (sx3<<1)) {
+ for (j3=3; j3 < sx3; j3+=6) { /* G-points (2/2) */
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - sx3] -
+ outG[base - sx3] +
+ outR[base + sx3] -
+ outG[base + sx3]) >> 1);
+ CLIP16(tmp, outR[base], bits);
+ }
+ for (j3=6; j3 < sx3 - 3; j3+=6) { /* B-points */
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outR[base - sx3 - 3] -
+ outG[base - sx3 - 3] +
+ outR[base - sx3 + 3] -
+ outG[base - sx3 + 3] +
+ outR[base + sx3 - 3] -
+ outG[base + sx3 - 3] +
+ outR[base + sx3 + 3] -
+ outG[base + sx3 + 3]) >> 2);
+ CLIP16(tmp, outR[base], bits);
+ }
+ }
+
+ /* process BLUE channel */
+ for (i = 0,i3=0; i < sy*sx; i += (sx<<1), i3 += (sx3<<1)) {
+ for (j = 1, j3=3; j < sx - 2; j += 2, j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - 3] -
+ outG[base - 3] +
+ outB[base + 3] -
+ outG[base + 3]) >> 1);
+ CLIP16(tmp, outB[base], bits);
+ }
+ }
+ for (i3=sx3; i3 < (sy - 1)*sx3; i3 += (sx3<<1)) {
+ for (j3=0; j3 < sx3 - 3; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - sx3] -
+ outG[base - sx3] +
+ outB[base + sx3] -
+ outG[base + sx3]) >> 1);
+ CLIP16(tmp, outB[base], bits);
+ }
+ for (j3=3; j3 < sx3 - 6; j3+=6) {
+ base=i3+j3;
+ tmp = outG[base] +
+ ((outB[base - sx3 - 3] -
+ outG[base - sx3 - 3] +
+ outB[base - sx3 + 3] -
+ outG[base - sx3 + 3] +
+ outB[base + sx3 - 3] -
+ outG[base + sx3 - 3] +
+ outB[base + sx3 + 3] -
+ outG[base + sx3 + 3]) >> 2);
+ CLIP16(tmp, outB[base], bits);
+ }
+ }
+ break;
+ }
+
+ ClearBorders_uint16(rgb, sx, sy, 3);
+
+ return DC1394_SUCCESS;
+}
+
+/* coriander's Bayer decoding */
+dc1394error_t
+dc1394_bayer_Downsample_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
+{
+ uint16_t *outR, *outG, *outB;
+ register int i, j;
+ int tmp;
+
+ switch (tile) {
+ case DC1394_COLOR_FILTER_GRBG:
+ case DC1394_COLOR_FILTER_BGGR:
+ outR = &rgb[0];
+ outG = &rgb[1];
+ outB = &rgb[2];
+ break;
+ case DC1394_COLOR_FILTER_GBRG:
+ case DC1394_COLOR_FILTER_RGGB:
+ outR = &rgb[2];
+ outG = &rgb[1];
+ outB = &rgb[0];
+ break;
+ default:
+ return DC1394_INVALID_COLOR_FILTER;
+ }
+
+ switch (tile) {
+ case DC1394_COLOR_FILTER_GRBG:
+ case DC1394_COLOR_FILTER_GBRG:
+ for (i = 0; i < sy*sx; i += (sx<<1)) {
+ for (j = 0; j < sx; j += 2) {
+ tmp =
+ ((bayer[i + j] + bayer[i + sx + j + 1]) >> 1);
+ CLIP16(tmp, outG[((i >> 2) + (j >> 1)) * 3], bits);
+ tmp = bayer[i + sx + j + 1];
+ CLIP16(tmp, outR[((i >> 2) + (j >> 1)) * 3], bits);
+ tmp = bayer[i + sx + j];
+ CLIP16(tmp, outB[((i >> 2) + (j >> 1)) * 3], bits);
+ }
+ }
+ break;
+ case DC1394_COLOR_FILTER_BGGR:
+ case DC1394_COLOR_FILTER_RGGB:
+ for (i = 0; i < sy*sx; i += (sx<<1)) {
+ for (j = 0; j < sx; j += 2) {
+ tmp =
+ ((bayer[i + sx + j] + bayer[i + j + 1]) >> 1);
+ CLIP16(tmp, outG[((i >> 2) + (j >> 1)) * 3], bits);
+ tmp = bayer[i + sx + j + 1];
+ CLIP16(tmp, outR[((i >> 2) + (j >> 1)) * 3], bits);
+ tmp = bayer[i + j];
+ CLIP16(tmp, outB[((i >> 2) + (j >> 1)) * 3], bits);
+ }
+ }
+ break;
+ }
+
+ return DC1394_SUCCESS;
+
+}
+
+/* coriander's Bayer decoding */
+dc1394error_t
+dc1394_bayer_Simple_uint16(const uint16_t *restrict bayer, uint16_t *restrict rgb, int sx, int sy, int tile, int bits)
{
- float *outR, *outG, *outB;
+ uint16_t *outR, *outG, *outB;
register int i, j;
int tmp, base;
- /* sx and sy should be even*/
+ /* sx and sy should be even */
switch (tile) {
case DC1394_COLOR_FILTER_GRBG:
case DC1394_COLOR_FILTER_BGGR:
@@ -550,45 +1687,45 @@ dc1394_bayer_Simple_float(const float * bayer, float * rgb, int sx, int sy, int
for (i = 0; i < sy - 1; i += 2) {
for (j = 0; j < sx - 1; j += 2) {
base = i * sx + j;
- tmp = ((bayer[base] + bayer[base + sx + 1]) / 2);
- CLIP_FLOAT(tmp, outG[base * 3]);
+ tmp = ((bayer[base] + bayer[base + sx + 1]) >> 1);
+ CLIP16(tmp, outG[base * 3], bits);
tmp = bayer[base + 1];
- CLIP_FLOAT(tmp, outR[base * 3]);
+ CLIP16(tmp, outR[base * 3], bits);
tmp = bayer[base + sx];
- CLIP_FLOAT(tmp, outB[base * 3]);
+ CLIP16(tmp, outB[base * 3], bits);
}
}
for (i = 0; i < sy - 1; i += 2) {
for (j = 1; j < sx - 1; j += 2) {
base = i * sx + j;
- tmp = ((bayer[base + 1] + bayer[base + sx]) / 2);
- CLIP_FLOAT(tmp, outG[(base) * 3]);
+ tmp = ((bayer[base + 1] + bayer[base + sx]) >> 1);
+ CLIP16(tmp, outG[(base) * 3], bits);
tmp = bayer[base];
- CLIP_FLOAT(tmp, outR[(base) * 3]);
+ CLIP16(tmp, outR[(base) * 3], bits);
tmp = bayer[base + 1 + sx];
- CLIP_FLOAT(tmp, outB[(base) * 3]);
+ CLIP16(tmp, outB[(base) * 3], bits);
}
}
for (i = 1; i < sy - 1; i += 2) {
for (j = 0; j < sx - 1; j += 2) {
base = i * sx + j;
- tmp = ((bayer[base + sx] + bayer[base + 1]) / 2);
- CLIP_FLOAT(tmp, outG[base * 3]);
+ tmp = ((bayer[base + sx] + bayer[base + 1]) >> 1);
+ CLIP16(tmp, outG[base * 3], bits);
tmp = bayer[base + sx + 1];
- CLIP_FLOAT(tmp, outR[base * 3]);
+ CLIP16(tmp, outR[base * 3], bits);
tmp = bayer[base];
- CLIP_FLOAT(tmp, outB[base * 3]);
+ CLIP16(tmp, outB[base * 3], bits);
}
}
for (i = 1; i < sy - 1; i += 2) {
for (j = 1; j < sx - 1; j += 2) {
base = i * sx + j;
- tmp = ((bayer[base] + bayer[base + 1 + sx]) / 2);
- CLIP_FLOAT(tmp, outG[(base) * 3]);
+ tmp = ((bayer[base] + bayer[base + 1 + sx]) >> 1);
+ CLIP16(tmp, outG[(base) * 3], bits);
tmp = bayer[base + sx];
- CLIP_FLOAT(tmp, outR[(base) * 3]);
+ CLIP16(tmp, outR[(base) * 3], bits);
tmp = bayer[base + 1];
- CLIP_FLOAT(tmp, outB[(base) * 3]);
+ CLIP16(tmp, outB[(base) * 3], bits);
}
}
break;
@@ -597,51 +1734,51 @@ dc1394_bayer_Simple_float(const float * bayer, float * rgb, int sx, int sy, int
for (i = 0; i < sy - 1; i += 2) {
for (j = 0; j < sx - 1; j += 2) {
base = i * sx + j;
- tmp = ((bayer[base + sx] + bayer[base + 1]) / 2);
- CLIP_FLOAT(tmp, outG[base * 3]);
+ tmp = ((bayer[base + sx] + bayer[base + 1]) >> 1);
+ CLIP16(tmp, outG[base * 3], bits);
tmp = bayer[base + sx + 1];
- CLIP_FLOAT(tmp, outR[base * 3]);
+ CLIP16(tmp, outR[base * 3], bits);
tmp = bayer[base];
- CLIP_FLOAT(tmp, outB[base * 3]);
+ CLIP16(tmp, outB[base * 3], bits);
}
}
for (i = 1; i < sy - 1; i += 2) {
for (j = 0; j < sx - 1; j += 2) {
base = i * sx + j;
- tmp = ((bayer[base] + bayer[base + 1 + sx]) / 2);
- CLIP_FLOAT(tmp, outG[(base) * 3]);
+ tmp = ((bayer[base] + bayer[base + 1 + sx]) >> 1);
+ CLIP16(tmp, outG[(base) * 3], bits);
tmp = bayer[base + 1];
- CLIP_FLOAT(tmp, outR[(base) * 3]);
+ CLIP16(tmp, outR[(base) * 3], bits);
tmp = bayer[base + sx];
- CLIP_FLOAT(tmp, outB[(base) * 3]);
+ CLIP16(tmp, outB[(base) * 3], bits);
}
}
for (i = 0; i < sy - 1; i += 2) {
for (j = 1; j < sx - 1; j += 2) {
base = i * sx + j;
- tmp = ((bayer[base] + bayer[base + sx + 1]) / 2);
- CLIP_FLOAT(tmp, outG[base * 3]);
+ tmp = ((bayer[base] + bayer[base + sx + 1]) >> 1);
+ CLIP16(tmp, outG[base * 3], bits);
tmp = bayer[base + sx];
- CLIP_FLOAT(tmp, outR[base * 3]);
+ CLIP16(tmp, outR[base * 3], bits);
tmp = bayer[base + 1];
- CLIP_FLOAT(tmp, outB[base * 3]);
+ CLIP16(tmp, outB[base * 3], bits);
}
}
for (i = 1; i < sy - 1; i += 2) {
for (j = 1; j < sx - 1; j += 2) {
base = i * sx + j;
- tmp = ((bayer[base + 1] + bayer[base + sx]) / 2);
- CLIP_FLOAT(tmp, outG[(base) * 3]);
+ tmp = ((bayer[base + 1] + bayer[base + sx]) >> 1);
+ CLIP16(tmp, outG[(base) * 3], bits);
tmp = bayer[base];
- CLIP_FLOAT(tmp, outR[(base) * 3]);
+ CLIP16(tmp, outR[(base) * 3], bits);
tmp = bayer[base + 1 + sx];
- CLIP_FLOAT(tmp, outB[(base) * 3]);
+ CLIP16(tmp, outB[(base) * 3], bits);
}
}
break;
}
- /* add black border
+ /* add black border */
for (i = sx * (sy - 1) * 3; i < sx * sy * 3; i++) {
rgb[i] = 0;
}
@@ -650,7 +1787,6 @@ dc1394_bayer_Simple_float(const float * bayer, float * rgb, int sx, int sy, int
rgb[i++] = 0;
rgb[i++] = 0;
}
- */
return DC1394_SUCCESS;
@@ -679,7 +1815,7 @@ dc1394_bayer_Simple_float(const float * bayer, float * rgb, int sx, int sy, int
Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2
*/
#define FC(row,col) \
- (filters >> ((((row) * 2 & 14) + ((col) & 1)) * 2) & 3)
+ (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)
/*
This algorithm is officially called:
@@ -717,21 +1853,147 @@ static const signed char bayervng_terms[] = {
}, bayervng_chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 };
dc1394error_t
-dc1394_bayer_VNG_float(const float * bayer, float * dst, int sx, int sy, int offsetX, int offsetY, dc1394color_filter_t pattern)
+dc1394_bayer_VNG(const uint8_t *restrict bayer,
+ uint8_t *restrict dst, int sx, int sy,
+ dc1394color_filter_t pattern)
{
const int height = sy, width = sx;
static const signed char *cp;
/* the following has the same type as the image */
- float (*brow[5])[3], *pix; /* [FD] */
+ uint8_t (*brow[5])[3], *pix; /* [FD] */
int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4];
- int row, col, x, y, x1, x2, y1, y2, t, weight, grads, diag;
- int g, diff, thold, num;
- uint32_t c, color;
+ int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
+ int g, diff, thold, num, c;
uint32_t filters; /* [FD] */
/* first, use bilinear bayer decoding */
+ dc1394_bayer_Bilinear(bayer, dst, sx, sy, pattern);
- dc1394_bayer_Bilinear_float(bayer, dst, sx, sy, offsetX, offsetY, pattern);
+ switch(pattern) {
+ case DC1394_COLOR_FILTER_BGGR:
+ filters = 0x16161616;
+ break;
+ case DC1394_COLOR_FILTER_GRBG:
+ filters = 0x61616161;
+ break;
+ case DC1394_COLOR_FILTER_RGGB:
+ filters = 0x94949494;
+ break;
+ case DC1394_COLOR_FILTER_GBRG:
+ filters = 0x49494949;
+ break;
+ default:
+ return DC1394_INVALID_COLOR_FILTER;
+ }
+
+ for (row=0; row < 8; row++) { /* Precalculate for VNG */
+ for (col=0; col < 2; col++) {
+ ip = code[row][col];
+ for (cp=bayervng_terms, t=0; t < 64; t++) {
+ y1 = *cp++; x1 = *cp++;
+ y2 = *cp++; x2 = *cp++;
+ weight = *cp++;
+ grads = *cp++;
+ color = FC(row+y1,col+x1);
+ if (FC(row+y2,col+x2) != color) continue;
+ diag = (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1;
+ if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue;
+ *ip++ = (y1*width + x1)*3 + color; /* [FD] */
+ *ip++ = (y2*width + x2)*3 + color; /* [FD] */
+ *ip++ = weight;
+ for (g=0; g < 8; g++)
+ if (grads & 1<<g) *ip++ = g;
+ *ip++ = -1;
+ }
+ *ip++ = INT_MAX;
+ for (cp=bayervng_chood, g=0; g < 8; g++) {
+ y = *cp++; x = *cp++;
+ *ip++ = (y*width + x) * 3; /* [FD] */
+ color = FC(row,col);
+ if (FC(row+y,col+x) != color && FC(row+y*2,col+x*2) == color)
+ *ip++ = (y*width + x) * 6 + color; /* [FD] */
+ else
+ *ip++ = 0;
+ }
+ }
+ }
+ brow[4] = calloc (width*3, sizeof **brow);
+ for (row=0; row < 3; row++)
+ brow[row] = brow[4] + row*width;
+ for (row=2; row < height-2; row++) { /* Do VNG interpolation */
+ for (col=2; col < width-2; col++) {
+ pix = dst + (row*width+col)*3; /* [FD] */
+ ip = code[row & 7][col & 1];
+ memset (gval, 0, sizeof gval);
+ while ((g = ip[0]) != INT_MAX) { /* Calculate gradients */
+ diff = ABS(pix[g] - pix[ip[1]]) << ip[2];
+ gval[ip[3]] += diff;
+ ip += 5;
+ if ((g = ip[-1]) == -1) continue;
+ gval[g] += diff;
+ while ((g = *ip++) != -1)
+ gval[g] += diff;
+ }
+ ip++;
+ gmin = gmax = gval[0]; /* Choose a threshold */
+ for (g=1; g < 8; g++) {
+ if (gmin > gval[g]) gmin = gval[g];
+ if (gmax < gval[g]) gmax = gval[g];
+ }
+ if (gmax == 0) {
+ memcpy (brow[2][col], pix, 3 * sizeof *dst); /* [FD] */
+ continue;
+ }
+ thold = gmin + (gmax >> 1);
+ memset (sum, 0, sizeof sum);
+ color = FC(row,col);
+ for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */
+ if (gval[g] <= thold) {
+ for (c=0; c < 3; c++) /* [FD] */
+ if (c == color && ip[1])
+ sum[c] += (pix[c] + pix[ip[1]]) >> 1;
+ else
+ sum[c] += pix[ip[0] + c];
+ num++;
+ }
+ }
+ for (c=0; c < 3; c++) { /* [FD] Save to buffer */
+ t = pix[color];
+ if (c != color)
+ t += (sum[c] - sum[color]) / num;
+ CLIP(t,brow[2][col][c]); /* [FD] */
+ }
+ }
+ if (row > 3) /* Write buffer to image */
+ memcpy (dst + 3*((row-2)*width+2), brow[0]+2, (width-4)*3*sizeof *dst); /* [FD] */
+ for (g=0; g < 4; g++)
+ brow[(g-1) & 3] = brow[g];
+ }
+ memcpy (dst + 3*((row-2)*width+2), brow[0]+2, (width-4)*3*sizeof *dst);
+ memcpy (dst + 3*((row-1)*width+2), brow[1]+2, (width-4)*3*sizeof *dst);
+ free (brow[4]);
+
+ return DC1394_SUCCESS;
+}
+
+
+dc1394error_t
+dc1394_bayer_VNG_uint16(const uint16_t *restrict bayer,
+ uint16_t *restrict dst, int sx, int sy,
+ dc1394color_filter_t pattern, int bits)
+{
+ const int height = sy, width = sx;
+ static const signed char *cp;
+ /* the following has the same type as the image */
+ uint16_t (*brow[5])[3], *pix; /* [FD] */
+ int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4];
+ int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
+ int g, diff, thold, num, c;
+ uint32_t filters; /* [FD] */
+
+ /* first, use bilinear bayer decoding */
+
+ dc1394_bayer_Bilinear_uint16(bayer, dst, sx, sy, pattern, bits);
switch(pattern) {
case DC1394_COLOR_FILTER_BGGR:
@@ -782,7 +2044,6 @@ dc1394_bayer_VNG_float(const float * bayer, float * dst, int sx, int sy, int off
}
}
brow[4] = calloc (width*3, sizeof **brow);
- /*merror (brow[4], "vng_interpolate()");*/
for (row=0; row < 3; row++)
brow[row] = brow[4] + row*width;
for (row=2; row < height-2; row++) { /* Do VNG interpolation */
@@ -809,14 +2070,14 @@ dc1394_bayer_VNG_float(const float * bayer, float * dst, int sx, int sy, int off
memcpy (brow[2][col], pix, 3 * sizeof *dst); /* [FD] */
continue;
}
- thold = gmin + (gmax / 2);
+ thold = gmin + (gmax >> 1);
memset (sum, 0, sizeof sum);
color = FC(row,col);
for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */
if (gval[g] <= thold) {
for (c=0; c < 3; c++) /* [FD] */
if (c == color && ip[1])
- sum[c] += (pix[c] + pix[ip[1]]) / 2;
+ sum[c] += (pix[c] + pix[ip[1]]) >> 1;
else
sum[c] += pix[ip[0] + c];
num++;
@@ -826,7 +2087,7 @@ dc1394_bayer_VNG_float(const float * bayer, float * dst, int sx, int sy, int off
t = pix[color];
if (c != color)
t += (sum[c] - sum[color]) / num;
- CLIP_FLOAT(t,brow[2][col][c]); /* [FD] */
+ CLIP16(t,brow[2][col][c],bits); /* [FD] */
}
}
if (row > 3) /* Write buffer to image */
@@ -847,7 +2108,7 @@ dc1394_bayer_VNG_float(const float * bayer, float * dst, int sx, int sy, int off
static dc1394bool_t ahd_inited = DC1394_FALSE; /* WARNING: not multi-processor safe */
#define CLIPOUT(x) LIM(x,0,255)
-#define CLIPOUT_FLOAT(x) LIM(x,FLT_MIN,FLT_MAX)
+#define CLIPOUT16(x,bits) LIM(x,0,((1<<bits)-1))
static const double xyz_rgb[3][3] = { /* XYZ from RGB */
{ 0.412453, 0.357580, 0.180423 },
@@ -855,7 +2116,7 @@ static const double xyz_rgb[3][3] = { /* XYZ from RGB */
{ 0.019334, 0.119193, 0.950227 } };
static const float d65_white[3] = { 0.950456, 1, 1.088754 };
-static void cam_to_cielab (float cam[3], float lab[3]) /* [SA] */
+static void cam_to_cielab (uint16_t cam[3], float lab[3]) /* [SA] */
{
int c, i, j;
float r, xyz[3];
@@ -876,32 +2137,415 @@ static void cam_to_cielab (float cam[3], float lab[3]) /* [SA] */
xyz[1] += xyz_cam[1][c] * cam[c];
xyz[2] += xyz_cam[2][c] * cam[c];
}
- xyz[0] = cbrt[(int) CLIPOUT_FLOAT(xyz[0])]; /* [SA] */
- xyz[1] = cbrt[(int) CLIPOUT_FLOAT(xyz[1])]; /* [SA] */
- xyz[2] = cbrt[(int) CLIPOUT_FLOAT(xyz[2])]; /* [SA] */
+ xyz[0] = cbrt[CLIPOUT16((int) xyz[0],16)]; /* [SA] */
+ xyz[1] = cbrt[CLIPOUT16((int) xyz[1],16)]; /* [SA] */
+ xyz[2] = cbrt[CLIPOUT16((int) xyz[2],16)]; /* [SA] */
lab[0] = 116 * xyz[1] - 16;
lab[1] = 500 * (xyz[0] - xyz[1]);
lab[2] = 200 * (xyz[1] - xyz[2]);
}
}
+/*
+ Adaptive Homogeneity-Directed interpolation is based on
+ the work of Keigo Hirakawa, Thomas Parks, and Paul Lee.
+ */
+#define TS 256 /* Tile Size */
+
+dc1394error_t
+dc1394_bayer_AHD(const uint8_t *restrict bayer,
+ uint8_t *restrict dst, int sx, int sy,
+ dc1394color_filter_t pattern)
+{
+ int i, j, top, left, row, col, tr, tc, fc, c, d, val, hm[2];
+ /* the following has the same type as the image */
+ uint8_t (*pix)[3], (*rix)[3]; /* [SA] */
+ uint16_t rix16[3]; /* [SA] */
+ static const int dir[4] = { -1, 1, -TS, TS };
+ unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
+ float flab[3]; /* [SA] */
+ uint8_t (*rgb)[TS][TS][3];
+ short (*lab)[TS][TS][3];
+ char (*homo)[TS][TS], *buffer;
+
+ /* start - new code for libdc1394 */
+ uint32_t filters;
+ const int height = sy, width = sx;
+ int x, y;
+
+ if (ahd_inited==DC1394_FALSE) {
+ /* WARNING: this might not be multi-processor safe */
+ cam_to_cielab (NULL,NULL);
+ ahd_inited = DC1394_TRUE;
+ }
+
+ switch(pattern) {
+ case DC1394_COLOR_FILTER_BGGR:
+ filters = 0x16161616;
+ break;
+ case DC1394_COLOR_FILTER_GRBG:
+ filters = 0x61616161;
+ break;
+ case DC1394_COLOR_FILTER_RGGB:
+ filters = 0x94949494;
+ break;
+ case DC1394_COLOR_FILTER_GBRG:
+ filters = 0x49494949;
+ break;
+ default:
+ return DC1394_INVALID_COLOR_FILTER;
+ }
+
+ /* fill-in destination with known exact values */
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int channel = FC(y,x);
+ dst[(y*width+x)*3 + channel] = bayer[y*width+x];
+ }
+ }
+ /* end - new code for libdc1394 */
+
+ /* start - code from border_interpolate (int border) */
+ {
+ int border = 3;
+ unsigned row, col, y, x, f, c, sum[8];
+
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++) {
+ if (col==border && row >= border && row < height-border)
+ col = width-border;
+ memset (sum, 0, sizeof sum);
+ for (y=row-1; y != row+2; y++)
+ for (x=col-1; x != col+2; x++)
+ if (y < height && x < width) {
+ f = FC(y,x);
+ sum[f] += dst[(y*width+x)*3 + f]; /* [SA] */
+ sum[f+4]++;
+ }
+ f = FC(row,col);
+ FORC3 if (c != f && sum[c+4]) /* [SA] */
+ dst[(row*width+col)*3 + c] = sum[c] / sum[c+4]; /* [SA] */
+ }
+ }
+ /* end - code from border_interpolate (int border) */
+
+
+ buffer = (char *) malloc (26*TS*TS); /* 1664 kB */
+ /* merror (buffer, "ahd_interpolate()"); */
+ rgb = (uint8_t(*)[TS][TS][3]) buffer; /* [SA] */
+ lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS);
+ homo = (char (*)[TS][TS]) (buffer + 24*TS*TS);
+
+ for (top=0; top < height; top += TS-6)
+ for (left=0; left < width; left += TS-6) {
+ memset (rgb, 0, 12*TS*TS);
+
+ /* Interpolate green horizontally and vertically: */
+ for (row = top < 2 ? 2:top; row < top+TS && row < height-2; row++) {
+ col = left + (FC(row,left) == 1);
+ if (col < 2) col += 2;
+ for (fc = FC(row,col); col < left+TS && col < width-2; col+=2) {
+ pix = (uint8_t (*)[3])dst + (row*width+col); /* [SA] */
+ val = ((pix[-1][1] + pix[0][fc] + pix[1][1]) * 2
+ - pix[-2][fc] - pix[2][fc]) >> 2;
+ rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]);
+ val = ((pix[-width][1] + pix[0][fc] + pix[width][1]) * 2
+ - pix[-2*width][fc] - pix[2*width][fc]) >> 2;
+ rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]);
+ }
+ }
+ /* Interpolate red and blue, and convert to CIELab: */
+ for (d=0; d < 2; d++)
+ for (row=top+1; row < top+TS-1 && row < height-1; row++)
+ for (col=left+1; col < left+TS-1 && col < width-1; col++) {
+ pix = (uint8_t (*)[3])dst + (row*width+col); /* [SA] */
+ rix = &rgb[d][row-top][col-left];
+ if ((c = 2 - FC(row,col)) == 1) {
+ c = FC(row+1,col);
+ val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c]
+ - rix[-1][1] - rix[1][1] ) >> 1);
+ rix[0][2-c] = CLIPOUT(val); /* [SA] */
+ val = pix[0][1] + (( pix[-width][c] + pix[width][c]
+ - rix[-TS][1] - rix[TS][1] ) >> 1);
+ } else
+ val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c]
+ + pix[+width-1][c] + pix[+width+1][c]
+ - rix[-TS-1][1] - rix[-TS+1][1]
+ - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2);
+ rix[0][c] = CLIPOUT(val); /* [SA] */
+ c = FC(row,col);
+ rix[0][c] = pix[0][c];
+ rix16[0] = rix[0][0]; /* [SA] */
+ rix16[1] = rix[0][1]; /* [SA] */
+ rix16[2] = rix[0][2]; /* [SA] */
+ cam_to_cielab (rix16, flab); /* [SA] */
+ FORC3 lab[d][row-top][col-left][c] = 64*flab[c];
+ }
+ /* Build homogeneity maps from the CIELab images: */
+ memset (homo, 0, 2*TS*TS);
+ for (row=top+2; row < top+TS-2 && row < height; row++) {
+ tr = row-top;
+ for (col=left+2; col < left+TS-2 && col < width; col++) {
+ tc = col-left;
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ ldiff[d][i] = ABS(lab[d][tr][tc][0]-lab[d][tr][tc+dir[i]][0]);
+ leps = MIN(MAX(ldiff[0][0],ldiff[0][1]),
+ MAX(ldiff[1][2],ldiff[1][3]));
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ if (i >> 1 == d || ldiff[d][i] <= leps)
+ abdiff[d][i] = SQR(lab[d][tr][tc][1]-lab[d][tr][tc+dir[i]][1])
+ + SQR(lab[d][tr][tc][2]-lab[d][tr][tc+dir[i]][2]);
+ abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]),
+ MAX(abdiff[1][2],abdiff[1][3]));
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps)
+ homo[d][tr][tc]++;
+ }
+ }
+ /* Combine the most homogenous pixels for the final result: */
+ for (row=top+3; row < top+TS-3 && row < height-3; row++) {
+ tr = row-top;
+ for (col=left+3; col < left+TS-3 && col < width-3; col++) {
+ tc = col-left;
+ for (d=0; d < 2; d++)
+ for (hm[d]=0, i=tr-1; i <= tr+1; i++)
+ for (j=tc-1; j <= tc+1; j++)
+ hm[d] += homo[d][i][j];
+ if (hm[0] != hm[1])
+ FORC3 dst[(row*width+col)*3 + c] = CLIPOUT(rgb[hm[1] > hm[0]][tr][tc][c]); /* [SA] */
+ else
+ FORC3 dst[(row*width+col)*3 + c] =
+ CLIPOUT((rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1); /* [SA] */
+ }
+ }
+ }
+ free (buffer);
+
+ return DC1394_SUCCESS;
+}
+
+dc1394error_t
+dc1394_bayer_AHD_uint16(const uint16_t *restrict bayer,
+ uint16_t *restrict dst, int sx, int sy,
+ dc1394color_filter_t pattern, int bits)
+{
+ int i, j, top, left, row, col, tr, tc, fc, c, d, val, hm[2];
+ /* the following has the same type as the image */
+ uint16_t (*pix)[3], (*rix)[3]; /* [SA] */
+ static const int dir[4] = { -1, 1, -TS, TS };
+ unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
+ float flab[3];
+ uint16_t (*rgb)[TS][TS][3]; /* [SA] */
+ short (*lab)[TS][TS][3];
+ char (*homo)[TS][TS], *buffer;
+
+ /* start - new code for libdc1394 */
+ uint32_t filters;
+ const int height = sy, width = sx;
+ int x, y;
+
+ if (ahd_inited==DC1394_FALSE) {
+ /* WARNING: this might not be multi-processor safe */
+ cam_to_cielab (NULL,NULL);
+ ahd_inited = DC1394_TRUE;
+ }
+
+ switch(pattern) {
+ case DC1394_COLOR_FILTER_BGGR:
+ filters = 0x16161616;
+ break;
+ case DC1394_COLOR_FILTER_GRBG:
+ filters = 0x61616161;
+ break;
+ case DC1394_COLOR_FILTER_RGGB:
+ filters = 0x94949494;
+ break;
+ case DC1394_COLOR_FILTER_GBRG:
+ filters = 0x49494949;
+ break;
+ default:
+ return DC1394_INVALID_COLOR_FILTER;
+ }
+
+ /* fill-in destination with known exact values */
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int channel = FC(y,x);
+ dst[(y*width+x)*3 + channel] = bayer[y*width+x];
+ }
+ }
+ /* end - new code for libdc1394 */
+
+ /* start - code from border_interpolate(int border) */
+ {
+ int border = 3;
+ unsigned row, col, y, x, f, c, sum[8];
+
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++) {
+ if (col==border && row >= border && row < height-border)
+ col = width-border;
+ memset (sum, 0, sizeof sum);
+ for (y=row-1; y != row+2; y++)
+ for (x=col-1; x != col+2; x++)
+ if (y < height && x < width) {
+ f = FC(y,x);
+ sum[f] += dst[(y*width+x)*3 + f]; /* [SA] */
+ sum[f+4]++;
+ }
+ f = FC(row,col);
+ FORC3 if (c != f && sum[c+4]) /* [SA] */
+ dst[(row*width+col)*3 + c] = sum[c] / sum[c+4]; /* [SA] */
+ }
+ }
+ /* end - code from border_interpolate(int border) */
+
+
+ buffer = (char *) malloc (26*TS*TS); /* 1664 kB */
+ /* merror (buffer, "ahd_interpolate()"); */
+ rgb = (uint16_t(*)[TS][TS][3]) buffer; /* [SA] */
+ lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS);
+ homo = (char (*)[TS][TS]) (buffer + 24*TS*TS);
+
+ for (top=0; top < height; top += TS-6)
+ for (left=0; left < width; left += TS-6) {
+ memset (rgb, 0, 12*TS*TS);
+
+ /* Interpolate green horizontally and vertically: */
+ for (row = top < 2 ? 2:top; row < top+TS && row < height-2; row++) {
+ col = left + (FC(row,left) == 1);
+ if (col < 2) col += 2;
+ for (fc = FC(row,col); col < left+TS && col < width-2; col+=2) {
+ pix = (uint16_t (*)[3])dst + (row*width+col); /* [SA] */
+ val = ((pix[-1][1] + pix[0][fc] + pix[1][1]) * 2
+ - pix[-2][fc] - pix[2][fc]) >> 2;
+ rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]);
+ val = ((pix[-width][1] + pix[0][fc] + pix[width][1]) * 2
+ - pix[-2*width][fc] - pix[2*width][fc]) >> 2;
+ rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]);
+ }
+ }
+ /* Interpolate red and blue, and convert to CIELab: */
+ for (d=0; d < 2; d++)
+ for (row=top+1; row < top+TS-1 && row < height-1; row++)
+ for (col=left+1; col < left+TS-1 && col < width-1; col++) {
+ pix = (uint16_t (*)[3])dst + (row*width+col); /* [SA] */
+ rix = &rgb[d][row-top][col-left];
+ if ((c = 2 - FC(row,col)) == 1) {
+ c = FC(row+1,col);
+ val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c]
+ - rix[-1][1] - rix[1][1] ) >> 1);
+ rix[0][2-c] = CLIPOUT16(val, bits); /* [SA] */
+ val = pix[0][1] + (( pix[-width][c] + pix[width][c]
+ - rix[-TS][1] - rix[TS][1] ) >> 1);
+ } else
+ val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c]
+ + pix[+width-1][c] + pix[+width+1][c]
+ - rix[-TS-1][1] - rix[-TS+1][1]
+ - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2);
+ rix[0][c] = CLIPOUT16(val, bits); /* [SA] */
+ c = FC(row,col);
+ rix[0][c] = pix[0][c];
+ cam_to_cielab (rix[0], flab);
+ FORC3 lab[d][row-top][col-left][c] = 64*flab[c];
+ }
+ /* Build homogeneity maps from the CIELab images: */
+ memset (homo, 0, 2*TS*TS);
+ for (row=top+2; row < top+TS-2 && row < height; row++) {
+ tr = row-top;
+ for (col=left+2; col < left+TS-2 && col < width; col++) {
+ tc = col-left;
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ ldiff[d][i] = ABS(lab[d][tr][tc][0]-lab[d][tr][tc+dir[i]][0]);
+ leps = MIN(MAX(ldiff[0][0],ldiff[0][1]),
+ MAX(ldiff[1][2],ldiff[1][3]));
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ if (i >> 1 == d || ldiff[d][i] <= leps)
+ abdiff[d][i] = SQR(lab[d][tr][tc][1]-lab[d][tr][tc+dir[i]][1])
+ + SQR(lab[d][tr][tc][2]-lab[d][tr][tc+dir[i]][2]);
+ abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]),
+ MAX(abdiff[1][2],abdiff[1][3]));
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps)
+ homo[d][tr][tc]++;
+ }
+ }
+ /* Combine the most homogenous pixels for the final result: */
+ for (row=top+3; row < top+TS-3 && row < height-3; row++) {
+ tr = row-top;
+ for (col=left+3; col < left+TS-3 && col < width-3; col++) {
+ tc = col-left;
+ for (d=0; d < 2; d++)
+ for (hm[d]=0, i=tr-1; i <= tr+1; i++)
+ for (j=tc-1; j <= tc+1; j++)
+ hm[d] += homo[d][i][j];
+ if (hm[0] != hm[1])
+ FORC3 dst[(row*width+col)*3 + c] = CLIPOUT16(rgb[hm[1] > hm[0]][tr][tc][c], bits); /* [SA] */
+ else
+ FORC3 dst[(row*width+col)*3 + c] =
+ CLIPOUT16((rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1, bits); /* [SA] */
+ }
+ }
+ }
+ free (buffer);
+
+ return DC1394_SUCCESS;
+}
+
dc1394error_t
-dc1394_bayer_decoding_float(const float * bayer, float * rgb, uint32_t sx, uint32_t sy, int offsetX, int offsetY, dc1394color_filter_t tile, dc1394bayer_method_t method)
+dc1394_bayer_decoding_8bit(const uint8_t *restrict bayer, uint8_t *restrict rgb, uint32_t sx, uint32_t sy, dc1394color_filter_t tile, dc1394bayer_method_t method)
{
switch (method) {
case DC1394_BAYER_METHOD_NEAREST:
- return dc1394_bayer_NearestNeighbor_float(bayer, rgb, sx, sy, offsetX, offsetY, tile);
+ return dc1394_bayer_NearestNeighbor(bayer, rgb, sx, sy, tile);
case DC1394_BAYER_METHOD_SIMPLE:
- return dc1394_bayer_Simple_float(bayer, rgb, sx, sy, offsetX, offsetY, tile);
+ return dc1394_bayer_Simple(bayer, rgb, sx, sy, tile);
case DC1394_BAYER_METHOD_BILINEAR:
- return dc1394_bayer_Bilinear_float(bayer, rgb, sx, sy, offsetX, offsetY, tile);
+ return dc1394_bayer_Bilinear(bayer, rgb, sx, sy, tile);
case DC1394_BAYER_METHOD_HQLINEAR:
- return dc1394_bayer_HQLinear_float(bayer, rgb, sx, sy, offsetX, offsetY, tile);
+ return dc1394_bayer_HQLinear(bayer, rgb, sx, sy, tile);
+ case DC1394_BAYER_METHOD_DOWNSAMPLE:
+ return dc1394_bayer_Downsample(bayer, rgb, sx, sy, tile);
+ case DC1394_BAYER_METHOD_EDGESENSE:
+ return dc1394_bayer_EdgeSense(bayer, rgb, sx, sy, tile);
case DC1394_BAYER_METHOD_VNG:
- return dc1394_bayer_VNG_float(bayer, rgb, sx, sy, offsetX, offsetY, tile);
+ return dc1394_bayer_VNG(bayer, rgb, sx, sy, tile);
+ case DC1394_BAYER_METHOD_AHD:
+ return dc1394_bayer_AHD(bayer, rgb, sx, sy, tile);
default:
return DC1394_INVALID_BAYER_METHOD;
- }
+ }
}
+dc1394error_t
+dc1394_bayer_decoding_16bit(const uint16_t *restrict bayer, uint16_t *restrict rgb, uint32_t sx, uint32_t sy, dc1394color_filter_t tile, dc1394bayer_method_t method, uint32_t bits)
+{
+ switch (method) {
+ case DC1394_BAYER_METHOD_NEAREST:
+ return dc1394_bayer_NearestNeighbor_uint16(bayer, rgb, sx, sy, tile, bits);
+ case DC1394_BAYER_METHOD_SIMPLE:
+ return dc1394_bayer_Simple_uint16(bayer, rgb, sx, sy, tile, bits);
+ case DC1394_BAYER_METHOD_BILINEAR:
+ return dc1394_bayer_Bilinear_uint16(bayer, rgb, sx, sy, tile, bits);
+ case DC1394_BAYER_METHOD_HQLINEAR:
+ return dc1394_bayer_HQLinear_uint16(bayer, rgb, sx, sy, tile, bits);
+ case DC1394_BAYER_METHOD_DOWNSAMPLE:
+ return dc1394_bayer_Downsample_uint16(bayer, rgb, sx, sy, tile, bits);
+ case DC1394_BAYER_METHOD_EDGESENSE:
+ return dc1394_bayer_EdgeSense_uint16(bayer, rgb, sx, sy, tile, bits);
+ case DC1394_BAYER_METHOD_VNG:
+ return dc1394_bayer_VNG_uint16(bayer, rgb, sx, sy, tile, bits);
+ case DC1394_BAYER_METHOD_AHD:
+ return dc1394_bayer_AHD_uint16(bayer, rgb, sx, sy, tile, bits);
+ default:
+ return DC1394_INVALID_BAYER_METHOD;
+ }
+
+}
diff --git a/kstars/fitsviewer/bayer.h b/kstars/fitsviewer/bayer.h
index 1a2fd0a..3c321f1 100644
--- a/kstars/fitsviewer/bayer.h
+++ b/kstars/fitsviewer/bayer.h
@@ -21,28 +21,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <stdint.h>
-
#ifndef BAYER_H
#define BAYER_H
-typedef enum {
- DC1394_BAYER_METHOD_NEAREST=0,
- DC1394_BAYER_METHOD_SIMPLE,
- DC1394_BAYER_METHOD_BILINEAR,
- DC1394_BAYER_METHOD_HQLINEAR,
- DC1394_BAYER_METHOD_VNG
-} dc1394bayer_method_t;
+#include <stdint.h>
-typedef enum {
- DC1394_COLOR_FILTER_RGGB = 512,
- DC1394_COLOR_FILTER_GBRG,
- DC1394_COLOR_FILTER_GRBG,
- DC1394_COLOR_FILTER_BGGR
-} dc1394color_filter_t ;
-#define DC1394_COLOR_FILTER_MIN DC1394_COLOR_FILTER_RGGB
-#define DC1394_COLOR_FILTER_MAX DC1394_COLOR_FILTER_BGGR
-#define DC1394_COLOR_FILTER_NUM (DC1394_COLOR_FILTER_MAX - DC1394_COLOR_FILTER_MIN + 1)
+#define restrict __restrict
/**
* Error codes returned by most libdc1394 functions.
@@ -95,11 +79,156 @@ typedef enum {
#define DC1394_ERROR_MAX DC1394_SUCCESS
#define DC1394_ERROR_NUM (DC1394_ERROR_MAX-DC1394_ERROR_MIN+1)
+/**
+ * Enumeration of video modes. Note that the notion of IIDC "format" is not present here, except in the format_7 name.
+ */
+typedef enum {
+ DC1394_VIDEO_MODE_160x120_YUV444= 64,
+ DC1394_VIDEO_MODE_320x240_YUV422,
+ DC1394_VIDEO_MODE_640x480_YUV411,
+ DC1394_VIDEO_MODE_640x480_YUV422,
+ DC1394_VIDEO_MODE_640x480_RGB8,
+ DC1394_VIDEO_MODE_640x480_MONO8,
+ DC1394_VIDEO_MODE_640x480_MONO16,
+ DC1394_VIDEO_MODE_800x600_YUV422,
+ DC1394_VIDEO_MODE_800x600_RGB8,
+ DC1394_VIDEO_MODE_800x600_MONO8,
+ DC1394_VIDEO_MODE_1024x768_YUV422,
+ DC1394_VIDEO_MODE_1024x768_RGB8,
+ DC1394_VIDEO_MODE_1024x768_MONO8,
+ DC1394_VIDEO_MODE_800x600_MONO16,
+ DC1394_VIDEO_MODE_1024x768_MONO16,
+ DC1394_VIDEO_MODE_1280x960_YUV422,
+ DC1394_VIDEO_MODE_1280x960_RGB8,
+ DC1394_VIDEO_MODE_1280x960_MONO8,
+ DC1394_VIDEO_MODE_1600x1200_YUV422,
+ DC1394_VIDEO_MODE_1600x1200_RGB8,
+ DC1394_VIDEO_MODE_1600x1200_MONO8,
+ DC1394_VIDEO_MODE_1280x960_MONO16,
+ DC1394_VIDEO_MODE_1600x1200_MONO16,
+ DC1394_VIDEO_MODE_EXIF,
+ DC1394_VIDEO_MODE_FORMAT7_0,
+ DC1394_VIDEO_MODE_FORMAT7_1,
+ DC1394_VIDEO_MODE_FORMAT7_2,
+ DC1394_VIDEO_MODE_FORMAT7_3,
+ DC1394_VIDEO_MODE_FORMAT7_4,
+ DC1394_VIDEO_MODE_FORMAT7_5,
+ DC1394_VIDEO_MODE_FORMAT7_6,
+ DC1394_VIDEO_MODE_FORMAT7_7
+} dc1394video_mode_t;
+#define DC1394_VIDEO_MODE_MIN DC1394_VIDEO_MODE_160x120_YUV444
+#define DC1394_VIDEO_MODE_MAX DC1394_VIDEO_MODE_FORMAT7_7
+#define DC1394_VIDEO_MODE_NUM (DC1394_VIDEO_MODE_MAX - DC1394_VIDEO_MODE_MIN + 1)
+
+/* Special min/max are defined for Format_7 */
+#define DC1394_VIDEO_MODE_FORMAT7_MIN DC1394_VIDEO_MODE_FORMAT7_0
+#define DC1394_VIDEO_MODE_FORMAT7_MAX DC1394_VIDEO_MODE_FORMAT7_7
+#define DC1394_VIDEO_MODE_FORMAT7_NUM (DC1394_VIDEO_MODE_FORMAT7_MAX - DC1394_VIDEO_MODE_FORMAT7_MIN + 1)
+
+/**
+ * Enumeration of colour codings. For details on the data format please read the IIDC specifications.
+ */
+typedef enum {
+ DC1394_COLOR_CODING_MONO8= 352,
+ DC1394_COLOR_CODING_YUV411,
+ DC1394_COLOR_CODING_YUV422,
+ DC1394_COLOR_CODING_YUV444,
+ DC1394_COLOR_CODING_RGB8,
+ DC1394_COLOR_CODING_MONO16,
+ DC1394_COLOR_CODING_RGB16,
+ DC1394_COLOR_CODING_MONO16S,
+ DC1394_COLOR_CODING_RGB16S,
+ DC1394_COLOR_CODING_RAW8,
+ DC1394_COLOR_CODING_RAW16
+} dc1394color_coding_t;
+#define DC1394_COLOR_CODING_MIN DC1394_COLOR_CODING_MONO8
+#define DC1394_COLOR_CODING_MAX DC1394_COLOR_CODING_RAW16
+#define DC1394_COLOR_CODING_NUM (DC1394_COLOR_CODING_MAX - DC1394_COLOR_CODING_MIN + 1)
+
+/**
+ * RAW sensor filters. These elementary tiles tesselate the image plane in RAW modes. RGGB should be interpreted in 2D as
+ *
+ * RG
+ * GB
+ *
+ * and similarly for other filters.
+ */
+typedef enum {
+ DC1394_COLOR_FILTER_RGGB = 512,
+ DC1394_COLOR_FILTER_GBRG,
+ DC1394_COLOR_FILTER_GRBG,
+ DC1394_COLOR_FILTER_BGGR
+} dc1394color_filter_t;
+#define DC1394_COLOR_FILTER_MIN DC1394_COLOR_FILTER_RGGB
+#define DC1394_COLOR_FILTER_MAX DC1394_COLOR_FILTER_BGGR
+#define DC1394_COLOR_FILTER_NUM (DC1394_COLOR_FILTER_MAX - DC1394_COLOR_FILTER_MIN + 1)
+
+/**
+ * Byte order for YUV formats (may be expanded to RGB in the future)
+ *
+ * IIDC cameras always return data in UYVY order, but conversion functions can change this if requested.
+ */
+typedef enum {
+ DC1394_BYTE_ORDER_UYVY=800,
+ DC1394_BYTE_ORDER_YUYV
+} dc1394byte_order_t;
+#define DC1394_BYTE_ORDER_MIN DC1394_BYTE_ORDER_UYVY
+#define DC1394_BYTE_ORDER_MAX DC1394_BYTE_ORDER_YUYV
+#define DC1394_BYTE_ORDER_NUM (DC1394_BYTE_ORDER_MAX - DC1394_BYTE_ORDER_MIN + 1)
+
+/**
+ * A struct containing a list of color codings
+ */
+typedef struct
+{
+ uint32_t num;
+ dc1394color_coding_t codings[DC1394_COLOR_CODING_NUM];
+} dc1394color_codings_t;
+
+/**
+ * A struct containing a list of video modes
+ */
+typedef struct
+{
+ uint32_t num;
+ dc1394video_mode_t modes[DC1394_VIDEO_MODE_NUM];
+} dc1394video_modes_t;
+
+/**
+ * Yet another boolean data type
+ */
typedef enum {
DC1394_FALSE= 0,
DC1394_TRUE
} dc1394bool_t;
+/**
+ * Yet another boolean data type, a bit more oriented towards electrical-engineers
+ */
+typedef enum {
+ DC1394_OFF= 0,
+ DC1394_ON
+} dc1394switch_t;
+
+/**
+ * A list of de-mosaicing techniques for Bayer-patterns.
+ *
+ * The speed of the techniques can vary greatly, as well as their quality.
+ */
+typedef enum {
+ DC1394_BAYER_METHOD_NEAREST=0,
+ DC1394_BAYER_METHOD_SIMPLE,
+ DC1394_BAYER_METHOD_BILINEAR,
+ DC1394_BAYER_METHOD_HQLINEAR,
+ DC1394_BAYER_METHOD_DOWNSAMPLE,
+ DC1394_BAYER_METHOD_EDGESENSE,
+ DC1394_BAYER_METHOD_VNG,
+ DC1394_BAYER_METHOD_AHD
+} dc1394bayer_method_t;
+#define DC1394_BAYER_METHOD_MIN DC1394_BAYER_METHOD_NEAREST
+#define DC1394_BAYER_METHOD_MAX DC1394_BAYER_METHOD_AHD
+#define DC1394_BAYER_METHOD_NUM (DC1394_BAYER_METHOD_MAX-DC1394_BAYER_METHOD_MIN+1)
+
typedef struct
{
dc1394bayer_method_t method; /* Debayer method */
@@ -107,12 +236,55 @@ typedef struct
int offsetX, offsetY; /* Debayer offset */
} BayerParams;
+/************************************************************************************************
+ * *
+ * Color conversion functions for cameras that can output raw Bayer pattern images (color *
+ * codings DC1394_COLOR_CODING_RAW8 and DC1394_COLOR_CODING_RAW16). *
+ * *
+ * Credits and sources: *
+ * - Nearest Neighbor : OpenCV library *
+ * - Bilinear : OpenCV library *
+ * - HQLinear : High-Quality Linear Interpolation For Demosaicing Of Bayer-Patterned *
+ * Color Images, by Henrique S. Malvar, Li-wei He, and Ross Cutler, *
+ * in Proceedings of the ICASSP'04 Conference. *
+ * - Edge Sense II : Laroche, Claude A. "Apparatus and method for adaptively interpolating *
+ * a full color image utilizing chrominance gradients" *
+ * U.S. Patent 5,373,322. Based on the code found on the website *
+ * http://www-ise.stanford.edu/~tingchen/ Converted to C and adapted to *
+ * all four elementary patterns. *
+ * - Downsample : "Known to the Ancients" *
+ * - Simple : Implemented from the information found in the manual of Allied Vision *
+ * Technologies (AVT) cameras. *
+ * - VNG : Variable Number of Gradients, a method described in *
+ * http://www-ise.stanford.edu/~tingchen/algodep/vargra.html *
+ * Sources import from DCRAW by Frederic Devernay. DCRAW is a RAW *
+ * converter program by Dave Coffin. URL: *
+ * http://www.cybercom.net/~dcoffin/dcraw/ *
+ * - AHD : Adaptive Homogeneity-Directed Demosaicing Algorithm, by K. Hirakawa *
+ * and T.W. Parks, IEEE Transactions on Image Processing, Vol. 14, Nr. 3, *
+ * March 2005, pp. 360 - 369. *
+ * *
+ ************************************************************************************************/
+
#ifdef __cplusplus
extern "C" {
#endif
+/**
+ * Perform de-mosaicing on an 8-bit image buffer
+ */
+dc1394error_t
+dc1394_bayer_decoding_8bit(const uint8_t *bayer, uint8_t *rgb,
+ uint32_t width, uint32_t height, dc1394color_filter_t tile,
+ dc1394bayer_method_t method);
+
+/**
+ * Perform de-mosaicing on an 16-bit image buffer
+ */
dc1394error_t
-dc1394_bayer_decoding_float(const float * bayer, float * rgb, uint32_t sx, uint32_t sy, int offsetX, int offsetY, dc1394color_filter_t tile, dc1394bayer_method_t method);
+dc1394_bayer_decoding_16bit(const uint16_t *bayer, uint16_t *rgb,
+ uint32_t width, uint32_t height, dc1394color_filter_t tile,
+ dc1394bayer_method_t method, uint32_t bits);
#ifdef __cplusplus
}
diff --git a/kstars/fitsviewer/fitsdata.cpp b/kstars/fitsviewer/fitsdata.cpp
index 12c80f1..4c3d060 100644
--- a/kstars/fitsviewer/fitsdata.cpp
+++ b/kstars/fitsviewer/fitsdata.cpp
@@ -70,12 +70,10 @@ bool greaterThan(Edge *s1, Edge *s2)
FITSData::FITSData(FITSMode fitsMode)
{
channels = 0;
- image_buffer = NULL;
- bayer_buffer = NULL;
wcs_coord = NULL;
fptr = NULL;
histogram = NULL;
- maxHFRStar = NULL;
+ maxHFRStar = NULL;
tempFile = false;
starsSearched = false;
HasWCS = false;
@@ -85,6 +83,7 @@ FITSData::FITSData(FITSMode fitsMode)
stats.bitpix=8;
stats.ndim = 2;
+ stats.bytesPerPixel=1;
debayerParams.method = DC1394_BAYER_METHOD_NEAREST;
debayerParams.filter = DC1394_COLOR_FILTER_RGGB;
@@ -178,21 +177,27 @@ bool FITSData::loadFITS (const QString &inFilename, bool silent)
{
case 8:
data_type = TBYTE;
+ stats.bytesPerPixel = sizeof(uint8_t);
break;
case 16:
data_type = TUSHORT;
+ stats.bytesPerPixel = sizeof(uint16_t);
break;
case 32:
data_type = TINT;
+ stats.bytesPerPixel = sizeof(uint32_t);
break;
case -32:
data_type = TFLOAT;
+ stats.bytesPerPixel = sizeof(float_t);
break;
case 64:
data_type = TLONGLONG;
+ stats.bytesPerPixel = sizeof(long long);
break;
case -64:
data_type = TDOUBLE;
+ stats.bytesPerPixel = sizeof(double_t);
default:
errMessage = i18n("Bit depth %1 is not supported.", stats.bitpix);
if (silent == false)
@@ -224,10 +229,16 @@ bool FITSData::loadFITS (const QString &inFilename, bool silent)
channels = naxes[2];
- image_buffer = new float[stats.samples_per_channel * channels];
- if (image_buffer == NULL)
+ // Channels always set to #1 if we are not required to process 3D Cubes
+ if (Options::auto3DCube() == false)
+ channels = 1;
+
+ //image_buffer = new float[stats.samples_per_channel * channels];
+ imageBuffer = new uint8_t[stats.samples_per_channel * channels * stats.bytesPerPixel];
+ //if (image_buffer == NULL)
+ if (imageBuffer == NULL)
{
- qDebug() << "FITSData: Not enough memory for image_buffer channel. Requested: " << stats.samples_per_channel * channels * sizeof(float) << " bytes.";
+ qDebug() << "FITSData: Not enough memory for image_buffer channel. Requested: " << stats.samples_per_channel * channels * stats.bytesPerPixel << " bytes.";
clearImageBuffers();
return false;
}
@@ -237,7 +248,7 @@ bool FITSData::loadFITS (const QString &inFilename, bool silent)
flipVCounter=0;
long nelements = stats.samples_per_channel * channels;
- if (fits_read_img(fptr, TFLOAT, 1, nelements, 0, image_buffer, &anynull, &status))
+ if (fits_read_img(fptr, data_type, 1, nelements, 0, imageBuffer, &anynull, &status))
{
char errmsg[512];
fits_get_errstatus(status, errmsg);
@@ -253,7 +264,10 @@ bool FITSData::loadFITS (const QString &inFilename, bool silent)
calculateStats();
if (Options::autoDebayerFITS() && checkDebayer())
+ {
+ bayerBuffer = imageBuffer;
debayer();
+ }
starsSearched = false;
@@ -263,10 +277,38 @@ bool FITSData::loadFITS (const QString &inFilename, bool silent)
int FITSData::saveFITS( const QString &newFilename )
{
+ if (newFilename == filename)
+ return 0;
+
int status=0, exttype=0;
long nelements;
fitsfile *new_fptr;
+ if (HasDebayer)
+ {
+ /* close current file */
+ if (fits_close_file(fptr, &status))
+ {
+ fits_report_error(stderr, status);
+ return status;
+ }
+
+ // Skip "!" in the beginning of the new file name
+ QFile::copy(filename, newFilename.mid(1));
+
+ if (tempFile)
+ {
+ QFile::remove(filename);
+ tempFile = false;
+ }
+
+ filename = newFilename;
+
+ fits_open_image(&fptr, filename.toLatin1(), READONLY, &status);
+
+ return 0;
+ }
+
nelements = stats.samples_per_channel * channels;
/* Create a new File, overwriting existing*/
@@ -288,27 +330,6 @@ int FITSData::saveFITS( const QString &newFilename )
return status;
}
- if (HasDebayer)
- {
- if (fits_close_file(fptr, &status))
- {
- fits_report_error(stderr, status);
- return status;
- }
-
- if (tempFile)
- {
- QFile::remove(filename);
- tempFile = false;
- }
-
- filename = newFilename;
-
- fptr = new_fptr;
-
- return 0;
- }
-
/* close current file */
if (fits_close_file(fptr, &status))
{
@@ -335,7 +356,7 @@ int FITSData::saveFITS( const QString &newFilename )
}
/* Write Data */
- if (fits_write_img(fptr, TFLOAT, 1, nelements, image_buffer, &status))
+ if (fits_write_img(fptr, data_type, 1, nelements, imageBuffer, &status))
{
fits_report_error(stderr, status);
return status;
@@ -406,12 +427,35 @@ int FITSData::saveFITS( const QString &newFilename )
void FITSData::clearImageBuffers()
{
- delete[] image_buffer;
- image_buffer=NULL;
- delete [] bayer_buffer;
- bayer_buffer=NULL;
+ delete[] imageBuffer;
+ imageBuffer=NULL;
+ bayerBuffer=NULL;
}
+void FITSData::calculateStats(bool refresh)
+{
+ // Calculate min max
+ calculateMinMax(refresh);
+
+ // Get standard deviation and mean in one run
+ switch(data_type)
+ {
+ case TBYTE:
+ runningAverageStdDev<uint8_t>();
+ break;
+
+ case TUSHORT:
+ runningAverageStdDev<uint16_t>();
+ break;
+ }
+
+ stats.SNR = stats.mean[0] / stats.stddev[0];
+
+ if (refresh && markStars)
+ // Let's try to find star positions again after transformation
+ starsSearched = false;
+
+}
int FITSData::calculateMinMax(bool refresh)
{
int status, nfound=0;
@@ -440,12 +484,32 @@ int FITSData::calculateMinMax(bool refresh)
stats.min[2]= 1.0E30;
stats.max[2]= -1.0E30;
+ switch(data_type)
+ {
+ case TBYTE:
+ calculateMinMax<uint8_t>();
+ break;
+
+ case TUSHORT:
+ calculateMinMax<uint16_t>();
+ break;
+ }
+
+
+ //qDebug() << "DATAMIN: " << stats.min << " - DATAMAX: " << stats.max;
+ return 0;
+}
+
+template<typename T> void FITSData::calculateMinMax()
+{
+ T *buffer = reinterpret_cast<T*>(imageBuffer);
+
if (channels == 1)
{
for (unsigned int i=0; i < stats.samples_per_channel; i++)
{
- if (image_buffer[i] < stats.min[0]) stats.min[0] = image_buffer[i];
- else if (image_buffer[i] > stats.max[0]) stats.max[0] = image_buffer[i];
+ if (buffer[i] < stats.min[0]) stats.min[0] = buffer[i];
+ else if (buffer[i] > stats.max[0]) stats.max[0] = buffer[i];
}
}
else
@@ -455,54 +519,36 @@ int FITSData::calculateMinMax(bool refresh)
for (unsigned int i=0; i < stats.samples_per_channel; i++)
{
- if (image_buffer[i] < stats.min[0])
- stats.min[0] = image_buffer[i];
- else if (image_buffer[i] > stats.max[0])
- stats.max[0] = image_buffer[i];
+ if (buffer[i] < stats.min[0])
+ stats.min[0] = buffer[i];
+ else if (buffer[i] > stats.max[0])
+ stats.max[0] = buffer[i];
- if (image_buffer[i+g_offset] < stats.min[1])
- stats.min[1] = image_buffer[i+g_offset];
- else if (image_buffer[i+g_offset] > stats.max[1])
- stats.max[1] = image_buffer[i+g_offset];
+ if (buffer[i+g_offset] < stats.min[1])
+ stats.min[1] = buffer[i+g_offset];
+ else if (buffer[i+g_offset] > stats.max[1])
+ stats.max[1] = buffer[i+g_offset];
- if (image_buffer[i+b_offset] < stats.min[2])
- stats.min[2] = image_buffer[i+b_offset];
- else if (image_buffer[i+b_offset] > stats.max[2])
- stats.max[2] = image_buffer[i+b_offset];
+ if (buffer[i+b_offset] < stats.min[2])
+ stats.min[2] = buffer[i+b_offset];
+ else if (buffer[i+b_offset] > stats.max[2])
+ stats.max[2] = buffer[i+b_offset];
}
}
-
- //qDebug() << "DATAMIN: " << stats.min << " - DATAMAX: " << stats.max;
- return 0;
}
-
-void FITSData::calculateStats(bool refresh)
+template<typename T> void FITSData::runningAverageStdDev()
{
- // Calculate min max
- calculateMinMax(refresh);
-
- // Get standard deviation and mean in one run
- runningAverageStdDev();
-
- stats.SNR = stats.mean[0] / stats.stddev[0];
-
- if (refresh && markStars)
- // Let's try to find star positions again after transformation
- starsSearched = false;
-
-}
+ T *buffer = reinterpret_cast<T*>(imageBuffer);
-void FITSData::runningAverageStdDev()
-{
int m_n = 2;
double m_oldM=0, m_newM=0, m_oldS=0, m_newS=0;
- m_oldM = m_newM = image_buffer[0];
+ m_oldM = m_newM = buffer[0];
for (unsigned int i=1; i < stats.samples_per_channel; i++)
{
- m_newM = m_oldM + (image_buffer[i] - m_oldM)/m_n;
- m_newS = m_oldS + (image_buffer[i] - m_oldM) * (image_buffer[i] - m_newM);
+ m_newM = m_oldM + (buffer[i] - m_oldM)/m_n;
+ m_newS = m_oldS + (buffer[i] - m_oldM) * (buffer[i] - m_newM);
m_oldM = m_newM;
m_oldS = m_newS;
@@ -560,11 +606,27 @@ bool FITSData::checkCollision(Edge* s1, Edge*s2)
int FITSData::findCannyStar(FITSData *data, const QRect &boundary)
{
+ switch(data->getDataType())
+ {
+ case TBYTE:
+ return FITSData::findCannyStar<uint8_t>(data, boundary);
+
+ case TUSHORT:
+ return FITSData::findCannyStar<uint16_t>(data, boundary);
+ }
+
+ return 0;
+}
+
+template<typename T> int FITSData::findCannyStar(FITSData *data, const QRect &boundary)
+{
int subX = boundary.isNull() ? 0 : boundary.x();
int subY = boundary.isNull() ? 0 : boundary.y();
int subW = (boundary.isNull() ? data->getWidth() : boundary.width());
int subH = (boundary.isNull() ? data->getHeight(): boundary.height());
+ int BBP = data->getBytesPerPixel();
+
uint16_t dataWidth = data->getWidth();
// #1 Find offsets
@@ -572,20 +634,20 @@ int FITSData::findCannyStar(FITSData *data, const QRect &boundary)
uint32_t offset = subX + subY * dataWidth;
// #2 Create new buffer
- float *buffer = new float[size];
+ uint8_t *buffer = new uint8_t[size*BBP];
// If there is no offset, copy whole buffer in one go
if (offset == 0)
- memcpy(buffer, data->getImageBuffer(), size * sizeof(float));
+ memcpy(buffer, data->getImageBuffer(), size*BBP);
else
{
- float *dataPtr = buffer;
- float *origDataPtr = data->getImageBuffer();
+ uint8_t *dataPtr = buffer;
+ uint8_t *origDataPtr = data->getImageBuffer();
// Copy data line by line
for (int height=subY; height < (subY+subH); height++)
{
- uint16_t lineOffset = subX + height * dataWidth;
- memcpy(dataPtr, origDataPtr + lineOffset, subW * sizeof(float));
- dataPtr += subW;
+ uint16_t lineOffset = (subX + height * dataWidth) * BBP;
+ memcpy(dataPtr, origDataPtr + lineOffset, subW * BBP);
+ dataPtr += (subW * BBP);
}
}
@@ -594,9 +656,12 @@ int FITSData::findCannyStar(FITSData *data, const QRect &boundary)
boundedImage->stats.width = subW;
boundedImage->stats.height = subH;
boundedImage->stats.bitpix = data->stats.bitpix;
+ boundedImage->stats.bytesPerPixel = data->stats.bytesPerPixel;
boundedImage->stats.samples_per_channel = size;
boundedImage->stats.ndim = 2;
+ boundedImage->setDataType(data->getDataType());
+
// #4 Set image buffer and calculate stats.
boundedImage->setImageBuffer(buffer);
@@ -612,7 +677,7 @@ int FITSData::findCannyStar(FITSData *data, const QRect &boundary)
// TODO Must trace neighbours and assign IDs to each shape so that they can be centered massed
// and discarded whenever necessary. It won't work on noisy images unless this is done.
- boundedImage->sobel(gradients, directions);
+ boundedImage->sobel<T>(gradients, directions);
QVector<int> ids(gradients.size());
@@ -697,7 +762,7 @@ int FITSData::findCannyStar(FITSData *data, const QRect &boundary)
break;
if (gradients[testX + testY * subW] > 0)
- //if (thresholded[testX + testY * subW] > 0)
+ //if (thresholded[testX + testY * subW] > 0)
{
if (++pass >= 24)
{
@@ -732,9 +797,9 @@ int FITSData::findCannyStar(FITSData *data, const QRect &boundary)
double leftEdge = center->x - center->width / 2.0;
QVector<double> subPixels;
- subPixels.reserve(center->width / resolution);
+ subPixels.reserve(center->width / resolution);
- const float *origBuffer = data->getImageBuffer() + offset;
+ const T *origBuffer = reinterpret_cast<T*>(data->getImageBuffer()) + offset;
QDebug deb = qDebug();
@@ -792,6 +857,20 @@ int FITSData::findCannyStar(FITSData *data, const QRect &boundary)
int FITSData::findOneStar(const QRectF &boundary)
{
+ switch (data_type)
+ {
+ case TBYTE:
+ return findOneStar<uint8_t>(boundary);
+
+ case TUSHORT:
+ return findOneStar<uint16_t>(boundary);
+ }
+
+ return 0;
+}
+
+template<typename T> int FITSData::findOneStar(const QRectF &boundary)
+{
int subX = boundary.x();
int subY = boundary.y();
int subW = subX + boundary.width();
@@ -799,6 +878,8 @@ int FITSData::findOneStar(const QRectF &boundary)
float massX=0, massY=0, totalMass=0;
+ T* buffer = reinterpret_cast<T*>(imageBuffer);
+
// TODO replace magic number with something more useful to understand
double threshold = stats.mean[0] * Options::focusThreshold()/100.0;
@@ -806,10 +887,9 @@ int FITSData::findOneStar(const QRectF &boundary)
{
for (int x=subX; x < subW; x++)
{
- float pixel = image_buffer[x+y*stats.width];
+ T pixel = buffer[x+y*stats.width];
if (pixel > threshold)
{
- //pixel *= pow(1000, pixel/stats.max[0]);
totalMass += pixel;
massX += x * pixel;
massY += y * pixel;
@@ -847,7 +927,7 @@ int FITSData::findOneStar(const QRectF &boundary)
if (testX < subX || testX > subW || testY < subY || testY > subH)
break;
- if (image_buffer[testX + testY * stats.width] > running_threshold)
+ if (buffer[testX + testY * stats.width] > running_threshold)
pass++;
}
@@ -855,8 +935,8 @@ int FITSData::findOneStar(const QRectF &boundary)
//if (pass >= 6)
if (pass >= 5)
{
- center->width = r*2;
- break;
+ center->width = r*2;
+ break;
}
}
@@ -890,7 +970,7 @@ int FITSData::findOneStar(const QRectF &boundary)
for (double x=leftEdge; x <= rightEdge; x += resolution)
{
//subPixels[x] = resolution * (image_buffer[static_cast<int>(floor(x)) + cen_y * stats.width] - min);
- double slice = resolution * (image_buffer[static_cast<int>(floor(x)) + cen_y * stats.width] - min);
+ double slice = resolution * (buffer[static_cast<int>(floor(x)) + cen_y * stats.width] - min);
FSum += slice;
subPixels.append(slice);
}
@@ -934,14 +1014,31 @@ int FITSData::findOneStar(const QRectF &boundary)
/*** Find center of stars and calculate Half Flux Radius */
void FITSData::findCentroid(const QRectF &boundary, int initStdDev, int minEdgeWidth)
{
+ switch (data_type)
+ {
+ case TBYTE:
+ findCentroid<uint8_t>(boundary, initStdDev, minEdgeWidth);
+ break;
+
+ case TUSHORT:
+ findCentroid<uint16_t>(boundary, initStdDev, minEdgeWidth);
+ break;
+ }
+}
+
+template<typename T> void FITSData::findCentroid(const QRectF &boundary, int initStdDev, int minEdgeWidth)
+{
double threshold=0,sum=0,avg=0,min=0;
int starDiameter=0;
int pixVal=0;
int minimumEdgeCount = MINIMUM_EDGE_LIMIT;
+ T *buffer = reinterpret_cast<T*>(imageBuffer);
+
double JMIndex = 100;
if (histogram)
JMIndex = histogram->getJMIndex();
+
float dispersion_ratio=1.5;
QList<Edge*> edges;
@@ -1022,14 +1119,14 @@ void FITSData::findCentroid(const QRectF &boundary, int initStdDev, int minEdgeW
subH = subY + boundary.height();
}
- // Detect "edges" that are above threshold
+ // Detect "edges" that are above threshold
for (int i=subY; i < subH; i++)
{
starDiameter = 0;
for(int j=subX; j < subW; j++)
{
- pixVal = image_buffer[j+(i*stats.width)] - min;
+ pixVal = buffer[j+(i*stats.width)] - min;
// If pixel value > threshold, let's get its weighted average
if ( pixVal >= threshold )
@@ -1050,14 +1147,14 @@ void FITSData::findCentroid(const QRectF &boundary, int initStdDev, int minEdgeW
int i_center = floor(center);
// Check if center is 10% or more brighter than edge, if not skip
- if ( ((image_buffer[i_center+(i*stats.width)]-min) / (image_buffer[i_center+(i*stats.width)-starDiameter/2]-min) >= dispersion_ratio) &&
- ((image_buffer[i_center+(i*stats.width)]-min) / (image_buffer[i_center+(i*stats.width)+starDiameter/2]-min) >= dispersion_ratio))
+ if ( ((buffer[i_center+(i*stats.width)]-min) / (buffer[i_center+(i*stats.width)-starDiameter/2]-min) >= dispersion_ratio) &&
+ ((buffer[i_center+(i*stats.width)]-min) / (buffer[i_center+(i*stats.width)+starDiameter/2]-min) >= dispersion_ratio))
{
if (Options::fITSLogging())
{
- qDebug() << "Edge center is " << image_buffer[i_center+(i*stats.width)]-min << " Edge is " << image_buffer[i_center+(i*stats.width)-starDiameter/2]-min
- << " and ratio is " << ((image_buffer[i_center+(i*stats.width)]-min) / (image_buffer[i_center+(i*stats.width)-starDiameter/2]-min))
- << " located at X: " << center << " Y: " << i+0.5;
+ qDebug() << "Edge center is " << buffer[i_center+(i*stats.width)]-min << " Edge is " << buffer[i_center+(i*stats.width)-starDiameter/2]-min
+ << " and ratio is " << ((buffer[i_center+(i*stats.width)]-min) / (buffer[i_center+(i*stats.width)-starDiameter/2]-min))
+ << " located at X: " << center << " Y: " << i+0.5;
}
Edge *newEdge = new Edge();
@@ -1065,7 +1162,7 @@ void FITSData::findCentroid(const QRectF &boundary, int initStdDev, int minEdgeW
newEdge->x = center;
newEdge->y = i + 0.5;
newEdge->scanned = 0;
- newEdge->val = image_buffer[i_center+(i*stats.width)] - min;
+ newEdge->val = buffer[i_center+(i*stats.width)] - min;
newEdge->width = starDiameter;
newEdge->HFR = 0;
newEdge->sum = sum;
@@ -1224,7 +1321,7 @@ void FITSData::findCentroid(const QRectF &boundary, int initStdDev, int minEdgeW
//for (int k=0; k < rCenter->width; k++)
for (int k=rCenter->width/2; k >= -(rCenter->width/2) ; k--)
{
- FSum += image_buffer[cen_x-k+(cen_y*stats.width)] - min;
+ FSum += buffer[cen_x-k+(cen_y*stats.width)] - min;
//qDebug() << image_buffer[cen_x-k+(cen_y*stats.width)] - min;
}
@@ -1232,7 +1329,7 @@ void FITSData::findCentroid(const QRectF &boundary, int initStdDev, int minEdgeW
HF = FSum / 2.0;
// Total flux starting from center
- TF = image_buffer[cen_y * stats.width + cen_x] - min;
+ TF = buffer[cen_y * stats.width + cen_x] - min;
int pixelCounter = 1;
@@ -1246,8 +1343,8 @@ void FITSData::findCentroid(const QRectF &boundary, int initStdDev, int minEdgeW
break;
}
- TF += image_buffer[cen_y * stats.width + cen_x + k] - min;
- TF += image_buffer[cen_y * stats.width + cen_x - k] - min;
+ TF += buffer[cen_y * stats.width + cen_x + k] - min;
+ TF += buffer[cen_y * stats.width + cen_x - k] - min;
pixelCounter++;
}
@@ -1355,26 +1452,94 @@ double FITSData::getHFR(int x, int y)
return -1;
}
-void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
+void FITSData::applyFilter(FITSScale type, uint8_t *image, float *min, float *max)
{
- if (type == FITS_NONE /* || histogram == NULL*/)
+ if (type == FITS_NONE)
return;
- double coeff=0;
- float val=0,bufferVal =0;
+ float dataMin=stats.min[0], dataMax=stats.max[0];
+
+ if (min && *min != -1)
+ dataMin = *min;
+ if (max && *max != -1)
+ dataMax = *max;
+
+ switch (type)
+ {
+ case FITS_AUTO_STRETCH:
+ {
+ dataMin = stats.mean[0] - stats.stddev[0];
+ dataMax = stats.mean[0] + stats.stddev[0] * 3;
+ //dataMin = 0;
+ //dataMax = pow(2, stats.bitpix) - 1;
+ }
+ break;
+
+ case FITS_HIGH_CONTRAST:
+ {
+ dataMin = stats.mean[0] + stats.stddev[0];
+ dataMax = stats.mean[0] + stats.stddev[0] * 3;
+ }
+ break;
+
+ case FITS_HIGH_PASS:
+ {
+ dataMin = stats.mean[0];
+ }
+ break;
+
+
+ default:
+ break;
+ }
+
+ switch (data_type)
+ {
+ case TBYTE:
+ {
+ dataMin = dataMin < 0 ? 0 : dataMin;
+ dataMax = dataMax > UINT8_MAX ? UINT8_MAX : dataMax;
+ applyFilter<uint8_t>(type, image, dataMin, dataMax);
+ }
+ break;
+
+ case TUSHORT:
+ {
+ dataMin = dataMin < 0 ? 0 : dataMin;
+ dataMax = dataMax > UINT16_MAX ? UINT16_MAX : dataMax;
+ applyFilter<uint16_t>(type, image, dataMin, dataMax);
+ }
+ break;
+ }
+
+ if (min)
+ *min = dataMin;
+ if (max)
+ *max = dataMax;
+}
+
+template<typename T> void FITSData::applyFilter(FITSScale type, uint8_t *targetImage, float image_min, float image_max)
+{
int offset=0, row=0;
+ double coeff=0;
+ bool calcStats = false;
+
+ T bufferVal =0, val= 0;
+ T *image = NULL;
- if (image == NULL)
- image = image_buffer;
+ if (targetImage)
+ image = reinterpret_cast<T*>(targetImage);
+ else
+ {
+ image = reinterpret_cast<T*>(imageBuffer);
+ calcStats = true;
+ }
int width = stats.width;
int height = stats.height;
- if (min == -1)
- min = stats.min[0];
- if (max == -1)
- max = stats.max[0];
+ T min = image_min, max = image_max;
int size = stats.samples_per_channel;
int index=0;
@@ -1384,7 +1549,6 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
case FITS_AUTO:
case FITS_LINEAR:
{
-
for (int i=0; i < channels; i++)
{
offset = i*size;
@@ -1397,14 +1561,17 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
bufferVal = image[index];
if (bufferVal < min) bufferVal = min;
else if (bufferVal > max) bufferVal = max;
- image_buffer[index] = bufferVal;
+ image[index] = bufferVal;
}
}
}
- stats.min[0] = min;
- stats.max[0] = max;
- //runningAverageStdDev();
+ if (calcStats)
+ {
+ stats.min[0] = min;
+ stats.max[0] = max;
+ }
+
}
break;
@@ -1425,15 +1592,18 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
if (bufferVal < min) bufferVal = min;
else if (bufferVal > max) bufferVal = max;
val = (coeff * log(1 + qBound(min, image[index], max)));
- image_buffer[index] = qBound(min, val, max);
+ image[index] = qBound(min, val, max);
}
}
}
- stats.min[0] = min;
- stats.max[0] = max;
- runningAverageStdDev();
+ if (calcStats)
+ {
+ stats.min[0] = min;
+ stats.max[0] = max;
+ runningAverageStdDev<T>();
+ }
}
break;
@@ -1451,21 +1621,24 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
{
index=k + row;
val = (int) (coeff * sqrt(qBound(min, image[index], max)));
- image_buffer[index] = val;
+ image[index] = val;
}
}
}
- stats.min[0] = min;
- stats.max[0] = max;
- runningAverageStdDev();
+ if (calcStats)
+ {
+ stats.min[0] = min;
+ stats.max[0] = max;
+ runningAverageStdDev<T>();
+ }
}
break;
case FITS_AUTO_STRETCH:
- {
- min = stats.mean[0] - stats.stddev[0];
- max = stats.mean[0] + stats.stddev[0] * 3;
+ {
+ /*double alpha = (pow(2, stats.bitpix) - 1) / (stats.max[0]-stats.min[0]);
+ double beta = (-1 * stats.min[0]) * alpha;
for (int i=0; i < channels; i++)
{
@@ -1476,24 +1649,34 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
for (int k=0; k < width; k++)
{
index=k + row;
- image_buffer[index] = qBound(min, image[index], max);
+ //image[index] = qBound(min, image[index], max);
+ image[index] = static_cast<T>((alpha * image[index] + beta));
}
}
+ }*/
+
+ for (int i=0; i < channels; i++)
+ {
+ offset = i*size;
+ for (int j=0; j < height; j++)
+ {
+ row = offset + j * width;
+ for (int k=0; k < width; k++)
+ image[k + row] = qBound(min, image[k + row], max);
+ }
}
- stats.min[0] = min;
- stats.max[0] = max;
- runningAverageStdDev();
+ if (calcStats)
+ {
+ stats.min[0] = min;
+ stats.max[0] = max;
+ runningAverageStdDev<T>();
+ }
}
break;
case FITS_HIGH_CONTRAST:
{
- min = stats.mean[0] + stats.stddev[0];
- if (min < 0)
- min =0;
- max = stats.mean[0] + stats.stddev[0] * 3;
-
for (int i=0; i < channels; i++)
{
offset = i*size;
@@ -1503,13 +1686,18 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
for (int k=0; k < width; k++)
{
index=k + row;
- image_buffer[index] = qBound(min, image[index], max);
+ image[index] = qBound(min, image[index], max);
}
}
}
- stats.min[0] = min;
- stats.max[0] = max;
- runningAverageStdDev();
+
+ if (calcStats)
+ {
+ stats.min[0] = min;
+ stats.max[0] = max;
+ runningAverageStdDev<T>();
+ }
+
}
break;
@@ -1536,12 +1724,13 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
val = (int) (coeff * cumulativeFreq[bufferVal]);
- image_buffer[index] = val;
+ image[index] = val;
}
}
}
}
- calculateStats(true);
+ if (calcStats)
+ calculateStats(true);
break;
case FITS_HIGH_PASS:
@@ -1556,21 +1745,25 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
for (int k=0; k < width; k++)
{
index=k + row;
- image_buffer[index] = qBound(min, image[index], max);
+ image[index] = qBound(min, image[index], max);
}
}
}
- stats.min[0] = min;
- stats.max[0] = max;
- runningAverageStdDev();
+ if (calcStats)
+ {
+ stats.min[0] = min;
+ stats.max[0] = max;
+ runningAverageStdDev<T>();
+ }
}
break;
- // Based on http://www.librow.com/articles/article-1
+ // Based on http://www.librow.com/articles/article-1
case FITS_MEDIAN:
{
- float* extension = new float[(width + 2) * (height + 2)];
+ int BBP = stats.bytesPerPixel;
+ T* extension = new T[(width + 2) * (height + 2)];
// Check memory allocation
if (!extension)
return;
@@ -1582,18 +1775,19 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
for (int i = 0; i < M; ++i)
{
- memcpy(extension + (N + 2) * (i + 1) + 1, image_buffer + N * i + offset, N * sizeof(float));
- extension[(N + 2) * (i + 1)] = image_buffer[N * i + offset];
- extension[(N + 2) * (i + 2) - 1] = image_buffer[N * (i + 1) - 1 + offset];
+ memcpy(extension + (N + 2) * (i + 1) + 1, image + (N * i) + offset, N * BBP);
+ extension[(N + 2) * (i + 1)] = image[N * i + offset];
+ extension[(N + 2) * (i + 2) - 1] = image[N * (i + 1) - 1 + offset];
}
// Fill first line of image extension
- memcpy(extension, extension + N + 2, (N + 2) * sizeof(float));
+ memcpy(extension, extension + N + 2, (N + 2) * BBP);
// Fill last line of image extension
- memcpy(extension + (N + 2) * (M + 1), extension + (N + 2) * M, (N + 2) * sizeof(float));
+ memcpy(extension + (N + 2) * (M + 1), extension + (N + 2) * M, (N + 2) * BBP);
// Call median filter implementation
N=width+2;
M=height+2;
+
// Move window through all elements of the image
for (int m = 1; m < M - 1; ++m)
for (int n = 1; n < N - 1; ++n)
@@ -1618,34 +1812,36 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
window[mine] = temp;
}
// Get result - the middle element
- image_buffer[(m - 1) * (N - 2) + n - 1 + offset] = window[4];
+ image[(m - 1) * (N - 2) + n - 1 + offset] = window[4];
}
}
// Free memory
delete[] extension;
- runningAverageStdDev();
+
+ if (calcStats)
+ runningAverageStdDev<T>();
}
break;
case FITS_ROTATE_CW:
- rotFITS(90, 0);
+ rotFITS<T>(90, 0);
rotCounter++;
break;
case FITS_ROTATE_CCW:
- rotFITS(270, 0);
+ rotFITS<T>(270, 0);
rotCounter--;
break;
case FITS_FLIP_H:
- rotFITS(0, 1);
+ rotFITS<T>(0, 1);
flipHCounter++;
break;
case FITS_FLIP_V:
- rotFITS(0, 2);
+ rotFITS<T>(0, 2);
flipVCounter++;
break;
@@ -1654,13 +1850,12 @@ void FITSData::applyFilter(FITSScale type, float *image, float min, float max)
return;
break;
}
-
}
int FITSData::findStars(const QRectF &boundary, bool force)
{
//if (histogram == NULL)
- //return -1;
+ //return -1;
if (starsSearched == false || force)
{
@@ -1717,6 +1912,7 @@ bool FITSData::checkWCS()
if ((status = wcspih(header, nkeyrec, WCSHDR_all, -3, &nreject, &nwcs, &wcs)))
{
+ free(header);
fprintf(stderr, "wcspih ERROR %d: %s.\n", status, wcshdr_errmsg[status]);
return false;
}
@@ -1828,22 +2024,22 @@ void FITSData::findObjectsInImage(struct wcsprm *wcs, double world[], double phi
int x=-100;
int y=-100;
- world[0]=object->ra0().Degrees();
- world[1]=object->dec0().Degrees();
-
- if ((status = wcss2p(wcs, 1, 2, &world[0], &phi, &theta, &imgcrd[0], &pixcrd[0], &stat[0])))
- {
- fprintf(stderr, "wcsp2s ERROR %d: %s.\n", status, wcs_errmsg[status]);
- }
- else
- {
- x = pixcrd[0];//The X and Y are set to the found position if it does work.
- y = pixcrd[1];
- }
+ world[0]=object->ra0().Degrees();
+ world[1]=object->dec0().Degrees();
- if(x>0&&y>0&&x<width&&y<height)
- objList.append(new FITSSkyObject(object,x,y));
+ if ((status = wcss2p(wcs, 1, 2, &world[0], &phi, &theta, &imgcrd[0], &pixcrd[0], &stat[0])))
+ {
+ fprintf(stderr, "wcsp2s ERROR %d: %s.\n", status, wcs_errmsg[status]);
+ }
+ else
+ {
+ x = pixcrd[0];//The X and Y are set to the found position if it does work.
+ y = pixcrd[1];
}
+
+ if(x>0&&y>0&&x<width&&y<height)
+ objList.append(new FITSSkyObject(object,x,y));
+ }
}
delete (num);
@@ -1918,11 +2114,11 @@ void FITSData::setRotCounter(int value)
* verbose generates extra info on stdout.
* return NULL if successful or rotated image.
*/
-bool FITSData::rotFITS (int rotate, int mirror)
+template<typename T> bool FITSData::rotFITS (int rotate, int mirror)
{
int ny, nx;
int x1, y1, x2, y2;
- float *rotimage = NULL;
+ uint8_t *rotimage = NULL;
int offset=0;
if (rotate == 1)
@@ -1937,14 +2133,20 @@ bool FITSData::rotFITS (int rotate, int mirror)
nx = stats.width;
ny = stats.height;
+ int BBP = stats.bytesPerPixel;
+
/* Allocate buffer for rotated image */
- rotimage = new float[stats.samples_per_channel*channels];
+ rotimage = new uint8_t[stats.samples_per_channel*channels*BBP];
+
if (rotimage == NULL)
{
qWarning() << "Unable to allocate memory for rotated image buffer!";
return false;
}
+ T * rotBuffer = reinterpret_cast<T*>(rotimage);
+ T * buffer = reinterpret_cast<T*>(imageBuffer);
+
/* Mirror image without rotation */
if (rotate < 45 && rotate > -45)
{
@@ -1957,7 +2159,7 @@ bool FITSData::rotFITS (int rotate, int mirror)
{
x2 = nx - x1 - 1;
for (y1 = 0; y1 < ny; y1++)
- rotimage[(y1*nx) + x2 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y1*nx) + x2 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
@@ -1971,7 +2173,7 @@ bool FITSData::rotFITS (int rotate, int mirror)
{
y2 = ny - y1 - 1;
for (x1 = 0; x1 < nx; x1++)
- rotimage[(y2*nx) + x1 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y2*nx) + x1 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
@@ -1984,10 +2186,9 @@ bool FITSData::rotFITS (int rotate, int mirror)
for (y1 = 0; y1 < ny; y1++)
{
for (x1 = 0; x1 < nx; x1++)
- rotimage[(y1*nx) + x1 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y1*nx) + x1 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
-
}
}
@@ -2005,11 +2206,10 @@ bool FITSData::rotFITS (int rotate, int mirror)
for (x1 = 0; x1 < nx; x1++)
{
y2 = nx - x1 - 1;
- rotimage[(y2*ny) + x2 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y2*ny) + x2 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
}
-
}
else if (mirror == 2)
{
@@ -2019,10 +2219,9 @@ bool FITSData::rotFITS (int rotate, int mirror)
for (y1 = 0; y1 < ny; y1++)
{
for (x1 = 0; x1 < nx; x1++)
- rotimage[(x1*ny) + y1 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(x1*ny) + y1 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
-
}
else
{
@@ -2035,11 +2234,10 @@ bool FITSData::rotFITS (int rotate, int mirror)
for (x1 = 0; x1 < nx; x1++)
{
y2 = x1;
- rotimage[(y2*ny) + x2 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y2*ny) + x2 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
}
-
}
stats.width = ny;
@@ -2058,10 +2256,9 @@ bool FITSData::rotFITS (int rotate, int mirror)
{
y2 = ny - y1 - 1;
for (x1 = 0; x1 < nx; x1++)
- rotimage[(y2*nx) + x1 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y2*nx) + x1 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
-
}
else if (mirror == 2)
{
@@ -2072,7 +2269,7 @@ bool FITSData::rotFITS (int rotate, int mirror)
{
x2 = nx - x1 - 1;
for (y1 = 0; y1 < ny; y1++)
- rotimage[(y1*nx) + x2 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y1*nx) + x2 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
}
@@ -2087,7 +2284,7 @@ bool FITSData::rotFITS (int rotate, int mirror)
for (x1 = 0; x1 < nx; x1++)
{
x2 = nx - x1 - 1;
- rotimage[(y2*nx) + x2 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y2*nx) + x2 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
}
@@ -2105,7 +2302,7 @@ bool FITSData::rotFITS (int rotate, int mirror)
for (y1 = 0; y1 < ny; y1++)
{
for (x1 = 0; x1 < nx; x1++)
- rotimage[(x1*ny) + y1 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(x1*ny) + y1 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
}
@@ -2120,7 +2317,7 @@ bool FITSData::rotFITS (int rotate, int mirror)
for (x1 = 0; x1 < nx; x1++)
{
y2 = nx - x1 - 1;
- rotimage[(y2*ny) + x2 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y2*ny) + x2 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
}
@@ -2136,7 +2333,7 @@ bool FITSData::rotFITS (int rotate, int mirror)
for (x1 = 0; x1 < nx; x1++)
{
y2 = nx - x1 - 1;
- rotimage[(y2*ny) + x2 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y2*ny) + x2 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
}
@@ -2158,14 +2355,14 @@ bool FITSData::rotFITS (int rotate, int mirror)
{
x2 = y1;
y2 = x1;
- rotimage[(y2*ny) + x2 + offset] = image_buffer[(y1*nx) + x1 + offset];
+ rotBuffer[(y2*ny) + x2 + offset] = buffer[(y1*nx) + x1 + offset];
}
}
}
}
- delete[] image_buffer;
- image_buffer = rotimage;
+ delete[] imageBuffer;
+ imageBuffer = rotimage;
return true;
}
@@ -2464,20 +2661,19 @@ void FITSData::rotWCSFITS (int angle, int mirror)
return;
}
-float * FITSData::getImageBuffer()
+uint8_t *FITSData::getImageBuffer()
{
- return image_buffer;
+ return imageBuffer;
}
-void FITSData::setImageBuffer(float *buffer)
+void FITSData::setImageBuffer(uint8_t *buffer)
{
- delete[] image_buffer;
- image_buffer = buffer;
+ delete[] imageBuffer;
+ imageBuffer = buffer;
}
bool FITSData::checkDebayer()
{
-
int status=0;
char bayerPattern[64];
@@ -2500,7 +2696,7 @@ bool FITSData::checkDebayer()
else if (pattern == "GRBG")
debayerParams.filter = DC1394_COLOR_FILTER_GRBG;
else if (pattern == "BGGR")
- debayerParams.filter = DC1394_COLOR_FILTER_BGGR;
+ debayerParams.filter = DC1394_COLOR_FILTER_BGGR;
// We return unless we find a valid pattern
else
return false;
@@ -2508,19 +2704,9 @@ bool FITSData::checkDebayer()
fits_read_key(fptr, TINT, "XBAYROFF", &debayerParams.offsetX, NULL, &status);
fits_read_key(fptr, TINT, "YBAYROFF", &debayerParams.offsetY, NULL, &status);
- delete[] bayer_buffer;
- bayer_buffer = new float[stats.samples_per_channel * channels];
- if (bayer_buffer == NULL)
- {
- KMessageBox::error(NULL, i18n("Unable to allocate memory for bayer buffer."), i18n("Open FITS"));
- return false;
- }
- memcpy(bayer_buffer, image_buffer, stats.samples_per_channel * channels * sizeof(float));
-
HasDebayer = true;
return true;
-
}
void FITSData::getBayerParams(BayerParams *param)
@@ -2541,59 +2727,179 @@ void FITSData::setBayerParams(BayerParams *param)
bool FITSData::debayer()
{
+ if (bayerBuffer == NULL)
+ {
+ int anynull=0, status=0;
+
+ bayerBuffer = imageBuffer;
+
+ if (fits_read_img(fptr, data_type, 1, stats.samples_per_channel, 0, bayerBuffer, &anynull, &status))
+ {
+ char errmsg[512];
+ fits_get_errstatus(status, errmsg);
+ KMessageBox::error(NULL, i18n("Error reading image: %1", QString(errmsg)));
+ return false;
+ }
+ }
+
+ switch (data_type)
+ {
+ case TBYTE:
+ return debayer_8bit();
+
+ case TUSHORT:
+ return debayer_16bit();
+
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+bool FITSData::debayer_8bit()
+{
dc1394error_t error_code;
- int rgb_size = stats.samples_per_channel*3;
- float * dst = new float[rgb_size];
- if (dst == NULL)
+ int rgb_size = stats.samples_per_channel*3*stats.bytesPerPixel;
+ uint8_t * destinationBuffer = new uint8_t[rgb_size];
+
+ if (destinationBuffer == NULL)
{
KMessageBox::error(NULL, i18n("Unable to allocate memory for temporary bayer buffer."), i18n("Debayer Error"));
return false;
}
- if ( (error_code = dc1394_bayer_decoding_float(bayer_buffer, dst, stats.width, stats.height, debayerParams.offsetX, debayerParams.offsetY,
- debayerParams.filter, debayerParams.method)) != DC1394_SUCCESS)
+ int ds1394_height = stats.height;
+ uint8_t * dc1394_source = bayerBuffer;
+
+ if (debayerParams.offsetY == 1)
+ {
+ dc1394_source += stats.width;
+ ds1394_height--;
+ }
+
+ if (debayerParams.offsetX == 1)
+ {
+ dc1394_source++;
+ }
+
+ error_code = dc1394_bayer_decoding_8bit(dc1394_source, destinationBuffer, stats.width, ds1394_height, debayerParams.filter, debayerParams.method);
+
+ if ( error_code != DC1394_SUCCESS)
{
KMessageBox::error(NULL, i18n("Debayer failed (%1)", error_code), i18n("Debayer error"));
channels=1;
- delete[] dst;
- //Restore buffer
- delete[] image_buffer;
- image_buffer = new float[stats.samples_per_channel];
- memcpy(image_buffer, bayer_buffer, stats.samples_per_channel * sizeof(float));
+ delete[] destinationBuffer;
return false;
}
if (channels == 1)
{
- delete[] image_buffer;
- image_buffer = new float[rgb_size];
+ delete[] imageBuffer;
+ imageBuffer = new uint8_t[rgb_size];
- if (image_buffer == NULL)
+ if (imageBuffer == NULL)
{
- delete[] dst;
+ delete[] destinationBuffer;
KMessageBox::error(NULL, i18n("Unable to allocate memory for debayerd buffer."), i18n("Debayer Error"));
return false;
}
}
// Data in R1G1B1, we need to copy them into 3 layers for FITS
- float * rBuff = image_buffer;
- float * gBuff = image_buffer + (stats.width * stats.height);
- float * bBuff = image_buffer + (stats.width * stats.height * 2);
+
+ uint8_t * rBuff = imageBuffer;
+ uint8_t * gBuff = imageBuffer + (stats.width * stats.height);
+ uint8_t * bBuff = imageBuffer + (stats.width * stats.height * 2);
int imax = stats.samples_per_channel*3 - 3;
for (int i=0; i <= imax; i += 3)
{
- *rBuff++ = dst[i];
- *gBuff++ = dst[i+1];
- *bBuff++ = dst[i+2];
+ *rBuff++ = destinationBuffer[i];
+ *gBuff++ = destinationBuffer[i+1];
+ *bBuff++ = destinationBuffer[i+2];
}
channels=3;
- delete[] dst;
+ delete[] destinationBuffer;
+ bayerBuffer = NULL;
return true;
+}
+
+bool FITSData::debayer_16bit()
+{
+ dc1394error_t error_code;
+ int rgb_size = stats.samples_per_channel*3*stats.bytesPerPixel;
+ uint8_t * destinationBuffer = new uint8_t[rgb_size];
+
+ uint16_t * buffer = reinterpret_cast<uint16_t*>(bayerBuffer);
+ uint16_t * dstBuffer = reinterpret_cast<uint16_t*>(destinationBuffer);
+
+ if (destinationBuffer == NULL)
+ {
+ KMessageBox::error(NULL, i18n("Unable to allocate memory for temporary bayer buffer."), i18n("Debayer Error"));
+ return false;
+ }
+
+ int ds1394_height = stats.height;
+ uint16_t * dc1394_source = buffer;
+
+ if (debayerParams.offsetY == 1)
+ {
+ dc1394_source += stats.width;
+ ds1394_height--;
+ }
+
+ if (debayerParams.offsetX == 1)
+ {
+ dc1394_source++;
+ }
+
+ error_code = dc1394_bayer_decoding_16bit(dc1394_source, dstBuffer, stats.width, ds1394_height, debayerParams.filter, debayerParams.method, 16);
+
+ if ( error_code != DC1394_SUCCESS)
+ {
+ KMessageBox::error(NULL, i18n("Debayer failed (%1)", error_code), i18n("Debayer error"));
+ channels=1;
+ delete[] destinationBuffer;
+ return false;
+ }
+
+ if (channels == 1)
+ {
+ delete[] imageBuffer;
+ imageBuffer = new uint8_t[rgb_size];
+
+ if (imageBuffer == NULL)
+ {
+ delete[] destinationBuffer;
+ KMessageBox::error(NULL, i18n("Unable to allocate memory for debayerd buffer."), i18n("Debayer Error"));
+ return false;
+ }
+ }
+
+ buffer = reinterpret_cast<uint16_t*>(imageBuffer);
+
+ // Data in R1G1B1, we need to copy them into 3 layers for FITS
+
+ uint16_t * rBuff = buffer;
+ uint16_t * gBuff = buffer + (stats.width * stats.height);
+ uint16_t * bBuff = buffer + (stats.width * stats.height * 2);
+
+ int imax = stats.samples_per_channel*3 - 3;
+ for (int i=0; i <= imax; i += 3)
+ {
+ *rBuff++ = dstBuffer[i];
+ *gBuff++ = dstBuffer[i+1];
+ *bBuff++ = dstBuffer[i+2];
+ }
+
+ channels=3;
+ delete[] destinationBuffer;
+ bayerBuffer = NULL;
+ return true;
}
double FITSData::getADU()
@@ -2647,18 +2953,18 @@ void FITSData::sobel(const QImage &image, QVector<int> &gradient, QVector<int> &
int x_p1 = x >= image.width() - 1? x: x + 1;
int gradX = grayLine_m1[x_p1]
- + 2 * grayLine[x_p1]
- + grayLine_p1[x_p1]
- - grayLine_m1[x_m1]
- - 2 * grayLine[x_m1]
- - grayLine_p1[x_m1];
+ + 2 * grayLine[x_p1]
+ + grayLine_p1[x_p1]
+ - grayLine_m1[x_m1]
+ - 2 * grayLine[x_m1]
+ - grayLine_p1[x_m1];
int gradY = grayLine_m1[x_m1]
- + 2 * grayLine_m1[x]
- + grayLine_m1[x_p1]
- - grayLine_p1[x_m1]
- - 2 * grayLine_p1[x]
- - grayLine_p1[x_p1];
+ + 2 * grayLine_m1[x]
+ + grayLine_m1[x_p1]
+ - grayLine_p1[x_m1]
+ - 2 * grayLine_p1[x]
+ - grayLine_p1[x_p1];
gradientLine[x] = qAbs(gradX) + qAbs(gradY);
@@ -2709,7 +3015,7 @@ void FITSData::sobel(const QImage &image, QVector<int> &gradient, QVector<int> &
}
#endif
-void FITSData::sobel(QVector<float> &gradient, QVector<float> &direction)
+template<typename T> void FITSData::sobel(QVector<float> &gradient, QVector<float> &direction)
{
//int size = image.width() * image.height();
gradient.resize(stats.samples_per_channel);
@@ -2718,10 +3024,10 @@ void FITSData::sobel(QVector<float> &gradient, QVector<float> &direction)
for (int y = 0; y < stats.height; y++)
{
size_t yOffset = y * stats.width;
- const float *grayLine = image_buffer + yOffset;
+ const T *grayLine = reinterpret_cast<T*>(imageBuffer) + yOffset;
- const float *grayLine_m1 = y < 1? grayLine: grayLine - stats.width;
- const float *grayLine_p1 = y >= stats.height - 1? grayLine: grayLine + stats.width;
+ const T *grayLine_m1 = y < 1? grayLine: grayLine - stats.width;
+ const T *grayLine_p1 = y >= stats.height - 1? grayLine: grayLine + stats.width;
float *gradientLine = gradient.data() + yOffset;
float *directionLine = direction.data() + yOffset;
@@ -2732,18 +3038,18 @@ void FITSData::sobel(QVector<float> &gradient, QVector<float> &direction)
int x_p1 = x >= stats.width - 1? x: x + 1;
int gradX = grayLine_m1[x_p1]
- + 2 * grayLine[x_p1]
- + grayLine_p1[x_p1]
- - grayLine_m1[x_m1]
- - 2 * grayLine[x_m1]
- - grayLine_p1[x_m1];
+ + 2 * grayLine[x_p1]
+ + grayLine_p1[x_p1]
+ - grayLine_m1[x_m1]
+ - 2 * grayLine[x_m1]
+ - grayLine_p1[x_m1];
int gradY = grayLine_m1[x_m1]
- + 2 * grayLine_m1[x]
- + grayLine_m1[x_p1]
- - grayLine_p1[x_m1]
- - 2 * grayLine_p1[x]
- - grayLine_p1[x_p1];
+ + 2 * grayLine_m1[x]
+ + grayLine_m1[x_p1]
+ - grayLine_p1[x_m1]
+ - 2 * grayLine_p1[x]
+ - grayLine_p1[x_p1];
gradientLine[x] = qAbs(gradX) + qAbs(gradY);
@@ -2807,7 +3113,7 @@ int FITSData::partition(int width, int height, QVector<float> &gradient, QVector
float val = gradient[index];
if (val > 0 && ids[index] == 0)
{
- trace(width, height, ++id, gradient, ids, x, y);
+ trace(width, height, ++id, gradient, ids, x, y);
}
}
@@ -2879,7 +3185,7 @@ QVector<int> FITSData::thinning(int width, int height, const QVector<int> &gradi
* x x x
*/
if (gradientLine[x] < gradientLine[x_m1]
- || gradientLine[x] < gradientLine[x_p1])
+ || gradientLine[x] < gradientLine[x_p1])
pixel = 0;
else
pixel = gradientLine[x];
@@ -2889,7 +3195,7 @@ QVector<int> FITSData::thinning(int width, int height, const QVector<int> &gradi
* / x x
*/
if (gradientLine[x] < gradientLine_m1[x_p1]
- || gradientLine[x] < gradientLine_p1[x_m1])
+ || gradientLine[x] < gradientLine_p1[x_m1])
pixel = 0;
else
pixel = gradientLine[x];
@@ -2899,7 +3205,7 @@ QVector<int> FITSData::thinning(int width, int height, const QVector<int> &gradi
* x x \
*/
if (gradientLine[x] < gradientLine_m1[x_m1]
- || gradientLine[x] < gradientLine_p1[x_p1])
+ || gradientLine[x] < gradientLine_p1[x_p1])
pixel = 0;
else
pixel = gradientLine[x];
@@ -2909,7 +3215,7 @@ QVector<int> FITSData::thinning(int width, int height, const QVector<int> &gradi
* x | x
*/
if (gradientLine[x] < gradientLine_m1[x]
- || gradientLine[x] < gradientLine_p1[x])
+ || gradientLine[x] < gradientLine_p1[x])
pixel = 0;
else
pixel = gradientLine[x];
@@ -2928,8 +3234,8 @@ QVector<float> FITSData::threshold(int thLow, int thHi, const QVector<float> &im
for (int i = 0; i < image.size(); i++)
thresholded[i] = image[i] <= thLow? 0:
- image[i] >= thHi? 255:
- 127;
+ image[i] >= thHi? 255:
+ 127;
return thresholded;
}
diff --git a/kstars/fitsviewer/fitsdata.h b/kstars/fitsviewer/fitsdata.h
index 68d6d3c..39ba120 100644
--- a/kstars/fitsviewer/fitsdata.h
+++ b/kstars/fitsviewer/fitsdata.h
@@ -111,17 +111,17 @@ public:
/* Rescale image lineary from image_buffer, fit to window if desired */
int rescale(FITSZoom type);
/* Calculate stats */
- void calculateStats(bool refresh=false);
- /* Calculate running average & standard deviation using Welford’s method for computing variance */
- void runningAverageStdDev();
+ void calculateStats(bool refresh=false);
// Access functions
void clearImageBuffers();
- void setImageBuffer(float *buffer);
- float * getImageBuffer();
+ void setImageBuffer(uint8_t *buffer);
+ uint8_t * getImageBuffer();
- // Stats
int getDataType() { return data_type; }
+ void setDataType(int value) { data_type = value; }
+
+ // Stats
unsigned int getSize() { return stats.samples_per_channel; }
void getDimensions(uint16_t *w, uint16_t *h) { *w = stats.width; *h = stats.height; }
void setWidth(uint16_t w) { stats.width = w; stats.samples_per_channel = stats.width * stats.height;}
@@ -142,6 +142,7 @@ public:
void setMedian(double val, uint8_t channel=0) { stats.median[channel] = val;}
double getMedian(uint8_t channel=0) { return stats.median[channel];}
+ int getBytesPerPixel() { return stats.bytesPerPixel; }
void setSNR(double val) { stats.SNR = val;}
double getSNR() { return stats.SNR;}
void setBPP(int value) { stats.bitpix = value;}
@@ -160,6 +161,7 @@ public:
// Find single star based on partially customized Canny edge detection
static int findCannyStar(FITSData *data, const QRect &boundary = QRect());
+ template<typename T> static int findCannyStar(FITSData *data, const QRect &boundary);
// Half Flux Radius
Edge * getMaxHFRStar() { return maxHFRStar;}
@@ -177,6 +179,8 @@ public:
// Debayer
bool hasDebayer() { return HasDebayer; }
bool debayer();
+ bool debayer_8bit();
+ bool debayer_16bit();
void getBayerParams(BayerParams *param);
void setBayerParams(BayerParams *param);
@@ -189,7 +193,7 @@ public:
void setHistogram(FITSHistogram *inHistogram) { histogram = inHistogram; }
// Filter
- void applyFilter(FITSScale type, float *image=NULL, float min=-1, float max=-1);
+ void applyFilter(FITSScale type, uint8_t *image=NULL, float * min= NULL, float * max= NULL);
// Rotation counter. We keep count to rotate WCS keywords on save
int getRotCounter() const;
@@ -215,15 +219,33 @@ public:
private:
- bool rotFITS (int rotate, int mirror);
+
void rotWCSFITS (int angle, int mirror);
bool checkCollision(Edge* s1, Edge*s2);
int calculateMinMax(bool refresh=false);
bool checkDebayer();
void readWCSKeys();
+ // Templated functions
+
+ template<typename T> bool debayer();
+
+ template<typename T> bool rotFITS (int rotate, int mirror);
+
+ // Apply Filter
+ template<typename T> void applyFilter(FITSScale type, uint8_t *targetImage, float image_min, float image_max);
+ // Star Detect - Centroid
+ template<typename T> void findCentroid(const QRectF &boundary, int initStdDev, int minEdgeWidth);
+ // Star Detect - Threshold
+ template<typename T> int findOneStar(const QRectF &boundary);
+
+
+ template<typename T> void calculateMinMax();
+ /* Calculate running average & standard deviation using Welford’s method for computing variance */
+ template<typename T> void runningAverageStdDev();
+
// Sobel detector by Gonzalo Exequiel Pedone
- void sobel(QVector<float> &gradient, QVector<float> &direction);
+ template<typename T> void sobel(QVector<float> &gradient, QVector<float> &direction);
// Give unique IDs to each contigous region
int partition(int width, int height, QVector<float> &gradient, QVector<int> &ids);
@@ -240,7 +262,7 @@ private:
int data_type; // FITS image data type (TBYTE, TUSHORT, TINT, TFLOAT, TLONGLONG, TDOUBLE)
int channels; // Number of channels
- float *image_buffer; // Current image buffer
+ uint8_t *imageBuffer = NULL; // Generic data image buffer
bool tempFile; // Is this a tempoprary file or one loaded from disk?
@@ -260,7 +282,7 @@ private:
QList<Edge*> starCenters; // All the stars we detected, if any.
Edge* maxHFRStar; // The biggest fattest star in the image.
- float *bayer_buffer; // Bayer buffer
+ uint8_t *bayerBuffer = NULL;
BayerParams debayerParams; // Bayer parameters
/* stats struct to hold statisical data about the FITS data */
@@ -272,14 +294,12 @@ private:
double median[3];
double SNR;
int bitpix;
+ int bytesPerPixel;
int ndim;
uint32_t samples_per_channel;
uint16_t width;
uint16_t height;
} stats;
-
-
-
};
#endif
diff --git a/kstars/fitsviewer/fitshistogram.cpp b/kstars/fitsviewer/fitshistogram.cpp
index 9aec501..a0e83eb 100644
--- a/kstars/fitsviewer/fitshistogram.cpp
+++ b/kstars/fitsviewer/fitshistogram.cpp
@@ -99,11 +99,27 @@ FITSHistogram::~FITSHistogram()
}
void FITSHistogram::constructHistogram()
-{
- uint16_t fits_w=0, fits_h=0;
+{
+ FITSData *image_data = tab->getView()->getImageData();
+ switch (image_data->getDataType())
+ {
+ case TBYTE:
+ constructHistogram<uint8_t>();
+ break;
+
+ case TUSHORT:
+ constructHistogram<uint16_t>();
+ break;
+ }
+}
+
+template<typename T> void FITSHistogram::constructHistogram()
+{
+ uint16_t fits_w=0, fits_h=0;
FITSData *image_data = tab->getView()->getImageData();
- float *buffer = image_data->getImageBuffer();
+
+ T *buffer = reinterpret_cast<T*>(image_data->getImageBuffer());
image_data->getDimensions(&fits_w, &fits_h);
image_data->getMinMax(&fits_min, &fits_max);
@@ -155,7 +171,6 @@ void FITSHistogram::constructHistogram()
}
}
-
// Cumuliative Frequency
for (int i=0; i < binCount; i++)
for (int j=0; j <= i; j++)
@@ -357,16 +372,15 @@ FITSHistogramCommand::~FITSHistogramCommand()
delete(delta);
}
-bool FITSHistogramCommand::calculateDelta(unsigned char *buffer)
+bool FITSHistogramCommand::calculateDelta(uint8_t *buffer)
{
FITSData *image_data = tab->getView()->getImageData();
- unsigned char *image_buffer = (unsigned char *) image_data->getImageBuffer();
+ uint8_t *image_buffer = image_data->getImageBuffer();
int totalPixels = image_data->getSize() * image_data->getNumOfChannels();
- unsigned long totalBytes = totalPixels * sizeof(float);
- //qDebug() << "raw total bytes " << totalBytes << " bytes" << endl;
+ unsigned long totalBytes = totalPixels * image_data->getBytesPerPixel();
- unsigned char *raw_delta = new unsigned char[totalBytes];
+ uint8_t *raw_delta = new uint8_t[totalBytes];
if (raw_delta == NULL)
{
qWarning() << "Error! not enough memory to create image delta" << endl;
@@ -376,13 +390,13 @@ bool FITSHistogramCommand::calculateDelta(unsigned char *buffer)
for (unsigned int i=0; i < totalBytes; i++)
raw_delta[i] = buffer[i] ^ image_buffer[i];
- compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3;
- delete(delta);
- delta = new unsigned char[compressedBytes];
+ compressedBytes = sizeof(uint8_t) * totalBytes + totalBytes / 64 + 16 + 3;
+ delete [] delta;
+ delta = new uint8_t[compressedBytes];
if (delta == NULL)
{
- delete(raw_delta);
+ delete [] raw_delta;
qDebug() << "FITSHistogram Error: Ran out of memory compressing delta" << endl;
return false;
}
@@ -397,7 +411,7 @@ bool FITSHistogramCommand::calculateDelta(unsigned char *buffer)
//qDebug() << "compressed bytes size " << compressedBytes << " bytes" << endl;
- delete(raw_delta);
+ delete [] raw_delta;
return true;
}
@@ -406,22 +420,22 @@ bool FITSHistogramCommand::reverseDelta()
{
FITSView *image = tab->getView();
FITSData *image_data = image->getImageData();
- unsigned char *image_buffer = (unsigned char *) (image_data->getImageBuffer());
+ uint8_t *image_buffer = (image_data->getImageBuffer());
unsigned int size = image_data->getSize();
int channels = image_data->getNumOfChannels();
int totalPixels = size * channels;
- unsigned long totalBytes = totalPixels * sizeof(float);
+ unsigned long totalBytes = totalPixels * image_data->getBytesPerPixel();
- unsigned char *output_image = new unsigned char[totalBytes];
+ uint8_t *output_image = new uint8_t[totalBytes];
if (output_image == NULL)
{
qWarning() << "Error! not enough memory to create output image" << endl;
return false;
}
- unsigned char *raw_delta = new unsigned char[totalBytes];
+ uint8_t *raw_delta = new uint8_t[totalBytes];
if (raw_delta == NULL)
{
delete(output_image);
@@ -433,16 +447,16 @@ bool FITSHistogramCommand::reverseDelta()
if (r != Z_OK)
{
qDebug() << "FITSHistogram compression error in reverseDelta()" << endl;
- delete(raw_delta);
+ delete [] raw_delta;
return false;
}
for (unsigned int i=0; i < totalBytes; i++)
output_image[i] = raw_delta[i] ^ image_buffer[i];
- image_data->setImageBuffer((float *)output_image);
+ image_data->setImageBuffer(output_image);
- delete(raw_delta);
+ delete [] raw_delta;
return true;
}
@@ -452,9 +466,10 @@ void FITSHistogramCommand::redo()
FITSView *image = tab->getView();
FITSData *image_data = image->getImageData();
- float *image_buffer = image_data->getImageBuffer();
+ uint8_t *image_buffer = image_data->getImageBuffer();
unsigned int size = image_data->getSize();
- int channels = image_data->getNumOfChannels();
+ int channels = image_data->getNumOfChannels();
+ int BBP = image_data->getBytesPerPixel();
QApplication::setOverrideCursor(Qt::WaitCursor);
@@ -485,7 +500,7 @@ void FITSHistogramCommand::redo()
}
else
{
- float *buffer = new float[size * channels];
+ uint8_t *buffer = new uint8_t[size * channels * BBP];
if (buffer == NULL)
{
qWarning() << "Error! not enough memory to create image buffer in redo()" << endl;
@@ -493,30 +508,31 @@ void FITSHistogramCommand::redo()
return;
}
- memcpy(buffer, image_buffer, size * channels * sizeof(float));
+ memcpy(buffer, image_buffer, size * channels * BBP);
+ float dataMin = min, dataMax = max;
switch (type)
{
case FITS_AUTO:
case FITS_LINEAR:
- image_data->applyFilter(FITS_LINEAR, image_buffer, min, max);
+ image_data->applyFilter(FITS_LINEAR, NULL, &dataMin, &dataMax);
break;
case FITS_LOG:
- image_data->applyFilter(FITS_LOG, image_buffer, min, max);
+ image_data->applyFilter(FITS_LOG, NULL, &dataMin, &dataMax);
break;
case FITS_SQRT:
- image_data->applyFilter(FITS_SQRT, image_buffer, min, max);
+ image_data->applyFilter(FITS_SQRT, NULL, &dataMin, &dataMax);
break;
default:
- image_data->applyFilter(type, image_buffer);
+ image_data->applyFilter(type);
break;
}
- calculateDelta( (unsigned char *) buffer);
- delete (buffer);
+ calculateDelta(buffer);
+ delete [] buffer;
}
}
@@ -528,11 +544,11 @@ void FITSHistogramCommand::redo()
image_data->findStars();
}
+ image->pushFilter(type);
image->rescale(ZOOM_KEEP_LEVEL);
image->updateFrame();
QApplication::restoreOverrideCursor();
-
}
void FITSHistogramCommand::undo()
@@ -586,6 +602,7 @@ void FITSHistogramCommand::undo()
image_data->findStars();
}
+ image->popFilter();
image->rescale(ZOOM_KEEP_LEVEL);
image->updateFrame();
diff --git a/kstars/fitsviewer/fitshistogram.h b/kstars/fitsviewer/fitshistogram.h
index b876603..054ca9a 100644
--- a/kstars/fitsviewer/fitshistogram.h
+++ b/kstars/fitsviewer/fitshistogram.h
@@ -77,6 +77,8 @@ public slots:
private:
+ template<typename T> void constructHistogram();
+
histogramUI *ui;
FITSTab *tab;
@@ -122,7 +124,7 @@ private:
long dim[2];
} stats;
- bool calculateDelta(unsigned char *buffer);
+ bool calculateDelta(uint8_t *buffer);
bool reverseDelta();
void saveStats(double min, double max, double stddev, double mean, double median, double SNR);
void restoreStats();
@@ -134,7 +136,7 @@ private:
unsigned char *delta;
unsigned long compressedBytes;
- float *original_buffer;
+ uint8_t *original_buffer;
FITSTab *tab;
};
diff --git a/kstars/fitsviewer/fitsview.cpp b/kstars/fitsviewer/fitsview.cpp
index 5563abd..d76781b 100644
--- a/kstars/fitsviewer/fitsview.cpp
+++ b/kstars/fitsviewer/fitsview.cpp
@@ -168,7 +168,7 @@ void FITSLabel::mouseMoveEvent(QMouseEvent *e)
double x,y;
FITSData *image_data = image->getImageData();
- float *buffer = image_data->getImageBuffer();
+ uint8_t *buffer = image_data->getImageBuffer();
if (buffer == NULL)
return;
@@ -185,10 +185,24 @@ void FITSLabel::mouseMoveEvent(QMouseEvent *e)
x -= 1;
y -= 1;
- if (image_data->getBPP() == -32 || image_data->getBPP() == 32)
- emit newStatus(QLocale().toString(buffer[(int) (y * width + x)], 'f', 4), FITS_VALUE);
- else
- emit newStatus(QLocale().toString(buffer[(int) (y * width + x)], 'f', 2), FITS_VALUE);
+ QString stringValue;
+
+ switch(image_data->getDataType())
+ {
+ case TBYTE:
+ {
+ stringValue = QLocale().toString(buffer[(int) (y * width + x)]);
+ }
+ break;
+
+ case TUSHORT:
+ {
+ stringValue = QLocale().toString( (reinterpret_cast<uint16_t*>(buffer)) [(int) (y * width + x)]);
+ }
+ break;
+ }
+
+ emit newStatus(stringValue, FITS_VALUE);
if (image_data->hasWCS()&&image->getMouseMode()!=FITSView::selectMouse)
@@ -429,6 +443,8 @@ FITSView::FITSView(QWidget * parent, FITSMode fitsMode, FITSScale filterType) :
filter = filterType;
mode = fitsMode;
+ filterStack.push(filterType);
+
setBackgroundRole(QPalette::Dark);
markerCrosshair.setX(0);
@@ -580,36 +596,44 @@ int FITSView::saveFITS( const QString &newFilename )
int FITSView::rescale(FITSZoom type)
{
+ switch(image_data->getDataType())
+ {
+ case TBYTE:
+ return rescale<uint8_t>(type);
+
+ case TUSHORT:
+ return rescale<uint16_t>(type);
+
+ }
+
+ return 0;
+}
+
+template<typename T> int FITSView::rescale(FITSZoom type)
+{
double val=0;
double bscale, bzero;
double min, max;
- float *image_buffer = image_data->getImageBuffer();
- float *display_buffer = image_buffer;
+ bool displayBuffer = false;
+
+ uint8_t *image_buffer = image_data->getImageBuffer();
+
uint32_t size = image_data->getSize();
+ int BBP = image_data->getBytesPerPixel();
+
+ filter = filterStack.last();
- if (Options::autoStretch() && filter == FITS_NONE)
+ if (Options::autoStretch() && (filter == FITS_NONE || (filter >= FITS_ROTATE_CW && filter <= FITS_FLIP_V )))
{
- display_buffer = new float[image_data->getSize() * image_data->getNumOfChannels()];
- memset(display_buffer, 0, image_data->getSize() * image_data->getNumOfChannels() * sizeof(float));
+ image_buffer = new uint8_t[image_data->getSize() * image_data->getNumOfChannels() * BBP];
+ memcpy(image_buffer, image_data->getImageBuffer(), image_data->getSize() * image_data->getNumOfChannels() * BBP);
- float data_min = image_data->getMean(0) - image_data->getStdDev(0);
- float data_max = image_data->getMean(0) + image_data->getStdDev(0) * 3;
- uint16_t data_w = image_data->getWidth();
- uint16_t data_h = image_data->getHeight();
+ displayBuffer = true;
- for (int i=0; i < image_data->getNumOfChannels(); i++)
- {
- int offset = i*size;
- for (int j=0; j < data_h; j++)
- {
- int row = offset + j * data_w;
- for (int k=0; k < data_w; k++)
- {
- int index=k + row;
- display_buffer[index] = qBound(data_min, image_buffer[index], data_max);
- }
- }
- }
+ float data_min = -1;
+ float data_max = -1;
+
+ image_data->applyFilter(FITS_AUTO_STRETCH, image_buffer, &data_min, &data_max);
min = data_min;
max = data_max;
@@ -617,6 +641,8 @@ int FITSView::rescale(FITSZoom type)
else
image_data->getMinMax(&min, &max);
+ T *buffer = reinterpret_cast<T*>(image_buffer);
+
if (min == max)
{
display_image->fill(Qt::white);
@@ -651,7 +677,7 @@ int FITSView::rescale(FITSZoom type)
for (int i = 0; i < image_width; i++)
{
- val = display_buffer[j * image_width + i];
+ val = buffer[j * image_width + i];
scanLine[i]= (val * bscale + bzero);
}
}
@@ -667,24 +693,20 @@ int FITSView::rescale(FITSZoom type)
for (int i = 0; i < image_width; i++)
{
- rval = display_buffer[j * image_width + i];
- gval = display_buffer[j * image_width + i + size];
- bval = display_buffer[j * image_width + i + size * 2];
+ rval = buffer[j * image_width + i];
+ gval = buffer[j * image_width + i + size];
+ bval = buffer[j * image_width + i + size * 2];
value = qRgb(rval* bscale + bzero, gval* bscale + bzero, bval* bscale + bzero);
- //display_image->setPixel(i, j, value);
scanLine[i] = value;
-
}
}
-
}
-
}
- if (display_buffer != image_buffer)
- delete [] display_buffer;
+ if (displayBuffer)
+ delete [] image_buffer;
switch (type)
{
diff --git a/kstars/fitsviewer/fitsview.h b/kstars/fitsviewer/fitsview.h
index ff93b8d..6b81db8 100644
--- a/kstars/fitsviewer/fitsview.h
+++ b/kstars/fitsviewer/fitsview.h
@@ -168,6 +168,9 @@ public:
void setFirstLoad(bool value);
+ void pushFilter(FITSScale value) { filterStack.push(value); }
+ FITSScale popFilter() { return filterStack.pop(); }
+
protected:
void wheelEvent(QWheelEvent* event);
@@ -188,6 +191,8 @@ private:
bool gestureEvent(QGestureEvent *event);
void pinchTriggered(QPinchGesture *gesture);
+ template<typename T> int rescale(FITSZoom type);
+
double average();
double stddev();
void calculateMaxPixel(double min, double max);
@@ -228,6 +233,8 @@ private:
FITSMode mode;
FITSScale filter;
+ QStack<FITSScale> filterStack;
+
// Cross hair
QPointF markerCrosshair;
diff --git a/kstars/indi/indidevice.cpp b/kstars/indi/indidevice.cpp
index c36edd5..b29ff26 100644
--- a/kstars/indi/indidevice.cpp
+++ b/kstars/indi/indidevice.cpp
@@ -289,15 +289,14 @@ void INDI_D::updateMessageLog(INDI::BaseDevice *idv, int messageID)
INDI_D::~INDI_D()
{
- /* while ( ! gl.isEmpty() ) delete gl.takeFirst();
+ while ( ! groupsList.isEmpty() ) delete groupsList.takeFirst();
- delete(deviceVBox);
+ /*delete(deviceVBox);
delete (stdDev);
free (dataBuffer);
dataBuffer = NULL;
deviceVBox = NULL;
- stdDev = NULL;
- */
+ stdDev = NULL;*/
}
INDI_G * INDI_D::getGroup (const QString & groupName)
diff --git a/kstars/kstars.kcfg b/kstars/kstars.kcfg
index b53d586..6f217e8 100644
--- a/kstars/kstars.kcfg
+++ b/kstars/kstars.kcfg
@@ -1288,6 +1288,10 @@
<label>Automatically debayer a FITS image if it is contains a bayer pattern</label>
<default>true</default>
</entry>
+ <entry name="auto3DCube" type="Bool">
+ <label>Process 3D FITS Cube (RGB). If false, only first channel is processed.</label>
+ <default>true</default>
+ </entry>
</group>
<group name="WISettings">
<entry name="BortleClass" type="UInt">
diff --git a/kstars/options/opsadvanced.ui b/kstars/options/opsadvanced.ui
index cd77bec..ecfb178 100644
--- a/kstars/options/opsadvanced.ui
+++ b/kstars/options/opsadvanced.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>723</width>
- <height>486</height>
+ <width>584</width>
+ <height>418</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
@@ -170,87 +170,83 @@
<property name="title">
<string>FITS Viewer</string>
</property>
- <layout class="QVBoxLayout" name="verticalLayout_7">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QCheckBox" name="kcfg_singlePreviewFITS">
- <property name="toolTip">
- <string>Display all captured FITS images in a single tab instead of multiple tabs per image.</string>
- </property>
- <property name="statusTip">
- <string/>
- </property>
- <property name="whatsThis">
- <string/>
- </property>
- <property name="text">
- <string>Preview Mode</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="kcfg_singleWindowCapturedFITS">
- <property name="toolTip">
- <string>Display captured FITS images from all cameras in a single FITS Viewer window instead of a dedicated window to each camera.</string>
- </property>
- <property name="whatsThis">
- <string/>
- </property>
- <property name="text">
- <string>Single Window Capture</string>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="kcfg_singleWindowOpenedFITS">
- <property name="toolTip">
- <string>Display opened FITS images in a single FITS Viewer window instead of a dedicated window to each file.</string>
- </property>
- <property name="whatsThis">
- <string/>
- </property>
- <property name="text">
- <string>Single Window Open</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="kcfg_independentWindowFITS">
- <property name="toolTip">
- <string>Make FITS Viewer window independent from KStars</string>
- </property>
- <property name="text">
- <string>Independent Window</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="kcfg_singlePreviewFITS">
+ <property name="toolTip">
+ <string>Display all captured FITS images in a single tab instead of multiple tabs per image.</string>
+ </property>
+ <property name="statusTip">
+ <string/>
+ </property>
+ <property name="whatsThis">
+ <string/>
+ </property>
+ <property name="text">
+ <string>Preview Mode</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
</item>
- <item>
+ <item row="0" column="1">
+ <widget class="QCheckBox" name="kcfg_singleWindowCapturedFITS">
+ <property name="toolTip">
+ <string>Display captured FITS images from all cameras in a single FITS Viewer window instead of a dedicated window to each camera.</string>
+ </property>
+ <property name="whatsThis">
+ <string/>
+ </property>
+ <property name="text">
+ <string>Single Window Capture</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QCheckBox" name="kcfg_singleWindowOpenedFITS">
+ <property name="toolTip">
+ <string>Display opened FITS images in a single FITS Viewer window instead of a dedicated window to each file.</string>
+ </property>
+ <property name="whatsThis">
+ <string/>
+ </property>
+ <property name="text">
+ <string>Single Window Open</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QCheckBox" name="kcfg_independentWindowFITS">
+ <property name="toolTip">
+ <string>Make FITS Viewer window independent from KStars</string>
+ </property>
+ <property name="text">
+ <string>Independent Window</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="kcfg_AutoStretch">
+ <property name="toolTip">
+ <string>Always apply auto stretch to images in FITS Viewer</string>
+ </property>
+ <property name="text">
+ <string>Auto Stretch</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
<widget class="QCheckBox" name="kcfg_autoDebayerFITS">
+ <property name="toolTip">
+ <string>Automatially debayer captured image if it contains a bayer pattern</string>
+ </property>
<property name="text">
<string>Auto Debayer</string>
</property>
@@ -259,6 +255,16 @@
</property>
</widget>
</item>
+ <item row="1" column="2">
+ <widget class="QCheckBox" name="kcfg_auto3DCube">
+ <property name="toolTip">
+ <string>Process 3D (RGB) FITS images. If unchecked, only first channel is processed.</string>
+ </property>
+ <property name="text">
+ <string>3D Cube</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>