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.csdn.net/images/p_blog_csdn_net/quanben/379511/o_ditu_ori.PNG
Processed Image:
https://p-blog.csdn.net/images/p_blog_csdn_net/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、付费专栏及课程。

余额充值