內插法改寫為SCANLINE(引用JerryKuo版主程式) |
尚未結案
|
dean
一般會員 發表:24 回覆:60 積分:21 註冊:2003-08-23 發送簡訊給我 |
各位前輩好:
小弟根據JerryKuo版主的程式去改寫為SCANLINE,希望能讓速度快一點,因為我想比較內插法與WINDOW提供的COPYRECT速度差異。但小弟更改之後大小有變動,但圖片內容卻卻非我所想要,請指引小弟謝謝!
DWORD BTime; BTime=timeGetTime(); //測試時間 Graphics::TBitmap *Bmp = new Graphics::TBitmap(); Bmp->Assign(Image2->Picture->Bitmap); Graphics::TBitmap *NBmp = new Graphics::TBitmap(); NBmp->PixelFormat=pf24bit; int w,h,newW,newH; double dX,dY,x,y; int i,j; int ix,iy; // integer value of (x,y) double fx,fy; // float value of (x,y) unsigned char clr, clrR,clrG,clrB, nclr1,nclr2,nclr3,nclr4; // color of neighbor 4 pixel w = Bmp->Width; h = Bmp->Height; newW = 50;//StrToInt(Edit1->Text); newH = 50;//StrToInt(Edit2->Text); if((newW <=0) ||(newH <=0)) { ShowMessage("Invalided parameter"); return; } NBmp->Width = newW; NBmp->Height = newH; /* Caculate the step size of movement */ dX = (double)w/(double)newW; dY = (double)h/(double)newH; Byte *ptr_up, *ptr_mid, *ptr_down; for(j = 1 ; j < newH-1 ; j ) { ptr_up=(Byte *)Bmp->ScanLine[j-1]; ptr_mid=(Byte *)Bmp->ScanLine[j]; ptr_down=(Byte *)Bmp->ScanLine[j 1]; for(i =1 ; i < newW-1 ; i ) { x = dX*(double)i; y = dY*(double)j; ix = (int)x; iy = (int)y; fx = x - (float)ix; fy = y - (float)iy; nclr1 = (ptr_mid)[i*3 2]; //GetRValue(Bmp->Canvas->Pixels[ix][iy]); nclr2 = (ptr_down)[i*3 2]; //GetRValue(Bmp->Canvas->Pixels[ix 1][iy]); nclr3 = (ptr_mid)[i*2*3 2]; //GetRValue(Bmp->Canvas->Pixels[ix][iy 1]); nclr4 = (ptr_down)[i*2*3 2]; //GetRValue(Bmp->Canvas->Pixels[ix 1][iy 1]); // Bilinear clrR=(byte)((1.0-fx)*(1.0-fy)*(double)nclr1 (fx)*(1.0-fy)*(double)nclr2 (1.0-fx)* (fy)*(double)nclr3 (fx)* (fy)*(double)nclr4); nclr1 = (ptr_mid)[i*3 1]; //GetGValue(Bmp->Canvas->Pixels[ix][iy]); nclr2 = (ptr_down)[i*3 1]; //GetGValue(Bmp->Canvas->Pixels[ix 1][iy]); nclr3 = (ptr_mid)[i*2*3 1]; //GetGValue(Bmp->Canvas->Pixels[ix][iy 1]); nclr4 = (ptr_down)[i*2*3 1]; //GetGValue(Bmp->Canvas->Pixels[ix 1][iy 1]); // Bilinear clrG=(byte)((1.0-fx)*(1.0-fy)*(double)nclr1 (fx)*(1.0-fy)*(double)nclr2 (1.0-fx)* (fy)*(double)nclr3 (fx)* (fy)*(double)nclr4); nclr1 = (ptr_mid)[i*3]; //GetBValue(Bmp->Canvas->Pixels[ix][iy]); nclr2 = (ptr_down)[i*3]; //GetBValue(Bmp->Canvas->Pixels[ix 1][iy]); nclr3 = (ptr_mid)[i*2*3]; //GetBValue(Bmp->Canvas->Pixels[ix][iy 1]); nclr4 = (ptr_down)[i*2*3]; //GetBValue(Bmp->Canvas->Pixels[ix 1][iy 1]); // Bilinear clrB=(byte)((1.0-fx)*(1.0-fy)*(double)nclr1 (fx)*(1.0-fy)*(double)nclr2 (1.0-fx)* (fy)*(double)nclr3 (fx)* (fy)*(double)nclr4); NBmp->Canvas->Pixels[i][j] = (TColor)RGB(clrR,clrG,clrB); //p1[i][j]=(TColor)RGB(clrR,clrG,clrB); } } Bmp->Width=newW; Bmp->Height=newH; Image2->Picture->Assign(NBmp); Label2->Caption="完 成 速 度 " (IntToStr(timeGetTime()-BTime) " msec."); delete NBmp;感謝指引!< >< > **我很想學,但又很不懂,所以一直問蠢問題,希望不要不屑我的問題,嘻嘻嘻** |
arisaka_matsuri
高階會員 發表:25 回覆:205 積分:231 註冊:2003-10-19 發送簡訊給我 |
dean 你好:
引言:我想,紅字部分應該就是原因~因為 href="http://delphi.ktop.com.tw/topic.php?TOPIC_ID=49370">http://delphi.ktop.com.tw/topic.php?TOPIC_ID=49370for(j = 1 ; j < newH-1 ; j ) { ptr_up=(Byte *)Bmp->ScanLine[j-1]; ptr_mid=(Byte *)Bmp->ScanLine[j]; ptr_down=(Byte *)Bmp->ScanLine[j 1]; for(i =1 ; i < newW-1 ; i ) { x = dX*(double)i; y = dY*(double)j; .... nclr3 = (ptr_mid)[i*2*3 2]; //GetRValue(Bmp->Canvas->Pixels[ix][iy 1]); .... |
dean
一般會員 發表:24 回覆:60 積分:21 註冊:2003-08-23 發送簡訊給我 |
感謝arisaka_matsuri:
您好!小弟看董您的建議之後,嘗試去更改程式,但仍是不對的結果。
w = Bmp->Width; h = Bmp->Height; newW = 400;//StrToInt(Edit1->Text); newH = 400;//StrToInt(Edit2->Text); NBmp->Width = newW; NBmp->Height = newH; /* Caculate the step size of movement */ dX = (double)w/(double)newW; dY = (double)h/(double)newH; int org=1; Byte *ptr_up, *ptr_mid, *ptr_down; for(j = 1 ; j < newH-1 ; j++) { ptr_up=(Byte *)Bmp->ScanLine[org-1]; ptr_mid=(Byte *)Bmp->ScanLine[org]; ptr_down=(Byte *)Bmp->ScanLine[org+1]; org+=dY; for(i =1 ; i < newW-1 ; i++) { x = dX*(double)i; y = dY*(double)j; ix = (int)x; iy = (int)y; fx = x - (float)ix; fy = y - (float)iy; nclr1 = (ptr_mid)[ix*3+2]; //GetRValue(Bmp->Canvas->Pixels[ix][iy]); nclr2 = (ptr_down)[ix*3+2]; //GetRValue(Bmp->Canvas->Pixels[ix+1][iy]); nclr3 = (ptr_mid)[(ix+1)*3+2]; //GetRValue(Bmp->Canvas->Pixels[ix][iy+1]); nclr4 = (ptr_down)[(ix+1)*3+2]; //GetRValue(Bmp->Canvas->Pixels[ix+1][iy+1]); // Bilinear clrR=(byte)((1.0-fx)*(1.0-fy)*(double)nclr1+(fx)*(1.0-fy)*(double)nclr2 +(1.0-fx)* (fy)*(double)nclr3+(fx)* (fy)*(double)nclr4); nclr1 = (ptr_mid)[ix*3+1]; //GetGValue(Bmp->Canvas->Pixels[ix][iy]); nclr2 = (ptr_down)[ix*3+1]; //GetGValue(Bmp->Canvas->Pixels[ix+1][iy]); nclr3 = (ptr_mid)[(ix+1)*3+1]; //GetGValue(Bmp->Canvas->Pixels[ix][iy+1]); nclr4 = (ptr_down)[(ix+1)*3+1]; //GetGValue(Bmp->Canvas->Pixels[ix+1][iy+1]); // Bilinear clrG=(byte)((1.0-fx)*(1.0-fy)*(double)nclr1+(fx)*(1.0-fy)*(double)nclr2 +(1.0-fx)* (fy)*(double)nclr3+(fx)* (fy)*(double)nclr4); nclr1 = (ptr_mid)[ix*3]; //GetBValue(Bmp->Canvas->Pixels[ix][iy]); nclr2 = (ptr_down)[ix*3]; //GetBValue(Bmp->Canvas->Pixels[ix+1][iy]); nclr3 = (ptr_mid)[(ix+1)*3]; //GetBValue(Bmp->Canvas->Pixels[ix][iy+1]); nclr4 = (ptr_down)[(ix+1)*3]; //GetBValue(Bmp->Canvas->Pixels[ix+1][iy+1]); // Bilinear clrB=(byte)((1.0-fx)*(1.0-fy)*(double)nclr1+(fx)*(1.0-fy)*(double)nclr2 +(1.0-fx)* (fy)*(double)nclr3+(fx)* (fy)*(double)nclr4); NBmp->Canvas->Pixels[i][j] = (TColor)RGB(clrR,clrG,clrB); //p1[i][j]=(TColor)RGB(clrR,clrG,clrB); if (org>Bmp->Height) exit; } }上述的程式結果產生原圖下半部的並沒有內插而得到,且內插出來的效果似乎不好!兩張圖片分別是用版主的原始程式,但處理時間很長,另一張是小弟改寫為SCANLINE的,處理時間較短,但效果很差,而且原圖下半部的並沒有內插而得到。 **我很想學,但又很不懂,所以一直問蠢問題,希望不要不屑我的問題,嘻嘻嘻** |
dean
一般會員 發表:24 回覆:60 積分:21 註冊:2003-08-23 發送簡訊給我 |
引言: dean 你好:**我很想學,但又很不懂,所以一直問蠢問題,希望不要不屑我的問題,嘻嘻嘻**引言:我想,紅字部分應該就是原因~因為 href="http://delphi.ktop.com.tw/topic.php?TOPIC_ID=49370">http://delphi.ktop.com.tw/topic.php?TOPIC_ID=49370 請問一下,小弟參考您的程式,發覺差很多,但卻有點看不懂您的寫法,請問可否給小弟指點一下?關於小弟的程式若要修改應該要怎麼修改?謝謝您for(j = 1 ; j < newH-1 ; j ) { ptr_up=(Byte *)Bmp->ScanLine[j-1]; ptr_mid=(Byte *)Bmp->ScanLine[j]; ptr_down=(Byte *)Bmp->ScanLine[j 1]; .... |
arisaka_matsuri
高階會員 發表:25 回覆:205 積分:231 註冊:2003-10-19 發送簡訊給我 |
dean 你好:
我實測你改過的程式,可以正常執行沒問題,但是結果不可預期,因為 org += dY; 這個敘述有問題。只要dY有小數點,在相加後 org 會捨棄小數的部分,這就是問題所在。不妨trace看看,會發現 org 不如你想像中那樣,「自動」對應到正確的列。
我用的原理是一樣的,只不過是按照公式直接轉成程式。符號定義如下圖
圖中的黑點代表原始影像(F)的像素,(l,k)為其座標;同樣的,灰點代表改變尺寸後的影像(G)像素,(c,r)代表其座標。而(x,y)則是(c,r)座標系對應到(l,k)座標系中的座標點,要注意的是l,k,c,r都是正整數,x,y則為實數。可以導出(c,r)對應到(l,k)的算式為
x = c / G 的寬 / F 的寬 y = r / G 的高 / F 的高 -- (1)而又知 Bilinear 轉換公式為 F(x,y) = F(c,r) = (1-dx) * (1-dy) * G(l,k) + dx * (1-dy) * G(l+1,k) + (1-dx) * dy * G(l,k+1) + dx * dy * G(l+1,k+1) 整理得 F(x,y) = F(c,r) = G(l,k) + (G(l+1,k) - G(l,k)) * dx + (G(l,k+1) - G(l,k)) * dy + (G(l,k) - G(l+1,k+1) - G(l+1,k) - G(l,k+1))) * dx * dy 可以看成是 F(x,y) = F(c,r) = c1 + c2 * dx + c3 * dy + c4 * dx * dy -- (2)就是這麼來的~ 我們知道算出( class="code"> void __fastcall ImageResize_Bilinear(Graphics::TBitmap *pRefBitmap, Graphics::TBitmap *pDestBitmap) { double XRatio = (double)pDestBitmap->Width / (double)pRefBitmap->Width; //---- (1) double YRatio = (double)pDestBitmap->Height / (double)pRefBitmap->Height; //---- (1) double dx, dy; // (x,y) 分別與 (l,k) 距離 int c1, c2, c3, c4; // Bilinear Eq.: f = c1 + c2*x + c3*y + c4*x*y int k, l; // (l,k) 代表 pRefBitmap 像素的位置(x,y) int r, c; // (c,r) 代表 pDestBitmap 像素的位置(x,y) double y, x; // (x,y) 代表 pDestBitmap(c,r) 對應到 pRefBitmap 中的位置 // 準備指向pRefBitmap像素記憶體的指標 ---- (4) Byte **pRef = new Byte *[pRefBitmap->Height]; for(k = 0; k < pRefBitmap->Height; k++) pRef[k] = (Byte *)pRefBitmap->ScanLine[k]; // bilinear 內差 Byte *pDest; for(r = 0; r < pDestBitmap->Height; r++) { pDest = (Byte *)pDestBitmap->ScanLine[r]; for(c = 0; c < pDestBitmap->Width; c++) { if(XRatio < 1) x = (double)c / XRatio + XRatio; // 新修正 else x = (double)c / XRatio; //---- (1) if(YRatio < 1) y = (double)r / YRatio + YRatio; // 新修正 else y = (double)r / YRatio; //---- (1) l = Floor(x); //---- (3) k = Floor(y); //---- (3) dx = x - (double)l; dy = y - (double)k; // 分別對BGR三色計算 for(int b = 0; b < 3; b++) { c1 = pRef[k][l*3+b]; if(l == pRefBitmap->Width - 1) //---- (4) c2 = 0; else c2 = pRef[k][(l+1)*3+b] - pRef[k][l*3+b]; if(k == pRefBitmap->Height - 1) c3 = 0; else c3 = pRef[k+1][l*3+b] - pRef[k][l*3+b]; if(l == pRefBitmap->Width - 1 || k == pRefBitmap->Height - 1) c4 = 0; else c4 = pRef[k][l*3+b] + pRef[k+1][(l+1)*3+b] - pRef[k][(l+1)*3+b] - pRef[k+1][l*3+b]; pDest[c*3+b] = (Byte)(c1 + c2 * dx + c3 * dy + c4 * dx * dy); //---- (2) } } } delete [] pRef; } 以上的回答,希望你滿意 發表人 - |
JerryKuo
版主 發表:42 回覆:571 積分:322 註冊:2003-03-10 發送簡訊給我 |
各位好: billinear內插法使用於影像縮放會有不連續的問題,如果想要讓縮小後的圖片
更有平滑感,建議你們可以加上prediction原理,參考之前的像素,做一個平均
值,考慮到處理速度,以下有幾個做法,參考看看 假設我們要算(x,y)這個點,可用之前已知四點像素值
左上(x-1,y-1),
上方(x, y-1),
右上(x 1,y-1),
左邊(x-1,y)
預測出(x,y)的像素值。 如何預測?
1.最簡單的方法,取平均值avg,當我們用內插法求得(x,y)實際的像素值clr時,
將avg和clr再取平均得realclr,(x,y)的像素值就是realclr。
2.第二個方法,當我們用內插法求得(x,y)實際的像素值clr時,再將clr和已知
四點像素值分別比對,取得和clr最相似的那個像素值clr',再取平均得realclr
就是(x,y)的像素值。 以上是小弟對"內插法使用於縮放影像"的改進方法,參考看看。 ^^
|
dean
一般會員 發表:24 回覆:60 積分:21 註冊:2003-08-23 發送簡訊給我 |
兩位前輩們好:
小弟更改了程式,而程式則是融合JERRYKUO與arisaka_matsuri兩位大哥的程式,下面是程式片段,而小弟也斗膽將兩位大哥的程式拿出比較,請勿見怪!請見圖!
void __fastcall TForm1::Button12Click(TObject *Sender) { DWORD BTime; BTime=timeGetTime(); //測試時間 Graphics::TBitmap *Bmp = new Graphics::TBitmap(); Bmp->Assign(Image2->Picture->Bitmap); Graphics::TBitmap *NBmp = new Graphics::TBitmap(); NBmp->PixelFormat=pf24bit; int w,h,newW,newH; double dX,dY,x,y; int i,j; int ix,iy; // integer value of (x,y) double fx,fy; // float value of (x,y) unsigned char clr, clrR,clrG,clrB, nclr1,nclr2,nclr3,nclr4; // color of neighbor 4 pixel w = Bmp->Width; h = Bmp->Height; newW = 50;//StrToInt(Edit1->Text); newH = 50;//StrToInt(Edit2->Text); if((newW <=0) ||(newH <=0)) { ShowMessage("Invalided parameter"); return; } NBmp->Width = newW; NBmp->Height = newH; /* Caculate the step size of movement */ dX = (double)newW/(double)w; dY = (double)newH/(double)h; Byte **pRef = new Byte *[Bmp->Height]; for(int k = 0; k < Bmp->Height; k ) pRef[k] = (Byte *)Bmp->ScanLine[k]; Byte *ptr; for(j = 0 ; j < newH ; j ) { ptr=(Byte *)NBmp->ScanLine[j]; for(i =0 ; i < newW ; i ) { if (dX<1) x=(double)i/dX dX; else x=(double)i/dX; if (dY<1) y=(double)j/dY dY; else y=(double)j/dY; /*x = dX*(double)i; y = dY*(double)j; */ ix = (int)x; iy = (int)y; fx = x - (float)ix; fy = y - (float)iy; nclr1 = pRef[iy][ix*3 2]; nclr2 = pRef[iy 1][ix*3 2]; nclr3 = pRef[iy][(ix 1)*3 2]; nclr4 = pRef[iy 1][(ix 1)*3 2]; // Bilinear //ptr[i*3 2] = (Byte)(nclr1 nclr2 * fx nclr3 * fy nclr4 * fx * fy); //---- (2) clrR=(byte)((1.0-fx)*(1.0-fy)*(double)nclr1 (fx)*(1.0-fy)*(double)nclr2 (1.0-fx)* (fy)*(double)nclr3 (fx)* (fy)*(double)nclr4); nclr1 = pRef[iy][ix*3 1]; nclr2 = pRef[iy 1][ix*3 1]; nclr3 = pRef[iy][(ix 1)*3 1]; nclr4 = pRef[iy 1][(ix 1)*3 1]; // Bilinear //ptr[i*3 1] = (Byte)(nclr1 nclr2 * fx nclr3 * fy nclr4 * fx * fy); clrG=(byte)((1.0-fx)*(1.0-fy)*(double)nclr1 (fx)*(1.0-fy)*(double)nclr2 (1.0-fx)* (fy)*(double)nclr3 (fx)* (fy)*(double)nclr4); nclr1 = pRef[iy][ix*3]; nclr2 = pRef[iy 1][ix*3]; nclr3 = pRef[iy][(ix 1)*3]; nclr4 = pRef[iy 1][(ix 1)*3]; // Bilinear //ptr[i*3] = (Byte)(nclr1 nclr2 * fx nclr3 * fy nclr4 * fx * fy); clrB=(byte)((1.0-fx)*(1.0-fy)*(double)nclr1 (fx)*(1.0-fy)*(double)nclr2 (1.0-fx)* (fy)*(double)nclr3 (fx)* (fy)*(double)nclr4); ptr[i*3]=clrB; ptr[i*3 1]=clrG; ptr[i*3 2]=clrR; //NBmp->Canvas->Pixels[i][j] = (TColor)RGB(clrR,clrG,clrB); } } Bmp->Width=newW; Bmp->Height=newH; Image2->Picture->Assign(NBmp); Label2->Caption="完 成 速 度 " (IntToStr(timeGetTime()-BTime) " msec."); delete NBmp;裡頭有不好的地方請兩位大哥前輩給小弟指引,謝謝! **我很想學,但又很不懂,所以一直問蠢問題,希望不要不屑我的問題,嘻嘻嘻** |
dean
一般會員 發表:24 回覆:60 積分:21 註冊:2003-08-23 發送簡訊給我 |
引言: 小弟也斗膽將兩位大哥的程式拿出比較,請勿見怪!請見圖! 謝謝!解釋一下: JERRYKRU版主用的是CANVAS所以比較慢,改為SCANLINE之後應該與arisaka_matsuri一樣快! 但另小弟真正好奇與有疑問的是,為什麼WINDOWS API提供的COPYRECT竟然收縮效果那麼好,仔細看各位前輩會發現她連密密麻麻的文字都還在,但其他三張縮小後的圖卻已經不見了!!!在速度上,COPYRECT也沒有慢許多,應該也在容許範圍內,但既然COPYRECT那麼好,那為什麼還要有其他的呢?COPYRECT又是用什麼方式去做的? 許多問題,不好意思,因為都是做BILINEAR後發現的!感謝各位前輩給予小弟指引!謝謝 **我很想學,但又很不懂,所以一直問蠢問題,希望不要不屑我的問題,嘻嘻嘻** |
arisaka_matsuri
高階會員 發表:25 回覆:205 積分:231 註冊:2003-10-19 發送簡訊給我 |
dean 你好:
引言: JERRYKRU版主用的是CANVAS所以比較慢,改為SCANLINE之後應該與arisaka_matsuri一樣快! ...COPYRECT又是用什麼方式去做的? 許多問題,不好意思,因為都是做BILINEAR後發現的!感謝各位前輩給予小弟指引!謝謝先說明計算速度的量測,用timeGetTime()的精確度有限,建議改用QueryPerformanceCounter()。 COPYRECT?被你這麼一提,讓我不禁好奇起來。看完TCanvas::CopyRect()的原始碼,其實就是呼叫StretchBlt()這個WinAPI。不過裡面在賣啥膏藥,得問M$了。我比較了PhotoShop跟Matlab處理bilinear縮小尺寸的結果,並不相同。這就說明同樣用「bilinear」,但是實做的內容還是有不同的地方。我也在IEEE上找了一些paper和其他相關的網頁資料,說明實做上有許多技巧,像是以low pass filter處理再取樣、利用wavelet等等。小弟學的也不多,恐怕無法給予更深入的解答了。如果有那位大大願意分享或提個範例,當然更棒了! |
dean
一般會員 發表:24 回覆:60 積分:21 註冊:2003-08-23 發送簡訊給我 |
引言: 先說明計算速度的量測,用timeGetTime()的精確度有限,建議改用QueryPerformanceCounter()。 COPYRECT?被你這麼一提,讓我不禁好奇起來。看完TCanvas::CopyRect()的原 始碼,其實就是呼叫StretchBlt()這個WinAPI。不過裡面在賣啥膏藥,得問 M$了。我比較了PhotoShop跟Matlab處理bilinear縮小尺寸的結果,並不相同。 這就說明同樣用「bilinear」,但是實做的內容還是有不同的地方。我也在IEEE 上找了一些paper和其他相關的網頁資料,說明實做上有許多技巧,像是以low pass filter處理再取樣、利用wavelet等等。小弟學的也不多,恐怕無法給予更 深入的解答了。如果有那位大大願意分享或提個範例,當然更棒了! 發表人 - jerrykuo 於 2004/05/11 16:02:01arisaka_matsuri大哥您好: 相當感謝您不斷的指引小弟學習,小弟在這邊在次感謝!另外也感謝JerryKuo所提供的範例與改進方法! 在測試的結果,小弟決定使用COPYRECT,他的效果以肉眼來觀看比較好,雖然在論文上沒有辦法解釋如何實作! 如果有哪位大大願意解釋讓我們更清楚COPYRECT,那就太感激了! arisaka_matsuri大哥真的謝謝你,讓我這方面獲益良多! **我很想學,但又很不懂,所以一直問蠢問題,希望不要不屑我的問題,嘻嘻嘻** |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |