[英]How do I draw an image based on a simple polygon?
我想將一個大致矩形的區域復制到一個矩形區域。 例:
兩個區域都由角點定義。 總體方向保持不變(沒有翻轉等)。
簡單地旋轉源圖像不起作用,因為相對的側面可能具有不同的長度。
到目前為止,我發現在純C#中沒有辦法做到這一點(手動像素復制除外),所以我想我必須求助於Windows API或某些第三方庫?
由於我找不到答案,我自己寫了一個天真的實現。 它運作得相當好。
例子
我在Paint中手動繪制了所有示例,因此它們不是很精確 - 它足以測試一些基礎知識。
a)輕微旋轉。
資源:
結果:
b)各方面
資源:
結果:
c)觀點
資源:
結果:
碼
(它專門用於我的用例,但應該很容易適應):
// _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;
}
一般來說,您要做的是通過轉換函數將目標坐標映射到源坐標:
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坐標的轉換的對象(反之亦然)。
在dest坐標中工作將更容易避免重新轉換的源圖像中的曲線並允許您更好的抗鋸齒,因為您可以將dest像素的角映射到源圖像並在其中進行采樣並插值/外推。
在你的情況下,你將有一組線性方程式進行映射 - 在這種情況下,這被稱為四邊形翹曲 - 請參閱前一個問題 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.