Image Flattener

The code is to smooth out the JPEG artifacts on some digitized maps in order to facilitate the PNG compression. I finally decided to use some flood-style algorithm the result of which is somewhat satifactory (As applied on the 640x480 sample image, the sizeof the output PNG file is reduced from 613KB to 373KB without apparent distortion. Currently I care not too much about the speed.) Further improvment is expected to be made in refining the lines and the characters, which is intrinsically much tougher.

Original Image: https://p-blog.youkuaiyun.com/images/p_blog_youkuaiyun.com/quanben/379511/o_ditu_ori.PNG
Processed Image:
https://p-blog.youkuaiyun.com/images/p_blog_youkuaiyun.com/quanben/379511/o_ditu_enh.PNG

Following is the code area.

#include <iostream>

#include <cstdio>
#include <list>
#include <queue>
#include <vector>
#include <stack>
#include <malloc.h>
#include <cmath>

using namespace std;

typedef unsigned char Byte;

struct Pixel
{
Byte b,g,r;
Pixel () : r(0),g(0),b(0) {}
void Reset () { r=g=b=0; }
};

struct Coord
{
int x,y;
Coord () : x(0),y(0) {}
Coord (int _x, int _y) : x(_x),y(_y) {}
};

class Flattener
{
protected:
void Init ()
{
m_nAccepted = 0;
m_InitThr = (128*5) * 3;
m_BotThr = (128*5) * 3;
m_NumThr = 100;

m_SADThr = m_BotThr * 3/2;

}

int Diff (Pixel &pel)
{
int dr = (int)pel.r - m_MeanPel.r;
int dg = (int)pel.g - m_MeanPel.g;
int db = (int)pel.b - m_MeanPel.b;
dr = abs(dr);
dg = abs(dg);
db = abs(db);

return (65*dr+128*dg+25*db);
}

bool CloseEnough (Pixel &pel)
{
return (Diff(pel) < m_Thr);
}

void Accept (int p)
{
int nLastAccepted = m_nAccepted;
m_nAccepted++;
int halfn = m_nAccepted >> 1;

int v = m_MeanPel.r;
v *= nLastAccepted;
v += m_pSrc[p].r + halfn;
v /= m_nAccepted;
m_MeanPel.r = v;

v = m_MeanPel.g;
v *= nLastAccepted;
v += m_pSrc[p].g + halfn;
v /= m_nAccepted;
m_MeanPel.g = v;

v = m_MeanPel.b;
v *= nLastAccepted;
v += m_pSrc[p].b + halfn;
v /= m_nAccepted;
m_MeanPel.b = v;

// update
m_Thr = (int)((double)(m_InitThr - m_BotThr)
* pow(1.2, -nLastAccepted) + m_BotThr);
}

void Reject (int p)
{
// Do nothing
}

void Filter (int x, int y)
{
// N-point average
int D = 2;
int dymin = y>D-1?-D:-y;
int dxmin = x>0?-D:-x;
int dymax = y<m_H-D?D:m_H-y-1;
int dxmax = x<m_W-D?D:m_W-x-1;
int p = y * m_W + x;
int r=0, g=0, b=0;
int c = 0;
for (int dy=dymin; dy<=dymax; ++dy)
{
for (int dx=dxmin; dx<=dxmax; ++dx)
{
if (dx==0&&dy==0)
{
continue;
}
int nx = x+dx; int ny = y+dy;
int np = ny*m_W+nx;
r += m_pSrc[np].r;
g += m_pSrc[np].g;
b += m_pSrc[np].b;
c++;
}
}
r /= c; g /= c; b /= c;
m_pDst[p].r = r;
m_pDst[p].g = g;
m_pDst[p].b = b;
}


protected:
typedef vector< int > IntVec;

Pixel *m_pSrc;
Pixel *m_pDst;
IntVec m_Stat;
int m_nAccepted;
Pixel m_MeanPel;
int m_Thr;
int m_InitThr;
int m_BotThr;
int m_H, m_W;

int m_NumThr;
int m_Rx, m_Ry;
int m_SADThr;

public:
Flattener ()
{
}

~Flattener ()
{
}

void SetPic (Pixel *src, Pixel *dst, int w, int h)
{
m_Stat.resize(w*h, 0);
m_pSrc = src;
m_pDst = dst;
m_H = h, m_W = w;

memcpy(dst, src, w*h*3);
}

void FlattenAll ()
{
for (int y = 0; y < m_H; y++)
{
for (int x = 0; x < m_W; x++)
{
Flatten(x,y,true);
if (m_Rx != -1)
{
Flatten(m_Rx,m_Ry);
}
}
}
}

void Flatten (int sx, int sy, bool pre = false)
{
queue<Coord> q;
IntVec v1, v2;
Coord cc;

int x,y,nx,ny;
int p;

Init();

p = sy*m_W+sx;
if (m_Stat[p])
{
return;
}

cc.x = sx; cc.y = sy;
Accept(sy*m_W+sx);
q.push(cc);

while (!q.empty())
{
Coord &coord = q.front();
x = coord.x;
y = coord.y;
p = y*m_W+x;
Pixel &ctr = m_pSrc[p];
q.pop();
int dymin = y>0?-1:0;
int dxmin = x>0?-1:0;
int dymax = y<m_H-1?1:0;
int dxmax = x<m_W-1?1:0;
for (int dy=dymin; dy<=dymax; ++dy)
{
for (int dx=dxmin; dx<=dxmax; ++dx)
{
if (dx==0&&dy==0)
{
continue;
}
ny=y+dy;
nx=x+dx;
int np = ny*m_W+nx;
if (m_Stat[np]!=0)
{
continue;
}

cc.x = nx; cc.y = ny;
if (CloseEnough(m_pSrc[np]))
{
Accept(np);
q.push(cc);
m_Stat[np] = 1;
v1.push_back(np);
}
else
{
Filter(nx, ny);
if (CloseEnough(m_pDst[np]))
{
Accept(np);
q.push(cc);
m_Stat[np] = 1;
v1.push_back(np);
}
else
{
Reject(np);
m_Stat[np] = 2;
v2.push_back(np);
}
}
}
}
}


if (m_nAccepted > m_NumThr)
{
int md = 0x7fffffff; // max int
int t;
double sd = 0;

for (int i = 0; i < v1.size(); ++i )
{
if (pre)
{ // for actual processing in the next turn
int d = Diff(m_pSrc[v1[i]]);
if (d < md)
{
md = d;
t = v1[i];
}
m_Stat[v1[i]] = 0;
sd += d*d;

}
else
{
m_pDst[v1[i]] = m_MeanPel;
}
}

for (int i = 0; i < v2.size(); ++i )
{
m_Stat[v2[i]] = 0;
}

sd /= v1.size();
sd = sqrt(sd);
if (sd < m_SADThr)
{
m_Rx = t % m_W;
m_Ry = t / m_W;
}
else
{
m_Rx = m_Ry = -1;
}
}
else
{
for (int i = 0; i < v1.size(); ++i )
{
m_Stat[v1[i]] = 3; // skipped
}
for (int i = 0; i < v2.size(); ++i )
{
m_Stat[v2[i]] = 0;
}
m_Rx = m_Ry = -1;
}
}

void Finalize ()
{
for (int i = 0; i < m_W*m_H; ++i )
{
if (m_Stat[i] != 1)
{
m_pDst[i]=m_pSrc[i];
}
}
}

};

#define MAXH 480
#define MAXW 640

#define EndianU32_L2N(v) (v)

int main (void)
{
Flattener flattener;

FILE *fIn = fopen("in.bmp", "rb");
FILE *fOut = fopen("out.bmp", "wb");
Byte buf[MAXW*MAXH*3];
Byte dst[MAXW*MAXH*3];

fread(buf, 1, 54, fIn);
fwrite(buf, 1, 54, fOut);

unsigned long w, h;
w = EndianU32_L2N(*(unsigned long *)(buf + 18));
h = EndianU32_L2N(*(unsigned long *)(buf + 22));
printf("w = %d, h = %d/n", w, h);

int x = 255;
int y = 46;
fread(buf, 1, w*h*3, fIn);
flattener.SetPic((Pixel*)buf, (Pixel*)dst, w, h);
//flattener.Flatten(x, h-y);
flattener.FlattenAll();
flattener.Finalize();
fwrite(dst, 1, w*h*3, fOut);

fclose(fIn);
fclose(fOut);

return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值