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
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
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
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
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
#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
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
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
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.