📄 toolsimagefilter.h
字号:
#ifndef ToolsImageFilter_h
#define ToolsImageFilter_h
/*
This "SOFTWARE" is a free software.
You are allowed to download, use, modify and redistribute this software.
The software is provided "AS IS" without warranty of any kind.
Copyright: University of Koblenz-Landau, Dirk Balthasar
*/
#include <ToolsImage.h>
namespace tools
{
/// \author Dirk Balthasar (private)
/// help class for FilterKuwaharaNagaoGeneric
/// replace sector with lowest variance by mean of r,g,b
template <class ImageType, class AccessRGB>
class FilterKuwaharaNagaoReplacePixelMeanRGB
{
public:
void Replace(ImageType &Input, ImageType &Output, int x, int y, tools::CROI &ROI, float mr, float mg, float mb)
{
Output(x,y) = AccessRGB::PackRGB(mr, mg, mb);
}
};
/// \author Dirk Balthasar (private)
/// help class for FilterKuwaharaNagaoGeneric
/// replace sector with lowest variance by mean of h,s,v
template <class ImageType, class AccessRGB>
class FilterKuwaharaNagaoReplacePixelMeanHSV
{
public:
void Replace(ImageType &Input, ImageType &Output, int x, int y, const tools::CROI &ROI, float mr, float mg, float mb)
{
int Ms = 0, Mv = 0,
Mhd = 0; // sum of offsets to angle 0
// calculate mean color of best sector in hsv color space
unsigned char r,g,b;
int RedLowCount = 0,
RedHighCount = 0,
HueCount = 0;
short int h;
unsigned char s,v;
for (unsigned int ry = y+ROI.y1(); ry <= y+ROI.y2(); ++ry)
{
for (unsigned int rx = x+ROI.x1(); rx <= x+ROI.x2(); ++rx)
{
r = AccessRGB::GetR(Input(rx,ry));
g = AccessRGB::GetG(Input(rx,ry));
b = AccessRGB::GetB(Input(rx,ry));
tools::RGB2HSVd(r,g,b,h,s,v); // 255,255,255,359,255,255
/*
Mhd += tools::CycleDiff(0, h, 360);
*/
if (h<=60) RedLowCount+=360;
else if (h>=300) RedHighCount++;
Mhd+=h;
HueCount++;
Ms += s;
Mv += v;
}
}
Ms /= 4;
Mv /= 4;
if (HueCount>0)
{ // works, if colors not to far away from each other
if (RedHighCount>0)
Mhd = (Mhd + RedLowCount + (HueCount >> 1)) / HueCount;
else
Mhd = (Mhd + (HueCount >> 1)) / HueCount;
if (Mhd>=360) Mhd = Mhd - 360;
}
else Mhd = 0;
//tools::HSV2RGBd(Mhd, Ms, Mv, r, g, b);
tools::HSV2RGBd(h, s, v, r, g, b);
// replace color by mean of h,s,v
Output(x,y) = AccessRGB::PackRGB(r, g, b);
}
};
/// \author Dirk Balthasar (private)
/// \author Dirk Balthasar (private)
/// help class for FilterKuwaharaNagaoGeneric
/// replace sector with pixel with lowest distance to r,g,b mean value
template <class ImageType, class AccessRGB>
class FilterKuwaharaNagaoReplacePixelMeanMinDist
{
public:
void Replace(ImageType &Input, ImageType &Output, int x, int y, const tools::CROI &ROI, float mr, float mg, float mb)
{
unsigned char
mri = (unsigned char)mr,
mgi = (unsigned char)mg,
mbi = (unsigned char)mb,
bestr,bestg,bestb;
float MinMeanDist = -1;
for (unsigned int ry = y+ROI.y1(); ry <= y+ROI.y2(); ++ry)
{
for (unsigned int rx = x+ROI.x1(); rx <= x+ROI.x2(); ++rx)
{
unsigned char
r = AccessRGB::GetR(Input(rx,ry)),
g = AccessRGB::GetG(Input(rx,ry)),
b = AccessRGB::GetB(Input(rx,ry));
float d = tools::DistRGBEuklidPow2(r, g, b, mri, mgi, mbi);
if (MinMeanDist < 0)
{ // first pixel
MinMeanDist = d;
bestr = r;
bestg = g;
bestb = b;
}else
{
if (d < MinMeanDist)
{
MinMeanDist = d;
bestr = r;
bestg = g;
bestb = b;
}
}
}
}
Output(x,y) = AccessRGB::PackRGB(bestr,bestg,bestb);
}
};
/// \author Dirk Balthasar (private)
/// \author Dirk Balthasar (private)
/// help class for FilterKuwaharaNagaoGeneric
/// replace sector with pixel with lowest distance to r,g,b mean value if center pixel has max distance to mean
template <class ImageType, class AccessRGB>
class FilterKuwaharaNagaoReplaceMeanMinIfMax
{
public:
void Replace(ImageType &Input, ImageType &Output, int x, int y, const tools::CROI &ROI, float mr, float mg, float mb)
{
unsigned char
mri = (unsigned char)mr,
mgi = (unsigned char)mg,
mbi = (unsigned char)mb,
bestr,bestg,bestb;
float MinMeanDist = -1, MaxMeanDist = -1;
int MaxMeanDistX, MaxMeanDistY;
for (unsigned int ry = y+ROI.y1(); ry <= y+ROI.y2(); ++ry)
{
for (unsigned int rx = x+ROI.x1(); rx <= x+ROI.x2(); ++rx)
{
unsigned char
r = AccessRGB::GetR(Input(rx,ry)),
g = AccessRGB::GetG(Input(rx,ry)),
b = AccessRGB::GetB(Input(rx,ry));
float d = tools::DistRGBEuklidPow2(r, g, b, mri, mgi, mbi);
if (MinMeanDist < 0)
{ // first pixel
MaxMeanDist = d;
MaxMeanDistX = rx;
MaxMeanDistY = ry;
MinMeanDist = d;
bestr = r;
bestg = g;
bestb = b;
}else
{
if (d > MaxMeanDist)
{
MaxMeanDist = d;
MaxMeanDistX = rx;
MaxMeanDistY = ry;
}
if (d < MinMeanDist)
{
MinMeanDist = d;
bestr = r;
bestg = g;
bestb = b;
}
}
}
}
if (MaxMeanDistX == x && MaxMeanDistY == y)
{ // replace if center pixe has maximum distance to mean
Output(x,y) = AccessRGB::PackRGB(bestr,bestg,bestb);
}else
{ // center pixel is ok
Output(x,y) = Input(x,y);
}
}
};
/// \author Dirk Balthasar (private)
/// Kuwahara Nagao Filter core
/// replace sector with lowest variance by value calucalted with plugin
/// \param PixelReplacer nessecary because of a compiler bug with templates in vcpp 6.0
template <class ImageType, class AccessRGB, class FilterKuwaharaNagaoReplacePixel>
void FilterKuwaharaNagaoGenericCore(ImageType &Input, ImageType &Output, FilterKuwaharaNagaoReplacePixel &PixelReplacer, std::vector<tools::CROI> &coord, const CROI &ROI)
{
int w = Input.GetWidth(),
h = Input.GetHeight();
if (Output.GetWidth() != w || Output.GetHeight() != h)
Output.SetSize(w,h);
int sectors = coord.size();
float varr, varg, varb;
std::vector<float> varrgb, mr, mg, mb;
varrgb.resize(sectors);
mr.resize(sectors);
mg.resize(sectors);
mb.resize(sectors);
for (unsigned int y = ROI.y1(); y <= ROI.y2(); ++y)
{
for (unsigned int x = ROI.x1(); x <= ROI.x2(); ++x)
{
// calculate variance of all sectors
for (char s = 0; s < sectors; ++s)
{
tools::Variance<ImageType, AccessRGB>(Input, tools::CROI(x+coord[s].x1(), y+coord[s].y1(), x+coord[s].x2(), y+coord[s].y2()), varr, varg, varb, mr[s], mg[s], mb[s]);
varrgb[s] = varr + varg + varb;
}
// find sector with lowest variance
char mVar = 0;
for (char i = 1; i < sectors; i++) if (varrgb[i] < varrgb[mVar]) mVar = i;
// replace color by using plugin
PixelReplacer.Replace(Input, Output, x, y, coord[mVar], mr[mVar], mg[mVar], mb[mVar]);
}
}
}
/// \author Dirk Balthasar (private)
/// Kuwahara Nagao Filter with generic core plugins
/// replace sector with lowest variance by value calucalted with plugin
/// \param PixelReplacer nessecary because of a compiler bug with templates in vcpp 6.0
template <class ImageType, class AccessRGB, class FilterKuwaharaNagaoReplacePixel>
void FilterKuwaharaNagaoGeneric(ImageType &Input, ImageType &Output, FilterKuwaharaNagaoReplacePixel &PixelReplacer)
{
int w = Input.GetWidth(),
h = Input.GetHeight();
if (Output.GetWidth() != w || Output.GetHeight() != h) Output.SetSize(w,h);
std::vector<tools::CROI> coord;
// core pixels
coord.resize(4);
coord[0] = tools::CROI(-1, -1, 0, 0);// upper left sector
coord[1] = tools::CROI( 0, -1, +1, 0);// upper right sector
coord[2] = tools::CROI( 0, 0, +1, +1);// lower right sector
coord[3] = tools::CROI(-1, 0, 0, +1);// lower left sector
FilterKuwaharaNagaoGenericCore<ImageType, AccessRGB, FilterKuwaharaNagaoReplacePixel>(Input, Output, PixelReplacer, coord, tools::CROI(1, 1, w-2, h-2));
coord.resize(2);
// left border
coord[0] = tools::CROI( 0, -1, +1, 0);// upper right sector
coord[1] = tools::CROI( 0, 0, +1, +1);// lower right sector
FilterKuwaharaNagaoGenericCore<ImageType, AccessRGB, FilterKuwaharaNagaoReplacePixel>(Input, Output, PixelReplacer, coord, tools::CROI(0, 1, 0, h-2));
// right border
coord[0] = tools::CROI(-1, -1, 0, 0);// upper left sector
coord[1] = tools::CROI(-1, 0, 0, +1);// lower left sector
FilterKuwaharaNagaoGenericCore<ImageType, AccessRGB, FilterKuwaharaNagaoReplacePixel>(Input, Output, PixelReplacer, coord, tools::CROI(w-1, 1, w-1, h-2));
// upper border
coord[0] = tools::CROI( 0, 0, +1, +1);// lower right sector
coord[1] = tools::CROI(-1, 0, 0, +1);// lower left sector
FilterKuwaharaNagaoGenericCore<ImageType, AccessRGB, FilterKuwaharaNagaoReplacePixel>(Input, Output, PixelReplacer, coord, tools::CROI(1, 0, w-2, 0));
// lower border
coord[0] = tools::CROI(-1, -1, 0, 0);// upper left sector
coord[1] = tools::CROI( 0, -1, +1, 0);// upper right sector
FilterKuwaharaNagaoGenericCore<ImageType, AccessRGB, FilterKuwaharaNagaoReplacePixel>(Input, Output, PixelReplacer, coord, tools::CROI(1, h-1, w-2, h-1));
coord.resize(1);
// upper left corner
coord[0] = tools::CROI( 0, 0, +1, +1);// lower right sector
FilterKuwaharaNagaoGenericCore<ImageType, AccessRGB, FilterKuwaharaNagaoReplacePixel>(Input, Output, PixelReplacer, coord, tools::CROI(0, 0, 0, 0));
// upper right corner
coord[0] = tools::CROI(-1, 0, 0, +1);// lower left sector
FilterKuwaharaNagaoGenericCore<ImageType, AccessRGB, FilterKuwaharaNagaoReplacePixel>(Input, Output, PixelReplacer, coord, tools::CROI(w-1, 0, w-1, 0));
// lower left border
coord[0] = tools::CROI( 0, -1, +1, 0);// upper right sector
FilterKuwaharaNagaoGenericCore<ImageType, AccessRGB, FilterKuwaharaNagaoReplacePixel>(Input, Output, PixelReplacer, coord, tools::CROI(0, h-1, 0, h-1));
// lower right border
coord[0] = tools::CROI(-1, -1, 0, 0);// upper left sector
FilterKuwaharaNagaoGenericCore<ImageType, AccessRGB, FilterKuwaharaNagaoReplacePixel>(Input, Output, PixelReplacer, coord, tools::CROI(w-1, h-1, w-1, h-1));
}
/// Symmetric nearest neighbour, help function
/// \author Dirk Balthasar
template <class ImageType, class AccessRGB>
void FilterSNNcore(ImageType &Input, ImageType &Output, const tools::CROI &ROI, std::vector<tools::CROI>& coord)
{
int sz = coord.size();
for (unsigned int y = ROI.y1(); y < ROI.y2(); ++y)
{
for (unsigned int x = ROI.x1(); x < ROI.x2(); ++x)
{
int mr = 0, mg = 0, mb = 0;
for (char a = 0; a < sz; ++a)
{
unsigned char
cr = AccessRGB::GetR(Input(x,y)),
cg = AccessRGB::GetG(Input(x,y)),
cb = AccessRGB::GetB(Input(x,y)),
r1 = AccessRGB::GetR(Input(x+coord[a].x1(),y+coord[a].y1())),
g1 = AccessRGB::GetG(Input(x+coord[a].x1(),y+coord[a].y1())),
b1 = AccessRGB::GetB(Input(x+coord[a].x1(),y+coord[a].y1())),
r2 = AccessRGB::GetR(Input(x+coord[a].x2(),y+coord[a].y2())),
g2 = AccessRGB::GetG(Input(x+coord[a].x2(),y+coord[a].y2())),
b2 = AccessRGB::GetB(Input(x+coord[a].x2(),y+coord[a].y2()));
if (tools::DistRGBEuklidPow2(cr, cg, cb, r1, g1, b1) < tools::DistRGBEuklidPow2(cr, cg, cb, r2, g2, b2))
{ // 1
mr += r1;
mg += g1;
mb += b1;
}else
{ // 2
mr += r2;
mg += g2;
mb += b2;
}
}
// replace color by mean of r, g, b
Output(x,y) = AccessRGB::PackRGB(mr/4, mg/4, mb/4);
}
}
}
/// Filter Symmetric nearest neighbour
/// \author Dirk Balthasar
template <class ImageType, class AccessRGB>
void FilterSNN(ImageType &Input, ImageType &Output)
{
int w = Input.GetWidth(),
h = Input.GetHeight();
if (Output.GetWidth() != w || Output.GetHeight() != h)
Output.SetSize(w,h);
std::vector<tools::CROI> coord;
// core of image
coord.resize(4);
coord[0] = tools::CROI(-1, -1, +1, +1);
coord[1] = tools::CROI( 0, -1, 0, +1);
coord[2] = tools::CROI(+1, -1, -1, +1);
coord[3] = tools::CROI(-1, 0, +1, 0);
FilterSNNcore<ImageType, AccessRGB>(Input, Output, tools::CROI(1, 1, w-1, h-1), coord);
// corner dots (just clone)
for (int y = 0; y < h; y++)
{
Output(0,y) = Input(0,y);
Output(w-1,y) = Input(w-1,y);
}
for (int x = 0; x < w; x++)
{
Output(x,0) = Input(x,0);
Output(x,h-1) = Input(x,h-1);
}
}
};
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -