| |
| |
| #include "tropcm.h" |
| |
| |
| #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 |
| |
| |
| #include "tcg/deleter_types.h" |
| |
| |
| #include <deque> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| using namespace TRop::borders; |
| |
| namespace { |
| |
| |
| |
| |
| |
| class InkSelectorCM32 { |
| public: |
| typedef TPixelCM32 pixel_type; |
| typedef TUINT32 value_type; |
| |
| public: |
| InkSelectorCM32() {} |
| |
| 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 { return pix.getInk(); } |
| 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; |
| } |
| }; |
| |
| |
| |
| template <typename PIXEL, typename CHANNEL> |
| class InkSelectorRGBM { |
| bool m_transparentIsWhite; |
| |
| public: |
| typedef PIXEL pixel_type; |
| typedef CHANNEL value_type; |
| |
| public: |
| 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; |
| } |
| }; |
| |
| |
| |
| template <typename PIXEL, typename CHANNEL> |
| class InkSelectorGR { |
| public: |
| typedef PIXEL pixel_type; |
| typedef CHANNEL value_type; |
| |
| public: |
| 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; |
| } |
| }; |
| |
| |
| |
| |
| |
| struct Border { |
| 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) { |
| |
| 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; |
| |
| |
| 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; |
| } |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename Pix> |
| class BordersPainter { |
| public: |
| typedef Pix pixel_type; |
| |
| protected: |
| TRasterPT<pixel_type> m_ras; |
| RunsMapP m_runsMap; |
| |
| public: |
| BordersPainter(const TRasterPT<pixel_type> &ras) : m_ras(ras) {} |
| |
| const TRasterPT<pixel_type> &ras() { return m_ras; } |
| RunsMapP &runsMap() { return m_runsMap; } |
| |
| 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]); |
| } |
| |
| protected: |
| virtual void paintPixel(pixel_type *pix) const = 0; |
| }; |
| |
| |
| |
| template <typename Pix> |
| 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); |
| } |
| |
| |
| |
| template <typename Pix> |
| 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; |
| |
| do { |
| if (runPix->value & TRop::borders::_HIERARCHY_INCREASE) ++hierarchy; |
| |
| |
| runLength += l = m_runsMap->runLength(runPix); |
| runPix += l; |
| |
| if ((runPix - 1)->value & TRop::borders::_HIERARCHY_DECREASE) --hierarchy; |
| } while (hierarchy > 0); |
| |
| pixel_type *pix = m_ras->pixels(j) + x, *pixEnd = pix + runLength; |
| |
| for (; pix < pixEnd; ++pix) paintPixel(pix); |
| } |
| } |
| |
| |
| |
| |
| |
| class DespecklingReader { |
| protected: |
| std::deque<Border *> m_borders; |
| Border m_border; |
| |
| int m_sizeTol; |
| |
| public: |
| 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; } |
| }; |
| |
| |
| |
| DespecklingReader::~DespecklingReader() { |
| std::for_each(m_borders.begin(), m_borders.end(), tcg::deleter<Border>()); |
| } |
| |
| |
| |
| void DespecklingReader::openContainer(const TPoint &pos) { |
| m_border.clear(); |
| m_border.addPoint(pos); |
| } |
| |
| |
| |
| void DespecklingReader::addElement(const TPoint &pos) { |
| m_border.addPoint(pos); |
| } |
| |
| |
| |
| void DespecklingReader::closeContainer() { |
| if (isSpeckle(m_border)) m_borders.push_back(new Border(m_border)); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename Pix> |
| class ReplacePainter final : public BordersPainter<Pix> { |
| typename ReplacePainter::pixel_type m_color; |
| |
| public: |
| 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; } |
| |
| void paintPixel(typename ReplacePainter::pixel_type *pix) const override { |
| *pix = m_color; |
| } |
| }; |
| |
| |
| |
| template <> |
| class ReplacePainter<TPixelCM32> final : public BordersPainter<TPixelCM32> { |
| TUINT32 m_value; |
| TUINT32 m_keepMask; |
| |
| public: |
| 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) {} |
| |
| const TUINT32 &value() const { return m_value; } |
| TUINT32 &value() { return m_value; } |
| |
| const TUINT32 &keepMask() const { return m_keepMask; } |
| TUINT32 &keepMask() { return m_keepMask; } |
| |
| void paintPixel(pixel_type *pix) const override { |
| *pix = TPixelCM32(m_value | (pix->getValue() & m_keepMask)); |
| } |
| }; |
| |
| |
| |
| |
| |
| template <typename PixelSelector> |
| class IsolatedReader final : public DespecklingReader { |
| public: |
| typedef typename PixelSelector::pixel_type pixel_type; |
| typedef typename PixelSelector::value_type value_type; |
| |
| private: |
| const PixelSelector &m_selector; |
| bool m_ok; |
| |
| public: |
| IsolatedReader(const PixelSelector &selector, int sizeTol); |
| |
| void openContainer(const RasterEdgeIterator<PixelSelector> &it); |
| void addElement(const RasterEdgeIterator<PixelSelector> &it); |
| void closeContainer() override; |
| }; |
| |
| |
| |
| template <typename PixelSelector> |
| IsolatedReader<PixelSelector>::IsolatedReader(const PixelSelector &selector, |
| int sizeTol) |
| : DespecklingReader(sizeTol), m_selector(selector) {} |
| |
| |
| |
| template <typename PixelSelector> |
| void IsolatedReader<PixelSelector>::openContainer( |
| const RasterEdgeIterator<PixelSelector> &it) { |
| m_ok = (it.leftColor() == m_selector.transparent()); |
| if (!m_ok) return; |
| |
| DespecklingReader::openContainer(it.pos()); |
| } |
| |
| |
| |
| template <typename PixelSelector> |
| 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()); |
| } |
| |
| |
| |
| template <typename PixelSelector> |
| void IsolatedReader<PixelSelector>::closeContainer() { |
| if (m_ok) DespecklingReader::closeContainer(); |
| } |
| |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename PIXEL, typename CHANNEL> |
| 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()); |
| } |
| |
| |
| |
| template <typename PIXEL, typename CHANNEL> |
| 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()); |
| } |
| |
| |
| |
| static 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); |
| |
| TRop::borders::readBorders(rasCM, selector, reader, &painter.runsMap()); |
| painter.paintBorders(reader.borders()); |
| |
| rasCM->unlock(); |
| } |
| |
| |
| |
| 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(); |
| } |
| |
| |
| |
| |
| |
| |
| void TRop::despeckle(const TRasterP &rout, const TRasterP &rin, |
| int sizeThreshold, bool check) { |
| TRop::copy(rout, rin); |
| TRop::despeckle(rout, sizeThreshold, check); |
| } |
| |
| |
| |
| |
| |
| namespace { |
| |
| template <typename PixelSelector> |
| class FillingReader final : public DespecklingReader { |
| public: |
| typedef typename PixelSelector::pixel_type pixel_type; |
| typedef typename PixelSelector::value_type value_type; |
| |
| private: |
| ReplacePainter<TPixelGR8> m_painter; |
| |
| public: |
| FillingReader(const TRasterGR8P &rasGR, int sizeTol) |
| : DespecklingReader(sizeTol), m_painter(rasGR, TPixelGR8::Black) {} |
| |
| void openContainer(const RasterEdgeIterator<PixelSelector> &it); |
| void addElement(const RasterEdgeIterator<PixelSelector> &it); |
| void closeContainer() override; |
| |
| RunsMapP &runsMap() { return m_painter.runsMap(); } |
| }; |
| |
| |
| |
| template <typename PixelSelector> |
| void FillingReader<PixelSelector>::openContainer( |
| const RasterEdgeIterator<PixelSelector> &it) { |
| DespecklingReader::openContainer(it.pos()); |
| } |
| |
| |
| |
| template <typename PixelSelector> |
| void FillingReader<PixelSelector>::addElement( |
| const RasterEdgeIterator<PixelSelector> &it) { |
| DespecklingReader::addElement(it.pos()); |
| } |
| |
| |
| |
| template <typename PixelSelector> |
| void FillingReader<PixelSelector>::closeContainer() { |
| if (isSpeckle(m_border)) m_painter.paintBorder(m_border); |
| |
| DespecklingReader::closeContainer(); |
| } |
| |
| |
| |
| 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); |
| } |
| |
| |
| |
| template <typename Pixel, typename PixelSelector> |
| bool majority(const TRasterPT<Pixel> ras, const TRasterGR8P &rasGR, |
| const PixelSelector &selector, const Border &border, |
| typename PixelSelector::value_type &color) { |
| typedef typename PixelSelector::value_type value_type; |
| |
| |
| std::map<value_type, int> histogram; |
| |
| Pixel *pix, *basePix = ras->pixels(0); |
| TPixelGR8 *grPix; |
| |
| int diff, x, y, lx = ras->getLx(), ly = ras->getLy(), wrap = ras->getWrap(); |
| |
| assert(border.m_points[1].y > border.m_points[0].y); |
| |
| |
| const std::vector<TPoint> &points = border.m_points; |
| |
| RasterEdgeIterator<PixelSelector> start(ras, selector, points[0], |
| direction(points[0], points[1])), |
| it(start); |
| |
| 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; |
| |
| if (x >= 0 && y >= 0 && x < lx && y < ly) { |
| grPix = rasGR->pixels(y) + x; |
| if (grPix->value) ++histogram[it.leftColor()]; |
| } |
| |
| it.setEdge(it.pos() + it.dir(), it.dir()); |
| } |
| |
| next = (next + 1) % size; |
| it.setEdge(it.pos(), direction(it.pos(), points[next])); |
| } while (it != start); |
| |
| if (!histogram.empty()) { |
| |
| color = histogram.begin()->first; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| |
| |
| template <typename Pix> |
| 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; |
| |
| ras->lock(); |
| |
| |
| |
| TRasterGR8P rasGR(ras->getSize()); |
| rasGR->fill(TPixelGR8::White); |
| |
| |
| pixel_selector selector; |
| FillingReader<pixel_selector> reader(rasGR, sizeThreshold); |
| |
| TRop::borders::readBorders(ras, selector, reader, &reader.runsMap()); |
| |
| |
| ReplacePainter<pixel_type> painter(ras); |
| painter.runsMap() = reader.runsMap(); |
| |
| ReplacePainter<TPixelGR8> painterGR(rasGR, TPixelGR8::White); |
| painterGR.runsMap() = reader.runsMap(); |
| |
| std::deque<Border *> borders = |
| reader.borders(); |
| |
| int processedCount = 1; |
| while (processedCount > 0 && !borders.empty()) { |
| processedCount = 0; |
| |
| |
| Border *current, *last = borders.back(); |
| |
| do { |
| current = borders.front(); |
| borders.pop_front(); |
| |
| value_type color; |
| if (majority(ras, rasGR, selector, *current, color)) { |
| ++processedCount; |
| painter.color() = color; |
| |
| painter.paintBorder(*current); |
| painterGR.paintBorder(*current); |
| } else |
| borders.push_back(current); |
| |
| } while (current != last); |
| } |
| |
| |
| painter.color() = selector.transparent(); |
| while (!borders.empty()) { |
| Border *current = borders.front(); |
| painter.paintBorder(*current); |
| borders.pop_front(); |
| } |
| |
| ras->unlock(); |
| } |
| |
| } |
| |
| |
| |
| 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) { |
| |
| assert(false); |
| |
| |
| return; |
| } |
| } |
| |