An Algorithm for Efficient Image Warping

Need to redo your image? Here's a nice algorithm to transform it as you like.


September 01, 2001
URL:http://www.drdobbs.com/an-algorithm-for-efficient-image-warping/184401431

September 2001/An Algorithm for Efficient Image Warping/Figure 1

Figure 1: Input and output for morphing rectangle

September 2001/An Algorithm for Efficient Image Warping/Figure 2

Figure 2: Sample output

September 2001/An Algorithm for Efficient Image Warping/Listing 1

Listing 1: Partial listing of delta.h

struct deltacontrol{
    int current;
    int delta;
    int len;
    int togo;
};

class DeltaControl
{
public:
    DeltaControl();
    virtual void SetFrom(int Major, int Minor);
    virtual void SetTo(int Major, int Minor);
    virtual BOOL Next();
    int GetMajor() {return m_Major.current;};
    int GetMinor() {return m_Minor.current;};
    virtual int GetLength() {return m_Minor.len + m_Major.len;};
protected:
    virtual void OnMajorChange(int Current) {};
    virtual void OnMinorChange(int Current) {};
    deltacontrl m_Major;
    deltacontrl m_Minor;
    int m_ErrorTerm;
    virtual void SetTo(int In, deltacontrol *Out);
    BOOL m_MinorLast;
};
— End of Listing —
September 2001/An Algorithm for Efficient Image Warping/Listing 2

Listing 2: Partial listing of delta.cpp

DeltaControl::DeltaControl() {
    static deltacontrol d = {0,0,0,0};
    m_Major = d;
    m_Minor = d;
    m_ErrorTerm = 0;
}

void DeltaControl::SetFrom(int Major, int Minor) {
    m_Major.current = Major;
    m_Minor.current = Minor;
}

void DeltaControl::SetTo(int Major, int Minor) {
    SetTo(Major, &m_Major);
    SetTo(Minor, &m_Minor);
    m_ErrorTerm = m_Major.len / 2;
    m_MinorLast = TRUE;
}

BOOL DeltaControl::Next() {
    if (m_MinorLast) m_MinorLast = FALSE;
    else {
        m_ErrorTerm += m_Minor.len;
        if (m_ErrorTerm > m_Major.len && m_Minor.togo) {
            m_Minor.current += m_Minor.delta;
            OnMinorChange(m_Minor.current);
            m_ErrorTerm -= m_Major.len;
            m_Minor.togo--;
            m_MinorLast = TRUE;
            return TRUE;
        }
    }
    if (!m_Major.togo) return FALSE;
    m_Major.current += m_Major.delta;
    m_Major.togo--;
    OnMajorChange(m_Major.current);
    return TRUE;
}

void DeltaControl::SetTo(int In, deltacontrol *Out) {
    int i = In - Out->current;

    Out->delta = (i < 0) ? -1 : 1;
    Out->togo = Out->len = abs(i);
}
— End of Listing —
September 2001/An Algorithm for Efficient Image Warping/Listing 3

Listing 3: Excerpt from delta.h

class DeltaControlLine : public DeltaControl, public CPoint
{
public:
    DeltaControlLine(CPoint *From, CPoint *To);
    DeltaControlLine(CPoint *From, CPoint *To, CPoint *Offset);
    virtual ~DeltaControlLine() {};
protected:
    virtual void Init(CPoint *From, CPoint *To);
    virtual void OnMajorChange(int Current) {*m_PMajor=Current;};
    virtual void OnMinorChange(int Current) {*m_PMinor=Current;};
    long *m_PMajor;
    long *m_PMinor;
};

exceprt from delta.cpp

DeltaControlLine::DeltaControlLine(CPoint *From, CPoint *To) {
    Init(From, To);
}

DeltaControlLine::DeltaControlLine(CPoint *From, CPoint *To,
        CPoint *Offset) {
    Init(From, To);
    CPoint::Offset(*Offset);
    m_Major.current = *m_PMajor;
    m_Minor.current = *m_PMinor;
}

void DeltaControlLine::Init(CPoint *From, CPoint *To) {
    CPoint p = *From;
    p -= *To;
    if (abs(p.x) > abs(p.y)) {
        SetFrom(From->x, From->y);
        SetTo(To->x, To->y);
        m_PMajor = &x;
        m_PMinor = &y;
    }
    else {
        SetFrom(From->y, From->x);
        SetTo(To->y, To->x);
        m_PMajor = &y;
        m_PMinor = &x;
    }
    x = From->x;
    y = From->y;
}
— End of Listing —
September 2001/An Algorithm for Efficient Image Warping/Listing 4

Listing 4: Class DeltaControlPair

excerpt from delta.h

class DeltaControlPair : public DeltaControl
{
public:
    DeltaControlPair(DeltaControl *A, DeltaControl *B);
    virtual ~DeltaControlPair() {};
    virtual int GetLength() {return m_Major.len;};
    virtual BOOL Next();
protected:
    virtual void OnMajorChange(int Current) {m_PMajor->Next();};
    virtual void OnMinorChange(int Current) {m_PMinor->Next();};
    DeltaControl *m_PMajor;
    DeltaControl *m_PMinor;
};

excerpt from delta.cpp

DeltaControlPair::DeltaControlPair(DeltaControl *A,
        DeltaControl *B) {
    SetFrom(0, 0);
    if (A->GetLength() > B->GetLength()) {
        SetTo(A->GetLength(), B->GetLength());
        m_PMajor = A;
        m_PMinor = B;
    }
    else {
        SetTo(B->GetLength(), A->GetLength());
        m_PMajor = B;
        m_PMinor = A;
    }
}

