Re: [問題] 圖片轉角度
※ 引述《sbty173 (我愛單眼皮)》之銘言:
: 各位前輩好
: 我最近用在做圖片的旋轉 用的是2003.net 的mfc寫
: 可是沒有什麼頭緒
: 去程式討論區發現有前輩做了一個類似的程式
: http://delphi.ktop.com.tw/topic.asp?topic_id=34152
: 他的button7 是作旋轉的
: 但他是用BCB做
: 內容如下
: void __fastcall TForm1::Button7Click(TObject *Sender)
: {
: Image2->AutoSize=true;
: int angle=StrToInt(Edit2->Text);
: Graphics::TBitmap *Bitmap1=new Graphics::TBitmap;
: Graphics::TBitmap *Bitmap2=new Graphics::TBitmap;
: Bitmap1->Assign(Image1->Picture->Bitmap);
: float radians=(2*3.1416*angle)/360; //不懂為何這樣設定??
: float cosine=(float)cos(radians);
: float sine=(float)sin(radians);
: float Point1x=(-Bitmap1->Height*sine);
: float Point1y=(Bitmap1->Height*cosine);
: float Point2x=(Bitmap1->Width*cosine-Bitmap1->Height*sine);
: float Point2y=(Bitmap1->Height*cosine+Bitmap1->Width*sine);
: float Point3x=(Bitmap1->Width*cosine);
: float Point3y=(Bitmap1->Width*sine);
: float minx=min(0,min(Point1x,min(Point2x,Point3x)));
: float miny=min(0,min(Point1y,min(Point2y,Point3y)));
: float maxx=max(Point1x,max(Point2x,Point3x));
: float maxy=max(Point1y,max(Point2y,Point3y));
: int Bitmap2Width=(int)ceil(maxx-minx);
: int Bitmap2Height=(int)ceil(maxy-miny);
: Bitmap2->Height=Bitmap2Height;
: Bitmap2->Width=Bitmap2Width;
: for(int x=0;x<Bitmap2Width;x++)
: {
: for(int y=0;y<Bitmap2Height;y++)
: {
: int Bitmap1x=(int)((x+minx)*cosine+(y+miny)*sine);
: int Bitmap1y=(int)((y+miny)*cosine-(x+minx)*sine);
: if(Bitmap1x>=0&&Bitmap1x<Bitmap1->Width&&Bitmap1y>=0&&Bitmap1y<Bitmap1->Height)
: {
: Bitmap2->Canvas->Pixels[x][y]=Bitmap1->Canvas->Pixels[Bitmap1x][Bitmap1y];
: }
: }
: }
: 我看不太懂為什麼要這樣做運算
: 不曉得前輩們可以幫我解釋一下嗎
: 還有請問語法有些我不太懂 要怎麼轉過來呢?
其實圖片的旋轉很簡單,用到的都是數學的公式而已!:)
把一張圖想成是放在一個數學座標上的圖來想,應該會比較好理解。
在數學的旋轉上面....
如果我要將 (x, y) 的點,逆時鐘旋轉 30 度變成 (x' , y')
哪麼公式是...
x' = cos30 * x - sin30 * y
y' = sin30 * x + cos30 * y
看了上面的公式,直覺的做法就是用雙 for 將原圖全部的 pixel 跑一次...
然後算出旋轉後的新位置,存到新的陣列中。
但是這樣做你會發現....
for (i = 0; i < old_bmp_h; i++)
for (j = 0; j < old_bmp_w; j++)
{
x' = cos(30度) * j - sin(30度) * i;
y' = cos(30度) * j - sin(30度) * i;
// cos() 裡面要傳入的是 "徑度"
// radians=(2*3.1416*angle)/360; //不懂為何這樣設定??
// 就是在轉成徑度用的。
new_bmp[x'][y'] = old_bmp[i][j];
}
如此作完,結果一定很難看....
因為 cos(30) * j - sin(30) * i 算出來的結果有可能是小數
如果說 x' = 30.1 那會被強制變成整數為 30
下一個 pixel 算出來 x' = 30.3 結果還是會是 30
所以,到最後的結果就會有很多旋轉前的 pixel 都填入同一個旋轉後的 pixel
而很多旋轉後的 pixel 沒有值填入。
因此!我們需要逆向思考!
for (i = 0; i < new_bmp_h; i++)
for (j = 0; j < new_bmp_w; j++)
{
x = ............... ;
y = ............... ;
// 倒過來個公式自己用數學代數算一下就出來了!:)
new_bmp[i][j] = old_bmp[x][y];
}
這樣是把旋轉後的每一個 pixel 都跑過一次....
反算應該要用旋轉前的哪一個 pixel 填入。
做到這樣,結果就會好很多了,但是會發現會有鋸齒狀。
所以有更好的演算法可以幫助你做的更好。
1. 最近鄰居法。
最簡單,但是效果非常有限。
2. biliner。
簡單,效過又好。
3. bicubic。
複雜,效過最好。
建議可以做到2就可以了!^^
至於詳細的內容,可以用 google 找一下就可以找到了。^^
2, 3 也是常常用在將圖片放大、縮小的時候。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 218.163.159.53
→
09/27 21:59, , 1F
09/27 21:59, 1F
※ 編輯: qazq 來自: 218.163.159.53 (09/27 22:02)
推
09/28 00:23, , 2F
09/28 00:23, 2F
推
09/28 10:40, , 3F
09/28 10:40, 3F
C_and_CPP 近期熱門文章
PTT數位生活區 即時熱門文章