全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:5372
推到 Plurk!
推到 Facebook!

如何讓放大縮小品質不錯

答題得分者是:daldal
linly
一般會員


發表:42
回覆:37
積分:15
註冊:2007-10-07

發送簡訊給我
#1 引用回覆 回覆 發表時間:2008-04-21 12:40:13 IP:218.168.xxx.xxx 訂閱
您好:

我一開始先從其他的程式模組取得圖片(1240x1754 RGB) 的 row data (in memory),接著將這張圖片的 row dara 利用內插法處理成 827x1169 的內容( 寬高的數據僅供參考)。

[code cpp]

void Interpolation( unsigned char* source, unsigned char* dest, int i_width, int i_height, int o_width, int o_height );

[/code]

然後再把這些資料利用 mommove 的方式一列一列的複製到 TImage::Pictrure::Bitmap 的元件中來呈現。所以我處理的重點就是 "內插法"、"Image 元件呈現"...etc。

接下來就是我想請教各位有經驗的板大的部分:我想在程式中製作放大縮小的功能,若執行這個功能會有兩頁(張)須處理。

嘗試簡單的方式:
1. 改變 TImage::Width、TImage::Height,不好。
2. 利用 TImage::Picture::Bitmap::Canvas::StrectchDraw 重繪,放大在縮小、或者縮小再放大,失真度明顯。

如果這裡用內插法去處理放大縮小的功能,因為我是用 TImage 元件呈現,所以需要考慮如何將"內插法配合ScanLine",搜尋板上文章似乎這在實作上有點麻煩,而且容易出錯(考慮相鄰兩列之類的問題);

如果說我先把 Image::Picture::Bitmap 一列一列利用 mommove 先複製出來放在 unsigned char* 的陣列,然後利用我文章一開始的那個內插法處理後,再複製回來 Image::Picture::Bitmap,這樣速度有點小慢。

小弟還有待磨練,以上描述若有不清楚之處,還請告知,這裡先謝謝各位寶貴的意見

編輯記錄
linly 重新編輯於 2008-04-21 12:41:11, 註解 無‧
brook
資深會員


發表:57
回覆:323
積分:371
註冊:2002-07-12

發送簡訊給我
#2 引用回覆 回覆 發表時間:2008-04-24 08:10:08 IP:118.168.xxx.xxx 訂閱
我之前用過CopyRect,不知合和合用.
linly
一般會員


發表:42
回覆:37
積分:15
註冊:2007-10-07

發送簡訊給我
#3 引用回覆 回覆 發表時間:2008-04-29 16:37:01 IP:140.113.xxx.xxx 訂閱
我剛剛試了一下,拿一張都是文字的 .bmp 測試,然後利用 CopyRect 把內容縮小成原先的 1/4,程式碼如下:

[code cpp]
Graphics::TBitmap *pBMP = new Graphics::TBitmap();
pBMP->LoadFromFile("1.bmp");

TRect rectSource = TRect(0,0,pBMP->Width-1,pBMP->Height-1);

this->Image1->Width = WIDTH/2;
this->Image1->Height = HEIGHT/2;
this->Image1->Left = (this->ClientWidth - this->Image1->Width)>>1;
this->Image1->Top = 0;
this->Image1->Stretch = true;
this->Image1->Canvas->CopyMode = cmSrcCopy;
this->Image1->Canvas->CopyRect(TRect(0,0,this->Image1->Width-1,this->Image1->Height-1), pBMP->Canvas,
rectSource);

delete pBMP;

[/code]

視覺感官上,文字都變成粗體,怎麼會這樣XD

連結是圖片片段,還請指教 謝謝 ^_^

處理前: http://www.flickr.com/photos/23700932@N07/2451701046/
處理後: http://www.flickr.com/photos/23700932@N07/2451701168/




===================引 用 brook 文 章===================
我之前用過CopyRect,不知合和合用.
編輯記錄
linly 重新編輯於 2008-04-30 13:15:12, 註解 無‧
linly
一般會員


發表:42
回覆:37
積分:15
註冊:2007-10-07

發送簡訊給我
#4 引用回覆 回覆 發表時間:2008-04-30 13:14:25 IP:140.113.xxx.xxx 訂閱
解決方式:利用 StretchBlt,不過還是希望能有強者可以解釋一下上一篇的原因為何,謝謝!!