BOOL DeltaControlPair::Next() {
    m_ErrorTerm += m_Minor.len;
    if (m_ErrorTerm > m_Major.len && m_Minor.togo) {
        m_Minor.current += m_Minor.delta;
        OnMinorChange(m_Minor.current);
        m_ErrorTerm -= m_Major.len;
        m_Minor.togo--;
    }
    if (!m_Major.togo) return FALSE;
    m_Major.current += m_Major.delta;
    m_Major.togo--;
    OnMajorChange(m_Major.current);
    return TRUE;
}
— End of Listing —
September 2001/An Algorithm for Efficient Image Warping/Listing 5

Listing 5: Definition of the CImageBitmap class

#ifndef IMAGE_H
#define IMAGE_H

class CIBHelper;

class CImageBitmap : public CBitmap
{
public:
    CImageBitmap();
    virtual ~CImageBitmap();
    BOOL LoadBMPFile(const char *Filespec);
    BOOL CreateFromBMPFile(CDC *pDC);
    void LoadDataFromBMPFile();
    BOOL CreationRequired() {return (m_Private == NULL);};
    BOOL BMPLoaded() {return (m_Image != NULL);};
    operator BITMAP *() {return m_Private ? &m_Bitmap : 0;};
    operator CSize *() {return m_Image ? &m_Size : 0;};
    operator CIBHelper *() {return m_Private;};
    void *GetPixel(CPoint *Point);
    BOOL PutPixel(CPoint *Point, void *In);
    void Transform(CImageBitmap *In, CPoint *TopLeft, 
        CPoint *BottomLeft, CPoint *TopRight,
        CPoint *BottomRight, CPoint *Offset);
private:
    CIBHelper *m_Private;
    CSize m_Size;
    BITMAP m_Bitmap;
    BITMAPINFOHEADER m_Hdr;
    char *m_Image;
    CString m_Title;
};

#endif
— End of Listing —
September 2001/An Algorithm for Efficient Image Warping/Listing 6

Listing 6: Definition for the private CIBHelper

class CIBHelper : public CObject
{
public:
    CIBHelper(CImageBitmap *Parent = 0);
    virtual ~CIBHelper();
    virtual void LoadDataFromBMPFile(BITMAPINFOHEADER *Hdr,
        char *Image) {};
    virtual void *GetPixel(CPoint *Point) {return 0;};
    virtual BOOL PutPixel(CPoint *Point, void *In) {return 0;};
    BOOL GoodCoords(CPoint *Point);
    operator char *() {return m_Image;};
    operator int() {return m_ImageSize;};
protected:
    CImageBitmap *m_Parent;
    char *GetBitmapBits();
    char **GetBitmapRows();
    char *m_Image;
    int m_ImageSize;
    char **m_Rows;
};
— End of Listing —
September 2001/An Algorithm for Efficient Image Warping/Listing 7

Listing 7: Shows where the drawing is controlled

void CImageBitmap::Transform(CImageBitmap *In, CPoint *TopLeft,
        CPoint *BottomLeft, CPoint *TopRight, CPoint *BottomRight,
        CPoint *Offset) {
    CIBHelper *p = *In;
    BITMAP *b = *In;

    // 1.
    /* controllers for moving the end points
        of the line to be stretched */
    DeltaControlLine left(TopLeft, BottomLeft);
    DeltaControlLine right(TopRight, BottomRight);
    DeltaControlPair output_y(&left, &right);

    // 2.
    // controller for moving down the input Y direction
    DeltaControl input_y; input_y.SetTo(b->bmHeight, 0);
    DeltaControlPair process_y(&input_y, &output_y);

    // 3.
    // outer loop
    do {
        // controller for outputing pixels in X direction
        DeltaControl input_x; input_x.SetTo(b->bmWidth, 0);
        CPoint pt(0, input_y.GetMajor());
        CIBLine output_x(&left, &right, &pt, p, Offset,
            *this);
        DeltaControlPair process_x(&input_x, &output_x);

        // inner loop
        do { pt.x = input_x.GetMajor();
        } while (process_x.Next());
    } while (process_y.Next());

    // update our CBitmap object
    SetBitmapBits(*m_Private, *m_Private);
}
— End of Listing —
September 2001/An Algorithm for Efficient Image Warping/Listing 8

Listing 8: Class CIBLine is derived from DeltaControlLine

class CIBLine : public DeltaControlLine
{
public:
    CIBLine(CPoint *From, CPoint *To, CPoint *Input,
        CIBHelper *Source, CPoint *Offset,
        CIBHelper *Dest);
    virtual ~CIBLine() {};
protected:
    virtual void OnMajorChange(int Current);
    virtual void OnMinorChange(int Current);
private:
    void PutPixel();
    CPoint *m_Input;
    CIBHelper *m_Source;
    CIBHelper *m_Dest;
};

CIBLine::CIBLine(CPoint *From, CPoint *To,
        CPoint *Input,  CIBHelper *Source, CPoint *Offset,
        CIBHelper *Dest)
            : DeltaControlLine(From, To, Offset) {
    m_Input = Input;
    m_Source = Source;
    m_Dest = Dest;
    // output the first pixel
    PutPixel();
}

void CIBLine::OnMajorChange(int Current) {
    DeltaControlLine::OnMajorChange(Current);
    PutPixel();
}

void CIBLine::OnMinorChange(int Current) {
    DeltaControlLine::OnMinorChange(Current);
    PutPixel();
}

void CIBLine::PutPixel() {
    m_Dest->PutPixel(this, m_Source->GetPixel(m_Input));
}

— End of Listing —

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.