2011-04-20 5 views
11

मैं एक आयताकार क्षेत्र में एक आयताकार क्षेत्र की प्रतिलिपि बनाना चाहता हूं। उदाहरण:मैं एक साधारण बहुभुज के आधार पर एक छवि कैसे आकर्षित करूं?

दोनों क्षेत्रों में अपने कोने अंक द्वारा परिभाषित कर रहे हैं। सामान्य दिशा रखी जाती है (कोई फिसलने आदि नहीं)।

बस स्रोत छवि को घूर्णन करना काम नहीं करता है क्योंकि विरोधी पक्ष अलग-अलग लंबाई के हो सकते हैं।

अब तक मुझे शुद्ध सी # (मैन्युअल पिक्सेल प्रतिलिपि को छोड़कर) में ऐसा करने का कोई तरीका नहीं मिला है, इसलिए मुझे लगता है कि मुझे विंडोज एपीआई या कुछ तृतीय पक्ष लाइब्रेरी का सहारा लेना है?

उत्तर

3

सामान्य शब्दों में, आप क्या करना चाहते नक्शा गंतव्य स्रोत के लिए निर्देशांक है

for (int y = 0; y < destHeight; y++) { 
    for (x=0; x < destWidth; x++) { 
     Color c = Transform(x, y, sourceImage, sourceTransform); 
     SetPixel(destImage, x, y, c); 
    } 
} 

मान लेते हैं कि sourceTransform एक वस्तु है कि इतने से एक परिवर्तन समाहित है दो: एक को बदलने समारोह के माध्यम से निर्देशांक dest समन्वय करने के लिए urce (और इसके विपरीत)।

dest coordinates में कार्य करना आपके पुनर्नवीनीकरण स्रोत छवि में उस वक्र से बचना आसान हो जाएगा और आपको बेहतर एंटीअलियास की अनुमति देगा, क्योंकि आप स्रोत छवि में भाग पिक्सेल के कोनों को मैप कर सकते हैं और इसके भीतर नमूना और इंटरपोलेट/एक्सट्रपलेशन।

आपके मामले में आप रैखिक समीकरणों का एक सेट होने जा रहे हैं जो मैपिंग करते हैं - इस मामले में इसे चतुर्भुज warping - see this previous question के रूप में जाना जाता है।

8

चूंकि मुझे कोई जवाब नहीं मिला, इसलिए मैंने खुद को एक निष्पक्ष कार्यान्वयन लिखा। यह काफी अच्छी तरह से काम करता है।

उदाहरण

मैं मैन्युअल रूप से पेंट के सारे उदाहरण आकर्षित किया है, तो वे बहुत सटीक नहीं हैं - यह बस कुछ बुनियादी बातों का परीक्षण करने के लिए पर्याप्त था।

ए) थोड़ा रोटेशन।

स्रोत:

source image

परिणाम:

resulting image

ख) विभिन्न पक्षों

स्रोत:

source 2

परिणाम:

result 2

ग) परिप्रेक्ष्य

स्रोत:

source 3

परिणाम:

result 3

कोड

(यह मेरी उपयोग के मामले के लिए विशेष है, लेकिन यह अनुकूलित करने के लिए आसान होना चाहिए):

// _Corners are, well, the 4 corners in the source image 
// _Px is an array of pixels extracted from the source image 

public void Rescale() 
{ 
    RescaleImage (
     _Corners[0], 
     _Corners[1], 
     _Corners[3], 
     _Corners[2], 
     100, 
     100); 
} 

private void RescaleImage (PointF TL, PointF TR, PointF LL, PointF LR, int sx, int sy) 
{ 
    var bmpOut = new Bitmap (sx, sy); 

    for (int x = 0; x < sx; x++) { 
     for (int y = 0; y < sy; y++) { 
      /* 
      * relative position 
      */ 
      double rx = (double) x/sx; 
      double ry = (double) y/sy; 

      /* 
      * get top and bottom position 
      */ 
      double topX = TL.X + rx * (TR.X - TL.X); 
      double topY = TL.Y + rx * (TR.Y - TL.Y); 
      double bottomX = LL.X + rx * (LR.X - LL.X); 
      double bottomY = LL.Y + rx * (LR.Y - LL.Y); 

      /* 
      * select center between top and bottom point 
      */ 
      double centerX = topX + ry * (bottomX - topX); 
      double centerY = topY + ry * (bottomY - topY); 

      /* 
      * store result 
      */ 
      var c = PolyColor (centerX, centerY); 
      bmpOut.SetPixel (x, y, c); 
     } 
    } 

    bmpOut.Save (_Path + "out5 rescale out.bmp"); 
} 

private Color PolyColor (double x, double y) 
{ 
    // get fractions 
    double xf = x - (int) x; 
    double yf = y - (int) y; 

    // 4 colors - we're flipping sides so we can use the distance instead of inverting it later 
    Color cTL = _Px[(int) y + 1, (int) x + 1]; 
    Color cTR = _Px[(int) y + 1, (int) x + 0]; 
    Color cLL = _Px[(int) y + 0, (int) x + 1]; 
    Color cLR = _Px[(int) y + 0, (int) x + 0]; 

    // 4 distances 
    double dTL = Math.Sqrt (xf * xf + yf * yf); 
    double dTR = Math.Sqrt ((1 - xf) * (1 - xf) + yf * yf); 
    double dLL = Math.Sqrt (xf * xf + (1 - yf) * (1 - yf)); 
    double dLR = Math.Sqrt ((1 - xf) * (1 - xf) + (1 - yf) * (1 - yf)); 

    // 4 parts 
    double factor = 1.0/(dTL + dTR + dLL + dLR); 
    dTL *= factor; 
    dTR *= factor; 
    dLL *= factor; 
    dLR *= factor; 

    // accumulate parts 
    double r = dTL * cTL.R + dTR * cTR.R + dLL * cLL.R + dLR * cLR.R; 
    double g = dTL * cTL.G + dTR * cTR.G + dLL * cLL.G + dLR * cLR.G; 
    double b = dTL * cTL.B + dTR * cTR.B + dLL * cLL.B + dLR * cLR.B; 

    Color c = Color.FromArgb ((int) (r + 0.5), (int) (g + 0.5), (int) (b + 0.5)); 

    return c; 
} 
+0

यह वाकई अच्छा है! इसे पढ़ने के बाद एकमात्र शब्द जिसे मैं सोच सकता हूं "एंटी-स्कू" है। अच्छा काम :) – Tom

+1

मुझे पता है कि यह एक पुरानी पोस्ट है, लेकिन आपका मतलब है कि * हम किनारे फिसल रहे हैं ताकि हम आपके 'पॉलीकॉलर' में बाद में * * को बदलने के बजाय दूरी का उपयोग कर सकें क्योंकि यदि आपकी छवि 800x600 है एक indexOutOfRangeExeption मिलेगा – WiiMaxx

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^