90 lines
2.1 KiB
C++
90 lines
2.1 KiB
C++
#ifndef DUST3D_IMAGE_SKELETON_EXTRACTOR_H
|
|
#define DUST3D_IMAGE_SKELETON_EXTRACTOR_H
|
|
#include <QImage>
|
|
#include <QObject>
|
|
#include <vector>
|
|
#include <set>
|
|
|
|
class ImageSkeletonExtractor : QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
const std::vector<std::pair<int, int>> neighborOffsets = {
|
|
{ 0, -1},
|
|
{ 1, -1},
|
|
{ 1, 0},
|
|
{ 1, 1},
|
|
{ 0, 1},
|
|
{-1, 1},
|
|
{-1, 0},
|
|
{-1, -1},
|
|
};
|
|
enum {
|
|
P2 = 0,
|
|
P3,
|
|
P4,
|
|
P5,
|
|
P6,
|
|
P7,
|
|
P8,
|
|
P9
|
|
};
|
|
|
|
~ImageSkeletonExtractor();
|
|
void setImage(QImage *image);
|
|
void extract();
|
|
QImage *takeResultGrayscaleImage();
|
|
void getSkeleton(std::vector<std::pair<int, int>> *skeleton);
|
|
int getArea();
|
|
const std::set<std::pair<int, int>> &getBlackPixels();
|
|
private:
|
|
QImage *m_image = nullptr;
|
|
QImage *m_grayscaleImage = nullptr;
|
|
int m_area = 0;
|
|
std::set<std::pair<int, int>> m_blackPixels;
|
|
|
|
bool isBlack(int i, int j)
|
|
{
|
|
return QColor(m_grayscaleImage->pixel(i, j)).black() > 0;
|
|
}
|
|
|
|
bool isWhite(int i, int j)
|
|
{
|
|
return !isBlack(i, j);
|
|
}
|
|
|
|
void setWhite(int i, int j)
|
|
{
|
|
m_grayscaleImage->setPixel(i, j, qRgb(255, 255, 255));
|
|
}
|
|
|
|
int countNeighborTransitions(int i, int j)
|
|
{
|
|
int num = 0;
|
|
for (size_t m = 0; m < neighborOffsets.size(); ++m) {
|
|
size_t n = (m + 1) % neighborOffsets.size();
|
|
if (isWhite(i + neighborOffsets[m].first, j + neighborOffsets[m].second) &&
|
|
isBlack(i + neighborOffsets[n].first, j + neighborOffsets[n].second)) {
|
|
++num;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
int countBlackNeighbors(int i, int j)
|
|
{
|
|
int num = 0;
|
|
for (const auto &it: neighborOffsets) {
|
|
if (isBlack(i + it.first, j + it.second))
|
|
++num;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
bool firstSubiterationSatisfied(int i, int j);
|
|
bool secondSubiterationSatisfied(int i, int j);
|
|
void calculateAreaAndBlackPixels();
|
|
};
|
|
|
|
#endif
|