作者tropical72 (藍影)
看板C_and_CPP
標題Re: [問題]關於影像二值化??
時間Thu Oct 6 01:53:31 2011
※ 引述《goodrain (mr.fu)》之銘言:
: ※ 引述《kiyasuto1 (kiy)》之銘言:
: : 各位前輩好!!小弟是用BCB作的二值化,寫了個副程式,
: : 想用圖的所有像素灰階值相加除以總像素數目來作門檻!
: : (門檻=所有像素灰階值相加/總像素數目)
: : 程式碼如下
: : void tw(Byte **a)
: : {
: : int Bsum;
: : float Background;
: : for(int i = 0; i < ImgWidth; i++)
: : {
: : for(int j = 0; j < ImgHeight; j++)
: : {
: : Background=(Bsum+=a[i][j])/((ImgHeight)*(ImgWidth));
: : }
: : }
其實 kiyasuto1 這段最後結果,Background 和
goodrain 的 Background 結果是一樣的。
先看一下下面這段程式碼
#include <stdio.h>
int main()
{
int a=1, b=5, c=2, d=0;
printf("a=%d, b=%d, c=%d, d=%d\n", a, b, c, d);
d = (a+=b)/c;
printf("a=%d, b=%d, c=%d, d=%d\n", a, b, c, d);
return 0;
}
實際上 d=(a+=b) / c ; 它是分解成
a=a+b;
d=a/c;
兩個步驟寫成一行而已, 輸出結果會是
a=1, b=5, c=2, d=0
a=6, b=5, c=2, d=3
於是 kiyasuto1 的這行
Background=(Bsum+=a[i][j])/((ImgHeight)*(ImgWidth));
也就只相等於下面這兩行而已
Bsum+= a[i][j];
Background = Bsum / ((ImgHeight)*(ImgWidth)) ;
整段看下來的話,除了做了沒必要的除法運算外,和 goodrain 的結果其實是一樣的。
意思是,「以最小修改」為目的的話,原原原 po(kiyasuto1) 程式碼只要改這樣即可
for(int i = 0; i < ImgWidth; i++)
{
for(int j = 0; j < ImgHeight; j++)
{
Background=
(float)(Bsum+=a[i][j])/((ImgHeight)*(ImgWidth));
}
}
只是這樣的確效率不太好,因要算平均的話,其實只要在算完總合時再除以點數即可,
所以loop 裡不必放除法,只要做加法動作即可,於是一般就像 goodrain 之作法。
: 這一段改成
: for(int i = 0; i < ImgWidth; i++)
: {
: for(int j = 0; j < ImgHeight; j++)
: {
: Bsum+=a[i][j];
: }
: }
: Background= (float)Bsum /(ImgHeight)*(ImgWidth);
以下恕刪。
Background 可以用 float 或 double 都沒問題,
但 Bsum 不建議用 float , 「至少」用 double,可以試試下面這個程式
#include <stdio.h>
int main()
{
float f=1.23456789E9f;
double d=1.23456789E9;
unsigned u=123456789;
printf("f=%.16e\nd=%.16e\nu=%u\n", f, d, u);
f=f+1.0f, d=d+1.0, u=u+1;
printf("f=%.16e\nd=%.16e\nu=%u\n", f, d, u);
return 0;
}
上面加 1 有影響的,只有 d 和 u 而已,這是因浮點數機制問題,
有興趣的話該去 K IEEE754 spec , 及浮點數 + - * / 大概是怎麼做的。
---
另,我有個嚴重的疑惑,system 若含 FPU ,其實 double 速度都比 float 快,
精度也比 float 高,為何還堅持要用 float ?
是因一些顯卡裡之 FPU 用 float 較快嗎?
--
No matter how gifted you are,
alone, can not change the world.
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.78.41
推 ericinttu:第一行的 "他" 與 "你",可以改用PTT id來表示. 10/06 02:06
已修改, 謝謝意見 *^_^*
→ ericinttu:Backgroun 少個d 10/06 02:06
推 ericinttu:很久以前有看到一篇文章說BCB的float都會轉成double去運 10/06 02:08
→ ericinttu:算. 不知道可不可信就是了. (我個人是因此而不用float) 10/06 02:09
推 ericinttu:要用double佔全線,還是float佔半線,跟CPU有很大的關連. 10/06 02:13
→ tropical72:多 compiler 應都有偷換動作..10/06 02:13
→
ericinttu:我計組忘光光,留給高手回答好了. (退後十大步 XD) 10/06 02:13
→ akasan:在x86 double/float 都轉80bit 後才運算 所以才會差不多快 10/06 02:13
→ akasan:在其他硬體架構下就會較為明顯的差距如你所提GPU 10/06 02:14
→ akasan:以printf 這個例子來看不太對...因為他會先轉成double 才傳10/06 02:15
→ tropical72:原來如此, 謝謝 akasan 補充。 10/06 02:14
→ tropical72:那 printf 有引數可顯示 float 嗎? 10/06 02:19
補齊。 另請教 akasan, 在該 code 裡
float f=1.0f;
while(1.0f+f!=1.0f) f/=2.0f;
以我系統裡,正常 f 為 1.192092896e-07F (FLT_EPSILON)時跳出 while loop
這樣就算 printf 出來也不該是 DBL_EPSILON , 所以才判斷有偷轉,
應可這麼解讀吧?
※ 編輯: tropical72 來自: 180.177.78.41 (10/06 02:32)
推 goodrain:沒有錯一模一樣的東西...我後來才發現原原po的邏輯xd 10/06 03:01
→ akasan:那段程式用double/float 透過 gcc -O2 -m32 出來幾乎一樣 10/06 03:02
→ akasan:注意一下code 用mmx or FPU 結果會有不一樣 10/06 03:07
→ tropical72:嗯, 看來和 compiler 特性與參數也有關係,謝謝指教!! 10/06 03:10
推 LPH66:printf 主要是變長參數的關係 float 會變成 double 10/06 06:23
→ LPH66:所以 printf 裡面接到的一定是 double 10/06 06:24