tahoma2d/toonz/sources/common/trop/tdespeckle.cpp

721 lines
21 KiB
C++
Raw Normal View History

2016-03-19 06:57:51 +13:00
#include "tropcm.h"
// TnzCore includes
#include "tpalette.h"
#include "trop_borders.h"
#include "pixelselectors.h"
#include "runsmap.h"
#define INCLUDE_HPP
#include "raster_edge_iterator.h"
#include "borders_extractor.h"
#define INCLUDE_HPP
// tcg includes
#include "tcg/deleter_types.h"
// STL includes
#include <deque>
/*============================================================================================
Explanation
2016-06-15 18:43:10 +12:00
Despeckling is a noise-removal procedure which aims at eliminating small blots
of color
2016-03-19 06:57:51 +13:00
from an image.
2016-06-15 18:43:10 +12:00
We will assume that speckles are recognized with uniform color (which means -
image
2016-03-19 06:57:51 +13:00
discretization should be externally performed).
2016-06-15 18:43:10 +12:00
We will currently assume that the despeckling procedure works only on the ink
or paint plane of a
2016-03-19 06:57:51 +13:00
TRasterCM32 instance, not both (should be extended in the future).
2016-06-15 18:43:10 +12:00
The image is traversed to isolate regions with the same color and, if their
area is
2016-03-19 06:57:51 +13:00
below the specified threshold, they get removed or changed of color.
2016-06-15 18:43:10 +12:00
Color change looks at the area's neighbouring pixels for the most used color
to use for
replacement. If NO neighbouring color can be found, the area is made
transparent.
2016-03-19 06:57:51 +13:00
==============================================================================================*/
using namespace TRop::borders;
2016-06-15 18:43:10 +12:00
namespace {
2016-03-19 06:57:51 +13:00
//************************************************************************
// Pixel Selectors
//************************************************************************
2016-06-15 18:43:10 +12:00
class InkSelectorCM32 {
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
typedef TPixelCM32 pixel_type;
typedef TUINT32 value_type;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
InkSelectorCM32() {}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
value_type transparent() const { return 0; }
bool transparent(const pixel_type &pix) const { return value(pix) == 0; }
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
value_type value(const pixel_type &pix) const { return pix.getInk(); }
bool equal(const pixel_type &a, const pixel_type &b) const {
return value(a) == value(b);
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
bool skip(const value_type &prevLeftValue,
const value_type &leftValue) const {
return true;
}
2016-03-19 06:57:51 +13:00
};
//------------------------------------------------------------------------------------------
template <typename PIXEL, typename CHANNEL>
2016-06-15 18:43:10 +12:00
class InkSelectorRGBM {
bool m_transparentIsWhite;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
typedef PIXEL pixel_type;
typedef CHANNEL value_type;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
InkSelectorRGBM(bool transparentIsWhite)
: m_transparentIsWhite(transparentIsWhite) {}
value_type transparent() const { return 0; }
bool transparent(const pixel_type &pix) const { return value(pix) == 0; }
value_type value(const pixel_type &pix) const {
if (m_transparentIsWhite)
return (pix == PIXEL::White) ? 0 : 1;
else
return (pix.m == 0) ? 0 : 1;
}
bool equal(const pixel_type &a, const pixel_type &b) const {
return value(a) == value(b);
}
bool skip(const value_type &prevLeftValue,
const value_type &leftValue) const {
return true;
}
2016-03-19 06:57:51 +13:00
};
//------------------------------------------------------------------------------------------
template <typename PIXEL, typename CHANNEL>
2016-06-15 18:43:10 +12:00
class InkSelectorGR {
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
typedef PIXEL pixel_type;
typedef CHANNEL value_type;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
InkSelectorGR() {}
value_type transparent() const { return PIXEL::maxChannelValue; }
bool transparent(const pixel_type &pix) const { return value(pix) == 0; }
value_type value(const pixel_type &pix) const {
return (pix.value == PIXEL::maxChannelValue) ? 0 : 1;
}
bool equal(const pixel_type &a, const pixel_type &b) const {
return value(a) == value(b);
}
bool skip(const value_type &prevLeftValue,
const value_type &leftValue) const {
return true;
}
2016-03-19 06:57:51 +13:00
};
//************************************************************************
// Border class
//************************************************************************
struct Border {
2016-06-15 18:43:10 +12:00
std::vector<TPoint> m_points;
int m_x0, m_y0, m_x1, m_y1;
Border()
: m_x0((std::numeric_limits<int>::max)())
, m_y0(m_x0)
, m_x1(-m_x0)
, m_y1(m_x1) {}
void addPoint(const TPoint &p) {
// Update the region box
if (p.x < m_x0) m_x0 = p.x;
if (p.x > m_x1) m_x1 = p.x;
if (p.y < m_y0) m_y0 = p.y;
if (p.y > m_y1) m_y1 = p.y;
// Add the vertex
m_points.push_back(p);
}
void clear() {
m_points.clear();
m_x0 = (std::numeric_limits<int>::max)(), m_y0 = m_x0, m_x1 = -m_x0,
m_y1 = m_x1;
}
2016-03-19 06:57:51 +13:00
};
//************************************************************************
// Base classes
//************************************************************************
//========================================================================
// Borders Painter
//========================================================================
template <typename Pix>
2016-06-15 18:43:10 +12:00
class BordersPainter {
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
typedef Pix pixel_type;
2016-03-19 06:57:51 +13:00
protected:
2016-06-15 18:43:10 +12:00
TRasterPT<pixel_type> m_ras;
RunsMapP m_runsMap;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
BordersPainter(const TRasterPT<pixel_type> &ras) : m_ras(ras) {}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
const TRasterPT<pixel_type> &ras() { return m_ras; }
RunsMapP &runsMap() { return m_runsMap; }
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
void paintLine(int x, int y0, int y1) const;
void paintBorder(const Border &border) const;
void paintBorders(const std::deque<Border *> &borders) const {
size_t i, size = borders.size();
for (i = 0; i < size; ++i) paintBorder(*borders[i]);
}
2016-03-19 06:57:51 +13:00
protected:
2016-06-15 18:43:10 +12:00
virtual void paintPixel(pixel_type *pix) const = 0;
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------------------------
template <typename Pix>
2016-06-15 18:43:10 +12:00
void BordersPainter<Pix>::paintBorder(const Border &border) const {
const std::vector<TPoint> &points = border.m_points;
size_t i, size_1 = points.size() - 1;
for (i = 0; i < size_1; ++i) {
const TPoint &p = points[i];
paintLine(p.x, p.y, points[i + 1].y);
}
paintLine(points[size_1].x, points[size_1].y, points[0].y);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
template <typename Pix>
2016-06-15 18:43:10 +12:00
void BordersPainter<Pix>::paintLine(int x, int y0, int y1) const {
for (int j = y0; j < y1; ++j) {
TPixelGR8 *runPix = m_runsMap->pixels(j) + x;
int l, runLength = 0, hierarchy = 0;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
do {
if (runPix->value & TRop::borders::_HIERARCHY_INCREASE) ++hierarchy;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Update vars
runLength += l = m_runsMap->runLength(runPix);
runPix += l;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if ((runPix - 1)->value & TRop::borders::_HIERARCHY_DECREASE) --hierarchy;
} while (hierarchy > 0);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
pixel_type *pix = m_ras->pixels(j) + x, *pixEnd = pix + runLength;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
for (; pix < pixEnd; ++pix) paintPixel(pix);
}
2016-03-19 06:57:51 +13:00
}
//========================================================================
// Despeckling Reader
//========================================================================
2016-06-15 18:43:10 +12:00
class DespecklingReader {
2016-03-19 06:57:51 +13:00
protected:
2016-06-15 18:43:10 +12:00
std::deque<Border *> m_borders;
Border m_border;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int m_sizeTol;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
DespecklingReader(int sizeTol) : m_sizeTol(sizeTol) {}
~DespecklingReader();
int sizeTol() const { return m_sizeTol; }
bool isSpeckle(const Border &border) {
return border.m_x1 - border.m_x0 <= m_sizeTol &&
border.m_y1 - border.m_y0 <= m_sizeTol;
}
void openContainer(const TPoint &pos);
void addElement(const TPoint &pos);
virtual void closeContainer();
const std::deque<Border *> &borders() const { return m_borders; }
std::deque<Border *> &borders() { return m_borders; }
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
DespecklingReader::~DespecklingReader() {
std::for_each(m_borders.begin(), m_borders.end(), tcg::deleter<Border>());
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void DespecklingReader::openContainer(const TPoint &pos) {
m_border.clear();
m_border.addPoint(pos);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void DespecklingReader::addElement(const TPoint &pos) {
m_border.addPoint(pos);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void DespecklingReader::closeContainer() {
if (isSpeckle(m_border)) m_borders.push_back(new Border(m_border));
2016-03-19 06:57:51 +13:00
}
//************************************************************************
// Specialized classes
//************************************************************************
//========================================================================
// Replace Painters
//========================================================================
template <typename Pix>
2016-06-15 18:43:10 +12:00
class ReplacePainter : public BordersPainter<Pix> {
typename ReplacePainter::pixel_type m_color;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
ReplacePainter(const TRasterPT<typename ReplacePainter::pixel_type> &ras)
: BordersPainter<Pix>(ras) {}
ReplacePainter(const TRasterPT<typename ReplacePainter::pixel_type> &ras,
const typename ReplacePainter::pixel_type &color)
: BordersPainter<Pix>(ras), m_color(color) {}
const typename ReplacePainter::pixel_type &color() const { return m_color; }
typename ReplacePainter::pixel_type &color() { return m_color; }
2016-06-19 20:06:29 +12:00
void paintPixel(typename ReplacePainter::pixel_type *pix) const override {
2016-06-15 18:43:10 +12:00
*pix = m_color;
}
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------------------------
template <>
2016-06-15 18:43:10 +12:00
class ReplacePainter<TPixelCM32> : public BordersPainter<TPixelCM32> {
TUINT32 m_value;
TUINT32 m_keepMask;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
ReplacePainter(const TRasterPT<pixel_type> &ras)
: BordersPainter<TPixelCM32>(ras), m_value(0), m_keepMask(0) {}
ReplacePainter(const TRasterPT<pixel_type> &ras, TUINT32 value,
TUINT32 keepMask)
: BordersPainter<TPixelCM32>(ras), m_value(value), m_keepMask(keepMask) {}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
const TUINT32 &value() const { return m_value; }
TUINT32 &value() { return m_value; }
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
const TUINT32 &keepMask() const { return m_keepMask; }
TUINT32 &keepMask() { return m_keepMask; }
2016-03-19 06:57:51 +13:00
2016-06-19 20:06:29 +12:00
void paintPixel(pixel_type *pix) const override {
2016-06-15 18:43:10 +12:00
*pix = TPixelCM32(m_value | (pix->getValue() & m_keepMask));
}
2016-03-19 06:57:51 +13:00
};
//========================================================================
// Isolated Despeckling
//========================================================================
template <typename PixelSelector>
2016-06-15 18:43:10 +12:00
class IsolatedReader : public DespecklingReader {
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
typedef typename PixelSelector::pixel_type pixel_type;
typedef typename PixelSelector::value_type value_type;
2016-03-19 06:57:51 +13:00
private:
2016-06-15 18:43:10 +12:00
const PixelSelector &m_selector;
bool m_ok;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
IsolatedReader(const PixelSelector &selector, int sizeTol);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
void openContainer(const RasterEdgeIterator<PixelSelector> &it);
void addElement(const RasterEdgeIterator<PixelSelector> &it);
2016-06-19 20:06:29 +12:00
void closeContainer() override;
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------------------------
template <typename PixelSelector>
2016-06-15 18:43:10 +12:00
IsolatedReader<PixelSelector>::IsolatedReader(const PixelSelector &selector,
int sizeTol)
: DespecklingReader(sizeTol), m_selector(selector) {}
2016-03-19 06:57:51 +13:00
//---------------------------------------------------------------------------------------------
template <typename PixelSelector>
2016-06-15 18:43:10 +12:00
void IsolatedReader<PixelSelector>::openContainer(
const RasterEdgeIterator<PixelSelector> &it) {
m_ok = (it.leftColor() == m_selector.transparent());
if (!m_ok) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
DespecklingReader::openContainer(it.pos());
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
template <typename PixelSelector>
2016-06-15 18:43:10 +12:00
void IsolatedReader<PixelSelector>::addElement(
const RasterEdgeIterator<PixelSelector> &it) {
if (!m_ok) return;
m_ok = (it.leftColor() == m_selector.transparent());
if (!m_ok) return;
DespecklingReader::addElement(it.pos());
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
template <typename PixelSelector>
2016-06-15 18:43:10 +12:00
void IsolatedReader<PixelSelector>::closeContainer() {
if (m_ok) DespecklingReader::closeContainer();
2016-03-19 06:57:51 +13:00
}
2016-06-15 18:43:10 +12:00
} // namespace
2016-03-19 06:57:51 +13:00
//*********************************************************************************************************
// Despeckling Mains
//*********************************************************************************************************
/*!
2016-06-15 18:43:10 +12:00
Applies despeckling (paint or removal of small blots of uniform color) to the
image.
2016-03-19 06:57:51 +13:00
*/
template <typename PIXEL, typename CHANNEL>
2016-06-15 18:43:10 +12:00
void doDespeckleRGBM(const TRasterPT<PIXEL> &ras, int sizeThreshold,
bool transparentIsWhite) {
InkSelectorRGBM<PIXEL, CHANNEL> selector(transparentIsWhite);
IsolatedReader<InkSelectorRGBM<PIXEL, CHANNEL>> reader(selector,
sizeThreshold);
ReplacePainter<PIXEL> painter(
ras, transparentIsWhite ? PIXEL::White : PIXEL::Transparent);
TRop::borders::readBorders(ras, selector, reader, &painter.runsMap());
painter.paintBorders(reader.borders());
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------
template <typename PIXEL, typename CHANNEL>
2016-06-15 18:43:10 +12:00
void doDespeckleGR(const TRasterPT<PIXEL> &ras, int sizeThreshold) {
InkSelectorGR<PIXEL, CHANNEL> selector;
IsolatedReader<InkSelectorGR<PIXEL, CHANNEL>> reader(selector, sizeThreshold);
ReplacePainter<PIXEL> painter(ras, PIXEL::maxChannelValue);
TRop::borders::readBorders(ras, selector, reader, &painter.runsMap());
painter.paintBorders(reader.borders());
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------
2016-06-15 18:43:10 +12:00
void doDespeckleCM32(const TRasterPT<TPixelCM32> &ras, int sizeThreshold,
bool check) {
TRasterCM32P rasCM(ras);
rasCM->lock();
InkSelectorCM32 selector;
IsolatedReader<InkSelectorCM32> reader(selector, sizeThreshold);
ReplacePainter<TPixelCM32> painter(
rasCM, check ? 0xffffff00 : 0x000000ff,
0); // 0xffffff00 is a special non-mapped full ink pixel
// 0x000000ff is a full transparent paint pixel
TRop::borders::readBorders(rasCM, selector, reader, &painter.runsMap());
painter.paintBorders(reader.borders());
rasCM->unlock();
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void TRop::despeckle(const TRasterP &ras, int sizeThreshold, bool check,
bool transparentIsWhite) {
ras->lock();
if (TRasterCM32P(ras)) {
doDespeckleCM32(ras, sizeThreshold, check);
return;
}
if (TRaster32P(ras)) {
doDespeckleRGBM<TPixel32, UCHAR>(ras, sizeThreshold, transparentIsWhite);
return;
}
if (TRaster64P(ras)) {
doDespeckleRGBM<TPixel64, USHORT>(ras, sizeThreshold, transparentIsWhite);
return;
}
if (TRasterGR8P(ras)) {
doDespeckleGR<TPixelGR8, UCHAR>(ras, sizeThreshold);
return;
}
if (TRasterGR16P(ras)) {
doDespeckleGR<TPixelGR16, USHORT>(ras, sizeThreshold);
return;
}
ras->unlock();
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
/*!
Performs a copy of rin and then applies despeckling.
*/
2016-06-15 18:43:10 +12:00
void TRop::despeckle(const TRasterP &rout, const TRasterP &rin,
int sizeThreshold, bool check) {
TRop::copy(rout, rin);
TRop::despeckle(rout, sizeThreshold, check);
2016-03-19 06:57:51 +13:00
}
//*********************************************************************************************************
// Majority Despeckling
//*********************************************************************************************************
2016-06-15 18:43:10 +12:00
namespace {
2016-03-19 06:57:51 +13:00
template <typename PixelSelector>
2016-06-15 18:43:10 +12:00
class FillingReader : public DespecklingReader {
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
typedef typename PixelSelector::pixel_type pixel_type;
typedef typename PixelSelector::value_type value_type;
2016-03-19 06:57:51 +13:00
private:
2016-06-15 18:43:10 +12:00
ReplacePainter<TPixelGR8> m_painter;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
FillingReader(const TRasterGR8P &rasGR, int sizeTol)
: DespecklingReader(sizeTol), m_painter(rasGR, TPixelGR8::Black) {}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
void openContainer(const RasterEdgeIterator<PixelSelector> &it);
void addElement(const RasterEdgeIterator<PixelSelector> &it);
2016-06-19 20:06:29 +12:00
void closeContainer() override;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
RunsMapP &runsMap() { return m_painter.runsMap(); }
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------------------------
template <typename PixelSelector>
2016-06-15 18:43:10 +12:00
void FillingReader<PixelSelector>::openContainer(
const RasterEdgeIterator<PixelSelector> &it) {
DespecklingReader::openContainer(it.pos());
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
template <typename PixelSelector>
2016-06-15 18:43:10 +12:00
void FillingReader<PixelSelector>::addElement(
const RasterEdgeIterator<PixelSelector> &it) {
DespecklingReader::addElement(it.pos());
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
template <typename PixelSelector>
2016-06-15 18:43:10 +12:00
void FillingReader<PixelSelector>::closeContainer() {
if (isSpeckle(m_border)) m_painter.paintBorder(m_border);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
DespecklingReader::closeContainer();
2016-03-19 06:57:51 +13:00
}
//=============================================================================================
2016-06-15 18:43:10 +12:00
inline TPoint direction(const TPoint &a, const TPoint &b) {
return TPoint((b.x > a.x) ? 1 : (b.x < a.x) ? -1 : 0,
(b.y > a.y) ? 1 : (b.y < a.y) ? -1 : 0);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
template <typename Pixel, typename PixelSelector>
bool majority(const TRasterPT<Pixel> ras, const TRasterGR8P &rasGR,
2016-06-15 18:43:10 +12:00
const PixelSelector &selector, const Border &border,
typename PixelSelector::value_type &color) {
typedef typename PixelSelector::value_type value_type;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Build a histogram of all found colors around the border
std::map<value_type, int> histogram;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
Pixel *pix, *basePix = ras->pixels(0);
TPixelGR8 *grPix;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int diff, x, y, lx = ras->getLx(), ly = ras->getLy(), wrap = ras->getWrap();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
assert(border.m_points[1].y > border.m_points[0].y);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Iterate the raster along the border
const std::vector<TPoint> &points = border.m_points;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
RasterEdgeIterator<PixelSelector> start(ras, selector, points[0],
direction(points[0], points[1])),
it(start);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
size_t next = 1, size = points.size();
do {
while (it.pos() != points[next]) {
pix = it.leftPix();
diff = pix - basePix;
x = diff % wrap;
y = diff / wrap;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (x >= 0 && y >= 0 && x < lx && y < ly) {
grPix = rasGR->pixels(y) + x;
if (grPix->value) ++histogram[it.leftColor()];
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
it.setEdge(it.pos() + it.dir(), it.dir());
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
next = (next + 1) % size;
it.setEdge(it.pos(), direction(it.pos(), points[next]));
} while (it != start);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (!histogram.empty()) {
// Return the most found color
color = histogram.begin()->first;
return true;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
return false;
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------------------------
template <typename Pix>
2016-06-15 18:43:10 +12:00
void majorityDespeckle(const TRasterPT<Pix> &ras, int sizeThreshold) {
typedef typename TRop::borders::PixelSelector<Pix> pixel_selector;
typedef typename pixel_selector::pixel_type pixel_type;
typedef typename pixel_selector::value_type value_type;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
ras->lock();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Use a temporary bitmap (well, a bytemap - for now?) to store the found
// speckles
TRasterGR8P rasGR(ras->getSize());
rasGR->fill(TPixelGR8::White);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Find the speckles and draw them on the bitmap
pixel_selector selector;
FillingReader<pixel_selector> reader(rasGR, sizeThreshold);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TRop::borders::readBorders(ras, selector, reader, &reader.runsMap());
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Now, operate each speckle. Try to apply a majority color to the speckle
ReplacePainter<pixel_type> painter(ras);
painter.runsMap() = reader.runsMap();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
ReplacePainter<TPixelGR8> painterGR(rasGR, TPixelGR8::White);
painterGR.runsMap() = reader.runsMap();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
std::deque<Border *> borders =
reader.borders(); // Note that the DEEP copy is NEEDED
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int processedCount = 1;
while (processedCount > 0 && !borders.empty()) {
processedCount = 0;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Traverse the speckles list. Try to apply majority.
Border *current, *last = borders.back();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
do {
current = borders.front();
borders.pop_front();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
value_type color;
if (majority(ras, rasGR, selector, *current, color)) {
++processedCount;
painter.color() = color;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
painter.paintBorder(*current);
painterGR.paintBorder(*current);
} else
borders.push_back(current);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
} while (current != last);
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Speckles may remain. In this case, fill with transparent.
painter.color() = selector.transparent();
while (!borders.empty()) {
Border *current = borders.front();
painter.paintBorder(*current);
borders.pop_front();
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
ras->unlock();
2016-03-19 06:57:51 +13:00
}
2016-06-15 18:43:10 +12:00
} // namespace
2016-03-19 06:57:51 +13:00
//================================================================================================
2016-06-15 18:43:10 +12:00
void TRop::majorityDespeckle(const TRasterP &ras, int sizeThreshold) {
TRaster32P ras32(ras);
if (ras32) {
::majorityDespeckle(ras32, sizeThreshold);
return;
}
TRaster64P ras64(ras);
if (ras64) {
::majorityDespeckle(ras64, sizeThreshold);
return;
}
TRasterGR8P rasGR8(ras);
if (rasGR8) {
::majorityDespeckle(rasGR8, sizeThreshold);
return;
}
TRasterGR16P rasGR16(ras);
if (rasGR16) {
::majorityDespeckle(rasGR16, sizeThreshold);
return;
}
TRasterCM32P rasCM32(ras);
if (rasCM32) {
// Not yet implemented
assert(false);
//::majorityDespeckleCM(rasCM32, sizeThreshold, toneTol);
return;
}
2016-03-19 06:57:51 +13:00
}