影像處理或其他多媒體處理中的值溢位處理
在網上查資料的時候,無意中連線到了“zyl910”的專欄,
看了裡面的一篇文章,感覺頗有收穫,就在此拋磚引玉一番。
原文見:http://blog.csdn.net/zyl910/archive/2006/10/11/1330614.aspx
<?xml:namespace prefix = o />
在用VB寫影像處理程式的時候,經常會遇到運算結果超出範圍的情況。
比如在處理32位點陣圖的時候,由於每一種顏色分量都是8位,它們的值就不能超出0-255的範圍。
否則,就會溢位到另一個顏色的分量裡去,或者是產生一個“負”的顏色值,前者破壞影像顯示效果,
後者將可能導致DIB崩潰。
其實只要在運算之後,輸出之前,加上兩句判斷就可以消除這種錯誤:
此處假定處理綠色分量:
if Green>255 then Green=255
if Green<0 then Green=0
當然,實際處理的時候,肯定不止一個點,因此這裡的Green也就會是一個陣列元素,外面套著N重迴圈了。
單單看這兩句,似乎也沒什麼不好。
可是這只是一個顏色分量而已,還有兩個顏色也得這麼處理:
if Red>255 then Red=255
if Red<0 then Red=0
if Blue>255 then Blue=255
if Blue<0 then Blue=0
而一個圖片少說也有好幾萬的象素吧,每一點象素處理完都得來這麼6句判斷。
N萬次的比較做下來,效率上的拖累可想而知。
而理想狀態的程式碼應該是型如 Out = Limitation(In) 的自洽方式,而不是醜陋的IF...THEN...
即用一個表示式來自然而然的得到“規範的,合乎要求”的資料。
首先,我這裡指的不是函式,用函式的話,我寧可用比較,因為函式更慢。
舉兩個例子:
例子一:
假設要寫一個很簡單的程式,介面上有一個CheckBox控制元件。
當使用者點選這個CheckBox的時候窗體背景變成黑色,反選這個CheckBox的時候窗體變成紅色。
讀者們,請先想一下,讓你寫這個程式,你會怎麼寫呢。
是否這樣寫呢:
Sub Check1_Click()
If Check1.value=1 then
Me.backColor=0
Else
Me.BackColor=VBred
endif
End Sub
或者是簡單點寫成一句:
If Check1.value=1 then Me.backColor=0 Else Me.BackColor=VBred
其實這兩句都是一樣的IF判斷語句,本質上沒有區別。
你有沒有想過這樣寫呢:
Sub Check1_Click()
Me.BackColor=Not(-Check1.Value) and VBRed
End Sub
這樣的寫法要比前面的優美多了。
首先,可能很多朋友不明白這個語句,其實在VB裡面,邏輯變數也是一個LONG型變數。
True=-1
False=0
你可以在寫True的地方寫-1也可以在該寫False的地方用0代替。
因為CheckBox控制元件它點和不點的值是1和0,只要加個負號,它就成了一個邏輯變數了。
Not(-Check1.Value):
如果你點選了CheckBox,Not(-Check1.Value)=>Not(-1)=>Not True=> False
如果你反選了CheckBox,Not(-Check1.Value)=>Not(0)=>Not False=>True
最後就是一個邏輯“與”運算了:True And Anything = Anything
而:False And Anything = False =0
於是,一個判斷語句就變成了一個簡單的賦值語句。
例子二:
很多程式需要用到全域性邏輯變數來標記某個狀態。
比如,在做文件處理,資料庫操作或者是其他可以由使用者儲存修改的程式(也包括影像處理程式)
如果使用者對資料進行了修改,這時退出程式的話,應該給使用者一個提示“是否要先儲存一下呀..."
否則,你的程式100%會被使用者強烈投訴,即使你其他功能做得再好也沒用。
恩,讀者們再動一下“腦白金”吧,如果要你實現這個功能,該如何寫?
想好了麼?
我來給你個建議吧:
建立一個全域性變數:
Dim Saved As Boolean
然後在窗體啟動中設定它為True
Sub Form_Load()
...
Saved=True
...
End Sub
為什麼?窗體還剛剛載入,當然不可能是“未儲存”咯。
然後在使用者更改內容的事件中,將這個變數設為:Saved=False
比如:
Sub Text1_Change()
Saved=False
End Sub
還有其他所有使用者修改資料的地方都加上這句。
然後在儲存資料的模組中將這個變數設為True
Sub SaveContent()
...
...
Saved=True '儲存完了,當然就是“已儲存”了咯
End Sub
最後呢,只要在窗體被解除安裝的事件中判斷是“未儲存”還是“已儲存”就可以了。
是這麼寫麼?
Sub Form_Unload(Cancel As Integer)
Dim I as Long
If Saved = False then
I = Msgbox("...要儲存麼...",,VBYESNOCANCEL) '隨手寫的,真有這個引數麼?
Select Case I
Case VBYes:SaveContent
Case VBNo:End
Case VBCancel:Cancel=1
End Select
endif
End sub
第二個例子繞了那麼大一個圈子,其實,只是想說:
If Saved = False then 為什麼就不能寫成 If Not Saved Then 呢?
這樣寫不但VB語句優美,而且幾乎連英語語法都要通順了。
這個例子我想說明的其實是邏輯表示式的值並非一定要用=,<,>這些等式符號才能表達出來的。
好了,最後來說說我們開頭的那個話題吧。
什麼?你已經忘記了?那太好了,請從頭再看一遍。
由於我對邏輯運算不大感冒,因此雖然覺得那兩個醜陋If...Then...
“或許”可以用一個“優美的”邏輯運算表示式來一次完成,但是一直都沒有仔細的研究和嘗試。
直到我看到“zyl910”的那篇文章,才重新提起了這個念頭來:“哦,原來真的是可以的哦”
仔細看了半天,似乎有點理解了,但是閉上眼睛又忘記了,邏輯運算真是挺搞得哦。
所以就索性拋開文章,直接拿張白紙來推導了。
其實,最基本的原理已經在我舉的第一個例子中說明了,即:
True=-1
False=0
既可以參加數學運算又可以參加邏輯運算的超級運動員!
由於我的邏輯運算不熟練,我採用的是反推的方法來得到表示式:
先從if Green<0 then Green=0開始。
如果小於0則等於0
大家知道邏輯運算的結果要麼是True要麼是False(-1和0)
並且True And Anything = Anything '結論1 (And 運算)
;False And Anything = False =0
這裡Anything則是可以做文章的地方了,因為我們最後要得到的是0,N,255這3個分段值。
上面這兩個運算就必定是關鍵,因為當0<N<255時我們需要得到的是N本身的值,而結論1
可以得到這樣的結果,我們一定要牢記。
判斷N<0 這個表示式,當N小於0的時候,N<0=True=-1
當N大於等於0的時候,N<0=False=0
代入結論1,
(N<0) And N
當N小於0的時候
(N<0) And N => True And N => N
當N大於0的時候
(N<0) And N => False And N => 0
咦,怎麼反過來了?
那也簡單,把條件改一下吧,反過來判斷N>0
當N小於等於0的時候,N>0=False=0
當N大於0的時候, N>0=True=-1
再代入結論1:
(N>0) And N
當N小於等於0的時候
(N>0) And N => False And N => 0
當N大於0的時候
(N>0) And N => True And N => N
正確.完全合乎我們的要求!
等等,別急著開香檳啊,才做了一小半啊,還有一大半沒做呢。
接下來我們來分析第二個判斷語句
if Green>255 then Green=255
唉,看到255這個數字,實在是想親上一口。倒不是我有什麼特殊愛好,而是因為255正好是十六進位制裡的FF
而十六進位制的FF,就是二進位制裡的11111111,這是個很奇妙的數字。
任何一個0-255範圍內的整數和它進行“與”運算,都會得到原來的數,也就是等於沒有運算。
什麼?你說我在忽悠你?什麼叫做“等於沒有運算”?
別忘記我們要做的事,是把一個分支判斷語句放到一個表示式裡面,
在這裡“等於沒有運算”=“得到原來的值”
首先我想到的是在何種情況下才能用到這個“等於沒有運算”呢?
那就是 Something And 255
當N大於255的時候,Something=True
當N小於等於255的時候,Something=N
這時我又想到了另一個邏輯運算:
True Or Anything = True '結論2 (Or 運算)
False Or Anything = Anthing
這可真是個好東東哦,想什麼來什麼,上面的那個Something可有著落了。
Something = AnotherThing Or N 就可以了。
對這個AnotherThing的要求是:
當N大於255的時候 AnotherThing=True
當N小於等於255的時候 AnotherThing=False
太簡單啦,直接AnotherThing=(N>255)就滿足啦
把前面的表示式都列出來看看:
N = Something And 255 '(1)
當N大於255的時候, Something=True
當N小於等於255的時候, Something=N
Something = AnotherThing Or N '(2)
當N大於255的時候 AnotherThing=True
當N小於等於255的時候 AnotherThing=False
AnotherThing=(N>255) '(3)
當N大於255的時候 N>255 = True
當N小於255的時候 N>255 = False
最後反過來一步一步代入前面的表示式:
(3)代入(2)再代入(1)
得到:
(N>255) Or N And 255
驗算一下:
當N大於255的時候:
(N>255) Or N And 255 => True Or N And 255 => True And 255 => 255
當N小於等於255的時候:
(N>255) Or N And 255 => False Or N And 255 => N And 255 => N
Yeah!!!
==
等等,別開香檳啊,還有事要做呀。
我們只是把兩個條件判斷語句變成了兩個邏輯表示式,還沒有達到最終目的呢。
那就是把兩個表示式整合成一個表示式。
先來看一下目前的成果:
if N > 255 then N=255
=》N = (N>255) Or N And 255 ‘(1)
if N < 0 then N=0
=》N = (N>0) And N ‘(2)
似乎有點難度哦,我首先想到的方法是把整個(2)代入(1)中,
N=(((n>0) And N) > 255) Or ((N>0) And N) And 255
整個表示式就變得奇長無比,估計即使成功,執行速度也不會比原來快。
你說化簡?恩,我也很想啊,但是連不等式運算都已經忘記,更不說邏輯表示式了。
還是繼續分析吧。
表示式(1)只考慮兩種情況: a: N>255 b: N<=255
而表示式(2)只考慮 a: N>0 b: N<=0
因此無論N是否大於0,都是被包含在表示式1的範圍之內的.
這樣的話,只需要將表示式(2)代入一半到表示式(1)中就可以了,
表示式1的括號內的不等式中的那個N不需要代入.
整個表示式變成: (N>255) Or ((N>0) And N) And 255
Or的兩邊可以交換順序,變成這樣:
((N>0) And N) Or (N>255) And 255
去括號: (N>0) And N Or (N>255) And 255
測試一下:
N=-1:
(-1>0) And –1 Or (-1>255) And 255
=False And –1 Or False And 255
=False Or False And 255
=False And 255
=False
=0
N=10:
(10>0) And 10 Or (10>255) And 255
=True And 10 Or False And 255
=10 Or False And 255
=10 And 255
=10
N=266
(266>0) And 266 Or (266>255) And 255
=True And 266 Or True And 255
=266 Or True And 255
=True And 255
=255
哈哈,終於成功了,回頭一看,原來和”zyl910”推匯出來的還是同一個東西.
香檳香檳拿出來!
你說我推匯出了一個別人早就弄好的東西為什麼還這麼開心??
廢話,要是自己不這麼來上一遍,那永遠是別人的,你最多隻能把它背出來,它終究不在你心裡.
最後,再花幾分鐘寫了一個測試程式,來驗證一下.
再回過頭去看,之前這個東東就是為了要放在影像處理中使用的,因此驗證的時候也應該用一個大陣列來做.
最後那個” CombWithVar”按鈕的事件其實也驗證了另外一個想法:用變數代替陣列元素運算確實可以提高速度,前提是在非常大的運算次數下才能顯現出這個差異來.
測試程式碼:
Private Declare Function timeGetTime Lib "winmm.dll" () As Long
Dim A(49999999) As Integer
Dim B(49999999) As Integer
Dim T As Long
Private Sub Form_Unload(Cancel As Integer)
End Sub
Private Sub Traditional_Click() ‘最原始的方法
Dim I As Long
T = timeGetTime
For I = LBound(A) To UBound(A)
If A(I) > 255 Then B(I) = 255
If A(I) < 0 Then A(I) = 0
Next
I = timeGetTime - T
Me.Print "Traditional Compare:" & I
Text1.Text = Text1.Text & Chr(13) & "Traditional Compare:" & I
End Sub
Private Sub BooleanExp_Click() ‘分成2個邏輯運算
Dim I As Long
T = timeGetTime
For I = LBound(A) To UBound(A)
B(I) = (A(I) > 255) Or A(I) And 255
B(I) = A(I) And (A(I) > 0)
Next
I = timeGetTime - T
Me.Print "Boolean Expression:" & I
Text1.Text = Text1.Text & Chr(13) & "Boolean Expression:" & I
End Sub
Private Sub Combination_Click() ‘合成一個邏輯運算
Dim I As Long
T = timeGetTime
For I = LBound(A) To UBound(A)
B(I) = (A(I) > 0 And A(I) Or (A(I) > 255)) And 255
Next
I = timeGetTime - T
Me.Print "Combination Bool-Exp:" & I
Text1.Text = Text1.Text & Chr(13) & "Combination Bool-Exp:" & I
End Sub
Private Sub CombWithVar_Click() ‘使用變數代替陣列元素
Dim I As Long
Dim L As Long
T = timeGetTime
For I = LBound(A) To UBound(A)
L = A(I)
B(I) = (L > 0 And L Or (L > 255)) And 255
Next
I = timeGetTime - T
Me.Print "Com_Bool_Exp_Var:" & I
Text1.Text = Text1.Text & Chr(13) & "Com_Bool_Exp_Var:" & I
End Sub
Private Sub Form_Load() ‘初始化陣列
Dim I As Long
For I = 0 To 1000
A(I) = Rnd * I / 2
Next
Me.Print "運算五千萬次計時"
Text1.Text = "運算五千萬次計時"
End Sub
<?xml:namespace prefix = v />
運算五千萬次計時
Traditional Compare:577
Traditional Compare:579
Traditional Compare:536
Traditional Compare:578
Traditional Compare:534
Traditional Compare:553
Traditional Compare:577
Traditional Compare:530
Traditional Compare:530
Traditional Compare:530
Boolean Expression:926
Boolean Expression:839
Boolean Expression:907
Boolean Expression:929
Boolean Expression:809
Boolean Expression:913
Boolean Expression:927
Boolean Expression:877
Boolean Expression:912
Boolean Expression:786
Combination Bool-Exp:593
Combination Bool-Exp:420
Combination Bool-Exp:426
Combination Bool-Exp:433
Combination Bool-Exp:467
Combination Bool-Exp:421
Combination Bool-Exp:415
Combination Bool-Exp:459
Combination Bool-Exp:422
Combination Bool-Exp:428
Com_Bool_Exp_Var:518
Com_Bool_Exp_Var:326
Com_Bool_Exp_Var:320
Com_Bool_Exp_Var:353
Com_Bool_Exp_Var:320
Com_Bool_Exp_Var:343
Com_Bool_Exp_Var:346
Com_Bool_Exp_Var:376
Com_Bool_Exp_Var:351
Com_Bool_Exp_Var:334
相關文章
- Python 影像處理 OpenCV (6):影像的閾值處理PythonOpenCV
- MySQL 數值型別溢位處理MySql型別
- openCV中的影像處理 3 影像閾值OpenCV
- 多對一處理 和一對多處理的處理
- Python影像處理丨5種影像處理特效Python特效
- webgl 影像處理2---影像畫素處理Web
- Python 影像處理 OpenCV (7):影像平滑(濾波)處理PythonOpenCV
- 影像處理--影像特效特效
- 影像預處理
- HDR影像便捷處理軟體
- 影像處理_切邊
- 前端影像處理指南前端
- 影像預處理方法
- OpenCV(影像NaN處理)OpenCVNaN
- 影像處理案例03
- 影像輪廓處理
- CPU(中央處理器)和GPU(影像處理器)的區別GPU
- 全能的影像處理軟體:inPixel for MacMac
- Repix Pro for Mac影像處理軟體Mac
- Mac上RAW影像處理軟體Mac
- CSS 小結筆記之文字溢位處理CSS筆記
- halcon的頻域影像處理
- 【scipy 基礎】--影像處理
- 遙感影像處理流程
- 影像處理之骨架提取
- solidworks2022,影像處理Solid
- 形態學影像處理
- cdr2022,影像處理
- Python影像處理庫——PILPython
- 影像行畫素處理
- 【scikit-learn基礎】--『預處理』之 缺失值處理
- Perfectly Clear Workbench 影像清晰處理軟體
- RAW Power for Mac(RAW影像處理軟體)Mac
- Perfectly Clear Workbench 影像清晰處理軟體
- Photomatix Pro for Mac(HDR影像處理軟體)Mac
- 如何處理JavaScript 中的貨幣值?JavaScript
- JSP 異常處理如何處理?JS
- Python 影像處理 OpenCV (2):畫素處理與 Numpy 操作以及 Matplotlib 顯示影像PythonOpenCV
- Python 影像處理 OpenCV (3):影像屬性、影像感興趣 ROI 區域及通道處理PythonOpenCV