[code cpp]
...
...
::SetStretchBltMode(this->Image1->Canvas->Handle,HALFTONE);
::StretchBlt(this->Image1->Canvas->Handle,0,0,this->Image1->Width,this->Image1->Height,pBMP->Canvas->Handle,0,0,pBMP->Width,pBMP->Height,SRCCOPY);
// this->Image1->Canvas->CopyMode = cmSrcCopy;
// this->Image1->Canvas->CopyRect(TRect(0,0,this->Image1->Width-1,this->Image1->Height-1), pBMP->Canvas, rectDisplay);

[/code]
daldal
高階會員


發表:6
回覆:102
積分:226
註冊:2007-06-18

發送簡訊給我
#5 引用回覆 回覆 發表時間:2008-04-30 18:30:44 IP:220.130.xxx.xxx 未訂閱
1.結果不同是因為你多了這一行,不然CopyRect跟StretchBlt結果是相同的 
(詳細內容可以看source code, CopyRect就是使用StretchBlt畫出來的)
[code cpp]
SetStretchBltMode(this->Image1->Canvas->Handle,HALFTONE);
[/code]

2.其實就TImage的draw function來看的話, 他也是使用StretchBlt來顯示
(依照不同格式會使用HALFONE or STRETCH_DELETESCANS ...)
至於Bitmap畫出來到Image的做法也就是使用CopyRect
所以你程式碼的動作
[code cpp]
SetStretchBltMode(this->Image1->Canvas->Handle,HALFTONE);
this->Image1->Canvas->CopyRect(TRect(0,0,this->Image1->Width-1,this->Image1->Height-1),pBMP->Canvas,rectSource);
[/code]
會等同於
[code cpp]
this->Image1->Picture->Bitmap->Assign(pBMP);
[/code]
只是圖片一個存放在pBMP, 一個放在Image裡的Bitmap
若是你不想要多一次(Assign)複製的話,
就直接使用Image->Picture->Bitmap->LoadFromFile即可
linly
一般會員


發表:42
回覆:37
積分:15
註冊:2007-10-07

發送簡訊給我
#6 引用回覆 回覆 發表時間:2008-04-30 18:48:03 IP:140.113.xxx.xxx 訂閱
首先,謝謝 daldal 的回覆,不過真的會等同於 Assign 嗎!? ( 是不是還有甚麼屬性需要設定 )

因為我要做縮放的動作,直接用 Assign 的話,只會複製到一部分的內容( 根據我的程式碼敘述則為左上方區塊 )

如果去設定 Stretch 那效果就不好了。

另外照你所描述的,TImage 元件把 StretchBlt 的模式給限制住了,變成它自己決定使用何種 mode,有點不方便。

最後,我把分數給你囉... 不好意思前一位回我的版友
編輯記錄
linly 重新編輯於 2008-04-30 18:50:02, 註解 無‧
daldal
高階會員


發表:6
回覆:102
積分:226
註冊:2007-06-18

發送簡訊給我
#7 引用回覆 回覆 發表時間:2008-04-30 19:11:56 IP:220.130.xxx.xxx 未訂閱
1.若是在Bitmap內容縮放顯示到Image顯示圖層的話
在條件BITSPIXEL(一個pixel多少bits)*PLANES(多少圖層,ex rgb=3) <=8
< DIB原始資料的bmBitsPixel*bmPlanes
兩者都符合才會使用HALFTONE模式
我用Assign只是複製到Bitmap讓他使用Image顯示,測試結果是不是相同而已

2.若是要自己決定使用何種Mode, 那就如同之前您所打的程式碼
用手工設定SetStretchMode CopyRect,來達到你的需求
不然就是自己改寫Image元件,全部照抄,只要把Draw部分的Function
改成手動去設定StretchMode,而非自行判斷

===================引 用 linly 文 章===================
首先,謝謝 daldal 的回覆,不過真的會等同於 Assign 嗎!? ( 是不是還有甚麼屬性需要設定 )
因為我要做縮放的動作,直接用 Assign 的話,只會複製到一部分的內容( 根據我的程式碼敘述則為左上方區塊 )
如果去設定 Stretch 那效果就不好了。
另外照你所描述的,TImage 元件把 StretchBlt 的模式給限制住了,變成它自己決定使用何種 mode,有點不方便。
最後,我把分數給你囉... 不好意思前一位回我的版友
編輯記錄
daldal 重新編輯於 2008-04-30 19:12:39, 註解 無‧
linly
一般會員


發表:42
回覆:37
積分:15
註冊:2007-10-07

發送簡訊給我
#8 引用回覆 回覆 發表時間:2008-04-30 20:28:53 IP:218.168.xxx.xxx 訂閱
Thanks again. :-)
daldal
高階會員


