Commit c63569a7 authored by Jasem Mutlaq's avatar Jasem Mutlaq
Browse files

Adding initial canny edge detector

parent 4ad48a3b
......@@ -1854,6 +1854,16 @@ bool FITSData::rotFITS (int rotate, int mirror)
return true;
}
/*
QVariant FITSData::getFITSHeaderValue(const QString &keyword){
QVariant property;
int status=0;
char comment[100];
fits_read_key_dbl(fptr, keyword, &property, comment, &status );
return property;
}
*/
void FITSData::rotWCSFITS (int angle, int mirror)
{
int status=0;
......@@ -2279,3 +2289,233 @@ double FITSData::getADU()
return (adu/ (double) channels);
}
/* CannyDetector, Implementation of Canny edge detector in Qt/C++.
* Copyright (C) 2015 Gonzalo Exequiel Pedone
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Email : hipersayan DOT x AT gmail DOT com
* Web-Site: http://github.com/hipersayanX/CannyDetector
*/
void FITSData::sobel(const QImage &image, QVector<int> &gradient, QVector<int> &direction)
{
int size = image.width() * image.height();
gradient.resize(size);
direction.resize(size);
for (int y = 0; y < image.height(); y++) {
size_t yOffset = y * image.width();
const quint8 *grayLine = image.constBits() + yOffset;
const quint8 *grayLine_m1 = y < 1? grayLine: grayLine - image.width();
const quint8 *grayLine_p1 = y >= image.height() - 1? grayLine: grayLine + image.width();
int *gradientLine = gradient.data() + yOffset;
int *directionLine = direction.data() + yOffset;
for (int x = 0; x < image.width(); x++) {
int x_m1 = x < 1? x: x - 1;
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];
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];
gradientLine[x] = qAbs(gradX) + qAbs(gradY);
/* Gradient directions are classified in 4 possible cases
*
* dir 0
*
* x x x
* - - -
* x x x
*
* dir 1
*
* x x /
* x / x
* / x x
*
* dir 2
*
* \ x x
* x \ x
* x x \
*
* dir 3
*
* x | x
* x | x
* x | x
*/
if (gradX == 0 && gradY == 0)
directionLine[x] = 0;
else if (gradX == 0)
directionLine[x] = 3;
else {
qreal a = 180. * atan(qreal(gradY) / gradX) / M_PI;
if (a >= -22.5 && a < 22.5)
directionLine[x] = 0;
else if (a >= 22.5 && a < 67.5)
directionLine[x] = 1;
else if (a >= -67.5 && a < -22.5)
directionLine[x] = 2;
else
directionLine[x] = 3;
}
}
}
}
QVector<int> FITSData::thinning(int width, int height, const QVector<int> &gradient, const QVector<int> &direction)
{
QVector<int> thinned(gradient.size());
for (int y = 0; y < height; y++) {
int yOffset = y * width;
const int *gradientLine = gradient.constData() + yOffset;
const int *gradientLine_m1 = y < 1? gradientLine: gradientLine - width;
const int *gradientLine_p1 = y >= height - 1? gradientLine: gradientLine + width;
const int *directionLine = direction.constData() + yOffset;
int *thinnedLine = thinned.data() + yOffset;
for (int x = 0; x < width; x++) {
int x_m1 = x < 1? 0: x - 1;
int x_p1 = x >= width - 1? x: x + 1;
int direction = directionLine[x];
int pixel = 0;
if (direction == 0) {
/* x x x
* - - -
* x x x
*/
if (gradientLine[x] < gradientLine[x_m1]
|| gradientLine[x] < gradientLine[x_p1])
pixel = 0;
else
pixel = gradientLine[x];
} else if (direction == 1) {
/* x x /
* x / x
* / x x
*/
if (gradientLine[x] < gradientLine_m1[x_p1]
|| gradientLine[x] < gradientLine_p1[x_m1])
pixel = 0;
else
pixel = gradientLine[x];
} else if (direction == 2) {
/* \ x x
* x \ x
* x x \
*/
if (gradientLine[x] < gradientLine_m1[x_m1]
|| gradientLine[x] < gradientLine_p1[x_p1])
pixel = 0;
else
pixel = gradientLine[x];
} else {
/* x | x
* x | x
* x | x
*/
if (gradientLine[x] < gradientLine_m1[x]
|| gradientLine[x] < gradientLine_p1[x])
pixel = 0;
else
pixel = gradientLine[x];
}
thinnedLine[x] = pixel;
}
}
return thinned;
}
QVector<int> FITSData::threshold(int thLow, int thHi, const QVector<int> &image)
{
QVector<int> thresholded(image.size());
for (int i = 0; i < image.size(); i++)
thresholded[i] = image[i] <= thLow? 0:
image[i] >= thHi? 255:
127;
return thresholded;
}
void FITSData::trace(int width, int height, QVector<int> &image, int x, int y)
{
int yOffset = y * width;
int *cannyLine = image.data() + yOffset;
if (cannyLine[x] != 255)
return;
for (int j = -1; j < 2; j++) {
int nextY = y + j;
if (nextY < 0 || nextY >= height)
continue;
int *cannyLineNext = cannyLine + j * width;
for (int i = -1; i < 2; i++) {
int nextX = x + i;
if (i == j || nextX < 0 || nextX >= width)
continue;
if (cannyLineNext[nextX] == 127) {
// Mark pixel as white.
cannyLineNext[nextX] = 255;
// Trace neighbors.
trace(width, height, image, nextX, nextY);
}
}
}
}
QVector<int> FITSData::hysteresis(int width, int height, const QVector<int> &image)
{
QVector<int> canny(image);
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
trace(width, height, canny, x, y);
// Remaining gray pixels becomes black.
for (int i = 0; i < canny.size(); i++)
if (canny[i] == 127)
canny[i] = 0;
return canny;
}
......@@ -46,9 +46,6 @@
#include "dms.h"
#include "bayer.h"
#define INITIAL_W 640
#define INITIAL_H 480
#define MINIMUM_PIXEL_RANGE 5
#define MINIMUM_STDVAR 5
......@@ -159,6 +156,8 @@ public:
// FITS Record
int getFITSRecord(QString &recordList, int &nkeys);
// QVariant getFITSHeaderValue(QString &keyword);
// Histogram
void setHistogram(FITSHistogram *inHistogram) { histogram = inHistogram; }
......@@ -210,6 +209,13 @@ private:
bool checkDebayer();
void readWCSKeys();
// Canny Edge detector by Gonzalo Exequiel Pedone
void sobel(const QImage &image, QVector<int> &gradient, QVector<int> &direction);
QVector<int> thinning(int width, int height, const QVector<int> &gradient, const QVector<int> &direction);
QVector<int> threshold(int thLow, int thHi, const QVector<int> &image);
void trace(int width, int height, QVector<int> &image, int x, int y);
QVector<int> hysteresis(int width, int height, const QVector<int> &image);
FITSHistogram *histogram; // Pointer to the FITS data histogram
fitsfile* fptr; // Pointer to CFITSIO FITS file struct
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment