Skip to content

Commit 500ae1e

Browse files
committed
0.2023.11.24: output: filters: unPaper
1 parent 8de3c41 commit 500ae1e

26 files changed

+468
-4
lines changed

src/filters/output/ColorGrayscaleOptions.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ ColorGrayscaleOptions::ColorGrayscaleOptions(QDomElement const& el)
3737
m_screenWindowSize(el.attribute("screenWinSize").toInt()),
3838
m_curveCoef(el.attribute("curveCoef").toDouble()),
3939
m_sqrCoef(el.attribute("sqrCoef").toDouble()),
40+
m_unPaperCoef(el.attribute("unPaper").toDouble()),
41+
m_unPaperIters(el.attribute("unPaperIters").toInt()),
4042
m_normalizeCoef(el.attribute("normalizeCoef").toDouble()),
4143
m_whiteMargins(el.attribute("whiteMargins") == "1")
4244
{
@@ -88,6 +90,14 @@ ColorGrayscaleOptions::ColorGrayscaleOptions(QDomElement const& el)
8890
{
8991
m_sqrCoef = 0.0;
9092
}
93+
if (m_unPaperCoef < 0.0 || m_unPaperCoef > 1.0)
94+
{
95+
m_unPaperCoef = 0.0;
96+
}
97+
if (m_unPaperIters < 1)
98+
{
99+
m_unPaperIters = 5;
100+
}
91101
if (m_normalizeCoef < 0.0 || m_normalizeCoef > 1.0)
92102
{
93103
m_normalizeCoef = 0.0;
@@ -110,6 +120,8 @@ ColorGrayscaleOptions::toXml(QDomDocument& doc, QString const& name) const
110120
el.setAttribute("screenWinSize", m_screenWindowSize);
111121
el.setAttribute("curveCoef", m_curveCoef);
112122
el.setAttribute("sqrCoef", m_sqrCoef);
123+
el.setAttribute("unPaper", m_unPaperCoef);
124+
el.setAttribute("unPaperIters", m_unPaperIters);
113125
el.setAttribute("normalizeCoef", m_normalizeCoef);
114126
el.setAttribute("whiteMargins", m_whiteMargins ? "1" : "0");
115127
return el;
@@ -146,6 +158,10 @@ ColorGrayscaleOptions::operator==(ColorGrayscaleOptions const& other) const
146158
{
147159
return false;
148160
}
161+
if ((m_unPaperCoef != other.m_unPaperCoef) || (m_unPaperIters != other.m_unPaperIters))
162+
{
163+
return false;
164+
}
149165
if (m_normalizeCoef != other.m_normalizeCoef)
150166
{
151167
return false;

src/filters/output/ColorGrayscaleOptions.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class ColorGrayscaleOptions
4242
m_screenWindowSize(10),
4343
m_curveCoef(0.5),
4444
m_sqrCoef(0.0),
45+
m_unPaperCoef(0.0),
46+
m_unPaperIters(5),
4547
m_normalizeCoef(0.5),
4648
m_whiteMargins(false) {}
4749

@@ -152,6 +154,23 @@ class ColorGrayscaleOptions
152154
m_sqrCoef = val;
153155
}
154156

157+
double unPaperCoef() const
158+
{
159+
return m_unPaperCoef;
160+
}
161+
void setUnPaperCoef(double val)
162+
{
163+
m_unPaperCoef = val;
164+
}
165+
int unPaperIters() const
166+
{
167+
return m_unPaperIters;
168+
}
169+
void setUnPaperIters(int val)
170+
{
171+
m_unPaperIters = val;
172+
}
173+
155174
double normalizeCoef() const
156175
{
157176
return m_normalizeCoef;
@@ -186,6 +205,8 @@ class ColorGrayscaleOptions
186205
int m_screenWindowSize;
187206
double m_curveCoef;
188207
double m_sqrCoef;
208+
double m_unPaperCoef;
209+
int m_unPaperIters;
189210
double m_normalizeCoef;
190211
bool m_whiteMargins;
191212
};

src/filters/output/OptionsWidget.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,14 @@ OptionsWidget::OptionsWidget(
184184
sqrCoef, SIGNAL(valueChanged(double)),
185185
this, SLOT(sqrCoefChanged(double))
186186
);
187+
connect(
188+
unPaperCoef, SIGNAL(valueChanged(double)),
189+
this, SLOT(unPaperCoefChanged(double))
190+
);
191+
connect(
192+
unPaperIters, SIGNAL(valueChanged(int)),
193+
this, SLOT(unPaperItersChanged(int))
194+
);
187195
connect(
188196
normalizeCoef, SIGNAL(valueChanged(double)),
189197
this, SLOT(normalizeCoefChanged(double))
@@ -544,6 +552,26 @@ OptionsWidget::sqrCoefChanged(double value)
544552
emit reloadRequested();
545553
}
546554

555+
void
556+
OptionsWidget::unPaperCoefChanged(double value)
557+
{
558+
ColorGrayscaleOptions color_options(m_colorParams.colorGrayscaleOptions());
559+
color_options.setUnPaperCoef(value);
560+
m_colorParams.setColorGrayscaleOptions(color_options);
561+
m_ptrSettings->setColorParams(m_pageId, m_colorParams);
562+
emit reloadRequested();
563+
}
564+
565+
void
566+
OptionsWidget::unPaperItersChanged(int value)
567+
{
568+
ColorGrayscaleOptions color_options(m_colorParams.colorGrayscaleOptions());
569+
color_options.setUnPaperIters(value);
570+
m_colorParams.setColorGrayscaleOptions(color_options);
571+
m_ptrSettings->setColorParams(m_pageId, m_colorParams);
572+
emit reloadRequested();
573+
}
574+
547575
void
548576
OptionsWidget::normalizeCoefChanged(double value)
549577
{
@@ -1033,6 +1061,8 @@ OptionsWidget::updateColorsDisplay()
10331061
screenWindowSize->setValue(color_options.screenWindowSize());
10341062
curveCoef->setValue(color_options.curveCoef());
10351063
sqrCoef->setValue(color_options.sqrCoef());
1064+
unPaperCoef->setValue(color_options.unPaperCoef());
1065+
unPaperIters->setValue(color_options.unPaperIters());
10361066
normalizeCoef->setValue(color_options.normalizeCoef());
10371067
if (color_grayscale_options_visible)
10381068
{

src/filters/output/OptionsWidget.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ private slots:
7171

7272
void knndCoefChanged(double value);
7373

74-
void cdespeckleRadiusChanged(int value);
74+
void knndRadiusChanged(int value);
7575

7676
void cdespeckleCoefChanged(double value);
7777

78-
void knndRadiusChanged(int value);
78+
void cdespeckleRadiusChanged(int value);
7979

8080
void blurCoefChanged(double value);
8181

@@ -89,6 +89,10 @@ private slots:
8989

9090
void sqrCoefChanged(double value);
9191

92+
void unPaperCoefChanged(double value);
93+
94+
void unPaperItersChanged(int value);
95+
9296
void normalizeCoefChanged(double value);
9397

9498
void whiteMarginsToggled(bool checked);

src/filters/output/OutputGenerator.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,6 @@ OutputGenerator::process(
377377
colorCurveFilterInPlace(transformed_image, color_options.curveCoef());
378378

379379
colorSqrFilterInPlace(transformed_image, color_options.sqrCoef());
380-
// Color filters end
381380

382381
GrayImage coloredSignificance(transformed_image);
383382
if (render_params.needBinarization())
@@ -427,7 +426,10 @@ OutputGenerator::process(
427426
}
428427
}
429428

429+
unPaperFilterInPlace(transformed_image, color_options.unPaperIters(), color_options.unPaperCoef());
430+
430431
status.throwIfCancelled();
432+
// Color filters end
431433

432434
QImage maybe_smoothed;
433435
// We only do smoothing if we are going to do binarization later.

src/filters/output/ui/OutputOptionsWidget.ui

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,42 @@
453453
</property>
454454
</widget>
455455
</item>
456+
<item row="6" column="0">
457+
<widget class="QLabel" name="unPaperLabel">
458+
<property name="text">
459+
<string>UnPaper</string>
460+
</property>
461+
</widget>
462+
</item>
463+
<item row="6" column="1">
464+
<widget class="QDoubleSpinBox" name="unPaperCoef">
465+
<property name="toolTip">
466+
<string>Value is 0.0 .. 1.0..</string>
467+
</property>
468+
<property name="minimum">
469+
<double>0.0</double>
470+
</property>
471+
<property name="maximum">
472+
<double>1.0</double>
473+
</property>
474+
<property name="singleStep">
475+
<double>0.05</double>
476+
</property>
477+
</widget>
478+
</item>
479+
<item row="6" column="2">
480+
<widget class="QSpinBox" name="unPaperIters">
481+
<property name="toolTip">
482+
<string>The iters of a unPaper.</string>
483+
</property>
484+
<property name="minimum">
485+
<number>1</number>
486+
</property>
487+
<property name="maximum">
488+
<number>99</number>
489+
</property>
490+
</widget>
491+
</item>
456492
</layout>
457493
</item>
458494
<item>

src/imageproc/ColorFilter.cpp

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,4 +1634,166 @@ void maskMorphological(
16341634
}
16351635
}
16361636

1637+
QImage unPaperFilter(
1638+
QImage const& image, unsigned int const iters, float const coef)
1639+
{
1640+
QImage dst(image);
1641+
unPaperFilterInPlace(dst, iters, coef);
1642+
return dst;
1643+
}
1644+
1645+
void unPaperFilterInPlace(
1646+
QImage& image, unsigned int const iters, float const coef)
1647+
{
1648+
if (image.isNull())
1649+
{
1650+
return;
1651+
}
1652+
1653+
if ((iters > 0) && (coef > 0.0f))
1654+
{
1655+
unsigned int const w = image.width();
1656+
unsigned int const h = image.height();
1657+
uint8_t* image_line = (uint8_t*) image.bits();
1658+
unsigned int const image_stride = image.bytesPerLine();
1659+
unsigned int const cnum = image_stride / w;
1660+
1661+
GrayImage gray = GrayImage(image);
1662+
uint8_t* gray_line = gray.data();
1663+
unsigned int const gray_stride = gray.stride();
1664+
1665+
unsigned int const histsize = 256;
1666+
unsigned long int histogram[histsize] = {0};
1667+
unsigned long int hmax = 0, bgcount = 0;
1668+
double bgthres, bg[4] = {0.0}, bgsum[4] = {0.0};
1669+
1670+
for (unsigned int y = 0; y < h; y++)
1671+
{
1672+
for (unsigned int x = 0; x < w; x++)
1673+
{
1674+
uint8_t const pixel = gray_line[x];
1675+
histogram[pixel]++;
1676+
}
1677+
gray_line += gray_stride;
1678+
}
1679+
1680+
for (unsigned int k = 0; k < histsize; k++)
1681+
{
1682+
hmax = (hmax > histogram[k]) ? hmax : histogram[k];
1683+
}
1684+
bgthres = (1.0 - coef) * hmax;
1685+
1686+
image_line = (uint8_t*) image.bits();
1687+
gray_line = gray.data();
1688+
for (unsigned int y = 0; y < h; y++)
1689+
{
1690+
for (unsigned int x = 0; x < w; x++)
1691+
{
1692+
unsigned int const origin = gray_line[x];
1693+
if (histogram[origin] > bgthres)
1694+
{
1695+
unsigned int const indx = x * cnum;
1696+
for (unsigned int c = 0; c < cnum; c++)
1697+
{
1698+
double const origcol = image_line[indx + c];
1699+
bgsum[c] += origcol;
1700+
}
1701+
bgcount++;
1702+
}
1703+
}
1704+
image_line += image_stride;
1705+
gray_line += gray_stride;
1706+
}
1707+
if (bgcount > 0)
1708+
{
1709+
for (unsigned int c = 0; c < cnum; c++)
1710+
{
1711+
bg[c] = bgsum[c] / bgcount;
1712+
}
1713+
for (unsigned int k = 0; k < iters; k++)
1714+
{
1715+
bgcount = 0;
1716+
for (unsigned int c = 0; c < cnum; c++)
1717+
{
1718+
bgsum[c] = 0.0;
1719+
}
1720+
double distmax = 0;
1721+
image_line = (uint8_t*) image.bits();
1722+
for (unsigned int y = 0; y < h; y++)
1723+
{
1724+
for (unsigned int x = 0; x < w; x++)
1725+
{
1726+
double dist = 0;
1727+
unsigned int const indx = x * cnum;
1728+
for (unsigned int c = 0; c < cnum; c++)
1729+
{
1730+
double const origcol = image_line[indx + c];
1731+
double const delta = origcol - bg[c];
1732+
dist += delta * delta;
1733+
}
1734+
distmax = (dist < distmax) ? distmax : dist;
1735+
}
1736+
image_line += image_stride;
1737+
}
1738+
double const distthres = distmax * coef * coef;
1739+
image_line = (uint8_t*) image.bits();
1740+
for (unsigned int y = 0; y < h; y++)
1741+
{
1742+
for (unsigned int x = 0; x < w; x++)
1743+
{
1744+
double dist = 0;
1745+
unsigned int const indx = x * cnum;
1746+
for (unsigned int c = 0; c < cnum; c++)
1747+
{
1748+
double const origcol = image_line[indx + c];
1749+
double const delta = origcol - bg[c];
1750+
dist += delta * delta;
1751+
}
1752+
if (dist < distthres)
1753+
{
1754+
for (unsigned int c = 0; c < cnum; c++)
1755+
{
1756+
double const origcol = image_line[indx + c];
1757+
bgsum[c] += origcol;
1758+
}
1759+
bgcount++;
1760+
}
1761+
}
1762+
image_line += image_stride;
1763+
}
1764+
if (bgcount > 0)
1765+
{
1766+
for (unsigned int c = 0; c < cnum; c++)
1767+
{
1768+
bg[c] = bgsum[c] / bgcount;
1769+
}
1770+
image_line = (uint8_t*) image.bits();
1771+
for (unsigned int y = 0; y < h; y++)
1772+
{
1773+
for (unsigned int x = 0; x < w; x++)
1774+
{
1775+
double dist = 0;
1776+
unsigned int const indx = x * cnum;
1777+
for (unsigned int c = 0; c < cnum; c++)
1778+
{
1779+
double const origcol = image_line[indx + c];
1780+
double const delta = origcol - bg[c];
1781+
dist += delta * delta;
1782+
}
1783+
if (dist < distthres)
1784+
{
1785+
for (unsigned int c = 0; c < cnum; ++c)
1786+
{
1787+
image_line[indx + c] = (uint8_t) (bg[c] + 0.5);
1788+
}
1789+
}
1790+
}
1791+
image_line += image_stride;
1792+
}
1793+
}
1794+
}
1795+
}
1796+
}
1797+
}
1798+
16371799
} // namespace imageproc

0 commit comments

Comments
 (0)