發表:6
回覆:102
積分:226
註冊:2007-06-18

發送簡訊給我
#9 引用回覆 回覆 發表時間:2008-05-01 09:59:34 IP:220.130.xxx.xxx 未訂閱
dear linly,

不好意思,可否請教一下
第一篇中提到的內插函式


[code cpp]
void Interpolation( unsigned char* source, unsigned char* dest, int i_width, int i_height, int o_width, int o_height );
[/code]

執行的內插法放大縮小,大概會花多久時間(ms)?
(整數倍以及非整數倍的縮放)
看您之前提到速度有點小慢,所以有點好奇處理的速度
編輯記錄
daldal 重新編輯於 2008-05-01 10:00:12, 註解 無‧
linly
一般會員


發表:42
回覆:37
積分:15
註冊:2007-10-07

發送簡訊給我
#10 引用回覆 回覆 發表時間:2008-05-01 12:05:17 IP:140.113.xxx.xxx 訂閱
我採用的是 bilinear 的方式,測試了一下時間

[code cpp]
請在此區域輸入程式碼
#include
#include
using namespace std;
...
...
clock_t start, end;

start = clock();
Reduce( pSource, pInterpolation, i_width, i_height, o_width, o_height, 3, 1 ) // 後面的 3 = RGB, 1 = bilinear,給使用者自訂
end = clock();

double total_time =
(end-start)/CLK_TCk);

ofstream outfile("time.txt");
outfile << "The time was : " << total_time;
outfile.close();

[/code]

上述單單做內插法的結果為:The time was: 0.718 s ( Source 為 1240 x 1754;內插後 827 x 1169 )

由於我是使用 Image 元件,所以內插法處理完後,還要做 memmove 的方式,一列一列的複製到 TImage::Picture::Bitmap 的 ScanLine 中。所以說,依照我的處理方式,如果我要做放大縮小,我就需要先把資料從Timage 元件搬動到一塊記憶空間,然後做內插法,然後在複製回 Image 元件中,每次放大縮小都有兩張需要處理(需求)。這樣看來 StretchBlt 的函式介面比較符合我實作方式的需要與便利。

也許有更好的方式,不過我目前只想到這樣的方式 ^_^

P.S.:Pentium 4 CPU 3.00 GHz,1 GB RAM
daldal
高階會員


發表:6
回覆:102
積分:226
註冊:2007-06-18

發送簡訊給我
#11 引用回覆 回覆 發表時間:2008-05-01 16:44:48 IP:220.130.xxx.xxx 未訂閱
謝謝, 以這速度我大概也pass過去吧@@
linly
一般會員


發表:42
回覆:37
積分:15
註冊:2007-10-07

發送簡訊給我
#12 引用回覆 回覆 發表時間:2008-05-01 21:45:56 IP:218.168.xxx.xxx 訂閱
Sorry!! 時間應該是..... The time was : 0.281 

中斷點下錯,所以 0.7 秒多包含一些我按 F8 debug 的時間XDDD



===================引 用 daldal 文 章===================
謝謝, 以這速度我大概也pass過去吧@@
perrychu
一般會員


發表:0
回覆:1
積分:0
註冊:2004-06-13

發送簡訊給我
#13 引用回覆 回覆 發表時間:2008-08-28 00:37:47 IP:218.175.xxx.xxx 訂閱
曾看過日本一篇圖面處理分享, 內容摘要如下: 若要放大圖面. 採用Bi-Linear 內插法會有不錯的效果.

若要縮小圖面. 則使用積分法(面積平圴法) 則較理想.不宜使用內插法. 若大家對這有興趣的話. 可至以下網站去下載demo 及 tool

http://www.asahi-net.or.jp/~HA3T-NKMR/DGS/DownLoad.htm

DHGL 1.2 下載解壓後. 有一目錄 common, 裏有一 BitmapUtils. 這就是圖面縮小. 放大的程式. 最主要有3個功能: enlarge(純放大). shrink(純縮小). stretch(可放大或縮小), 這3個功能都是使用 scanline 及快取功能(使用記憶體). 執行速度很快...

若要使用demo的話. 可把 common 加入 Environment 的 library. 然後去找第4章第5節的sample . 若想提昇圖面處理技術. 一定要去下載.

工具程式內都有註解. 但都是日文. 若本身電腦無法看日文. 則會顯示 ? 或亂碼. 但. 不會影響執行...
系統時間:2024-04-20 4:19:01
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!