WallPaper

HomePage | Memberswill go by tor | RecentChanges | Join |

把你的影子撒點鹽醃起來,風乾,老的時候下酒。

一般而言年紀越大會累積越多不堪回首的東西,例如年輕時候投資後來倒閉公司的股票,憤恨不平是難免,當然可以按鈴控告老闆,但是能拿回多少只有無語問蒼天;曾經價值不斐如今只能當壁紙。以下說明一個方法,可以根據這些不堪回首的圖片,一轉念,製造出精美的名符其實的壁紙,

所謂壁紙是指在兩個方向上不斷重複的某種圖案,數學上可以證明全宇宙的壁紙的對稱形式只有十七種。先看看其中一種根據兩張底圖和分別做出的壁紙:

廢紙:

壁紙:

廢紙:

壁紙:

壁紙上會有所有底圖細部的圖案,只是呈現上會平滑的變形。如果底圖的畫素夠高的話,壁紙上連那些字都會看得清楚。

基本上做法是這樣。把平面視為一個複數平面,所以一個點在平面上的位置就是一個複數。以 z 1z_1 代表底圖平面的位置的複數,以 zz 代表壁紙平面的位置的複數。給定一個複數到複數的函數,z 1=wallpaper(z)z_1=wallpaper(z)。把 z 1z_1 的顏色塗在 zz 上(如果 z 1z_1 超出底圖的邊界就把 zz 塗上黑色),然後在這些對稱性限制之下去選擇符合這些對稱性限制的 wallpaperwallpaper 函數。

例如上面這個壁紙例子要求對實數軸和120度轉角對稱,所以隨便給定 a(n,m)a(n,m) 這些複數,只要 a(n,m)=a(m,n)a(n,m)=a(m,n),任何 wallpaper(z)= n,ma(n,m)W(z,n,m)wallpaper(z) = \sum_{n,m} { a(n,m) \cdot W(z, n, m) } 都有這樣的對稱。請參看這個程式:

using System;  
using System.Drawing;  
using JoshuaChen.Quant;
 
namespace tester {  
class Program {  
static Bitmap oldmap, newmap;  
static Color bg = Color.Black;  
static Complex omega = new Complex(-0.5, Math.Sqrt(3) / 2);  
static double k1 = 2 / Math.Sqrt(3), k3, k4;  
static Complex k2 = 2 * Math.PI * Complex.I;
 
static void z_to_XY(Complex z, out double X, out double Y) { // z = X * 1 + Y * omega  
Y = k1 * z.Im;  
X = z.Re + Y / 2;  
}
 
static Complex E(double X, double Y, int n, int m) { // therefore the same evaluation for z + n * 1 or z + m * omega  
return Complex.Exp(k2 * (n * X + m * Y));  
}  
static Complex W(double X, double Y, int n, int m) { // (E(z) + E(omega * z) + E(omega^2 * z))/3 ,therefore the same for 120 degree rotation  
return (E(X, Y, n, m) + E(X, Y, m, -n - m) + E(X, Y, -n - m, n)) / 3;  
}  
// x1,y1 are scaled between -0.5-0.5I ~ 0.5+0.5I  
static void z_to_x1y1(ref Complex z, out int x1, out int y1) {  
x1 = (int)((z.Re + 0.5) * oldmap.Width);  
y1 = (int)((z.Im + 0.5) * oldmap.Height);  
}  
// x,y are scaled between -1.5-1.5I ~ 1.5+1.5I  
static Complex xy_to_z(int x, int y) {  
Complex z = new Complex();  
z.Re = -1.5 + x * k3;  
z.Im = -1.5 + y * k4;  
return z;  
}
 
// static Complex a1 = new Complex(-0.125, 0.2), a2 = new Complex(0.225, -0.35);  
static Complex a1 = new Complex(-0.06, 0.1), a2 = new Complex(0.11, -0.17);  
// wallpaper function map -1.5-1.5I ~ 1.5+1.5I hopefully into -0.5-0.5I ~ 0.5+0.5I symmetrically  
static Complex wallpaper(Complex z) {  
double X, Y;  
z_to_XY(z, out X, out Y);  
return a1 * (W(X, Y, 2, 1) + W(X, Y, 1, 2)) + a2 * (W(X, Y, 3, 7) + W(X, Y, 7, 3));  
}
 
static void xy_to_x1y1(int x, int y, out int x1, out int y1) {  
Complex ans = wallpaper(xy_to_z(x,y));  
z_to_x1y1(ref ans, out x1, out y1);  
}
 
static void Main(string[] args) {  
string src = args[0], res = args[1];  
oldmap = (Bitmap)Bitmap.FromFile(src);  
newmap = new Bitmap(3 * oldmap.Width, 3 * oldmap.Height);  
k3 = 3.0 / newmap.Width;  
k4 = 3.0 / newmap.Height;  
for (int x = 0; x \< newmap.Width; x++) {  
for (int y = 0; y \< newmap.Height; y++) {  
int x1, y1;  
xy_to_x1y1(x, y, out x1, out y1);  
Color c;  
if (x1 \>= 0 && x1 \< oldmap.Width && y1 \>= 0 && y1 \< oldmap.Height) {  
c = oldmap.GetPixel(x1, y1);  
} else {  
c = bg;  
}  
newmap.SetPixel(x, y, c);  
}  
}  
newmap.Save(res);  
}  
}  
}