立體視覺是計算機視覺領域的一個重要課題,它的目的在于重構場景的三維幾何資訊。立體視覺的研究具有重要的應用價值,其應用包括移動機器人的自主導航系統,航空及遙感測量,工業自動化系統等。
1. 引言
立體視覺是計算機視覺領域的一個重要課題,它的目的在于重構場景的三維幾何資訊。立體視覺的研究具有重要的應用價值,其應用包括移動機器人的自主導航系統,航空及遙感測量,工業自動化系統等。
一般而言,立體視覺的研究有如下三類方法:
(1) 直接利用測距器(如雷射測距儀)獲得程距(range data)資訊,建立三維描述的方法;
(2) 僅利用一幅圖象所提供的資訊推斷三維形狀的方法;
(3) 利用不同視點上的,也許是不同時間拍攝的,兩幅或更多幅圖象提供的資訊重構三維結構的方法。
第一類方法,也就是程距法 (range data method),根據已知的深度圖,用數值逼近的方法重建表面資訊,根據模型建立場景中的物體描述,實作圖象了解功能。這是一種主動方式的立體視覺方法,其深度圖是由測距器(range finders)獲得的,如結構光(structured light)、雷射測距器(laser range finders) 等其他主動傳感技術 (active sensing techniques)。這類方法适用于嚴格控制下的環境(tightly controlled domains),如工業自動化的應用方面。
第二類方法,依據光學成象的透視原理及統計假設,根據場景中灰階變化導出物體輪廓及表面,由影到形(shape from shading),進而推斷場景中的物體。線條圖的了解就是這樣的一個典型問題,曾經引起了普遍的重視而成為計算機視覺研究領域的一個焦點,由此産生了各種各樣的線條标注法。這種方法的結果是定性的,不能确定位置等定量資訊,該方法由于受到單一圖象所能提供資訊的局限性,存在難以克服的困難。
第三類方法,利用多幅圖象來恢複三維資訊的方法,它是被動方式的。根據圖象擷取方式的差別又可以劃分成普通立體視覺和通常所稱的光流(optical flow)兩大類。普通立體視覺研究的是由兩錄影機同時拍攝下的兩幅圖象,而光流法中研究的是單個錄影機沿任一軌道運動時順序拍下的兩幅或更多幅圖象。前者可以看作後者的一個特例,它們具有相同的幾何構形,研究方法具有共同點。雙目立體視覺是它的一個特例。
立體視覺的研究由如下幾部分組成:
(1) 圖象擷取 (image acquisition),
用作立體視覺研究的圖象的擷取方法是多種多樣的,在時間、視點、方向上有很大的變動範圍,直接受所應用領域的影響。立體視覺的研究主要集中在三個應用領域中,即自動測繪中的航空圖檔的解釋,自主車的導引及避障,人類立體視覺的功能模拟。不同的應用領域涉及不同類的景物,就場景特征的差別來分,可以劃分成兩大類,一類是含有文明特征(cultural features)的景物,如建築、道路等; 另一類是含有自然特征的景物和表面(natural objects and surfaces), 如山、水、平原及樹木等。不同類的景物的圖象處理方法大不相同,各有其特殊性。
總之,與圖象擷取相關的主要因素可歸納如下:
(a) 場景領域 (scene domain),
(b) 計時 (timing),
(c) 時間(照明和陰影)(time of day (lighting and presence ofshadows)),
(d) 成像形态(包括特殊的遮蓋)(photometry (including special coverage)),
(e) 分辨率 (resolution),
(f) 視野 (field of view),
(g) 錄影機的相對位置 (relative camera positioning).
場景的複雜程度受如下因素的影響:
(a) 遮掩 (occlusion),
(b) 人工物體(直的邊界,平的表面) (man-made objects (straight edge, flat surfaces)),
(c) 均勻的紋理區域 (smoothly textured areas),
(d) 含有重複結構的區域 (areas containing repetitive structure)。
(2) 錄影機模型 (camera modeling),
錄影機模型就是對立體錄影機組的重要的幾何與實體特征的表示形式,它作為一個計算模型,根據對應點的視差資訊,用于計算對應點所代表的空間點的位置。錄影機模型除了提供圖象上對應點空間與實際場景空間之間的映射關系外,還可以用于限制尋找對應點時的搜尋空間,進而降低比對算法的複雜性,減小誤比對率。
(3) 特征抽取 (feature acquisition),
幾乎是同一灰階的沒有特征的區域是難以找到可靠比對的,因而,絕大部分計算機視覺中的工作都包括某種形式的特征抽取過程,而且特征抽取的具體形式與比對政策緊密相關。在立體視覺的研究中,特征抽取過程就是提取比對基元的過程。
(4) 圖象比對 (image matching),
圖象比對是立體視覺系統的核心,是建立圖象間的對應進而計算視差的過程,是極為重要的。
(5) 深度計算 (distance(depth) determination),
立體視覺的關鍵在于圖象比對,一旦精确的對應點建立起來,距離的計算相對而言隻是一個簡單的三角計算而已。然而,深度計算過程也遇到了顯著的困難,尤其是當對應點具有某種程度的非精确性或不可靠性時。粗略地說,距離計算的誤差與比對的偏差成正比,而與錄影機組的基線長成反比。加大基線長可以減少誤差,但是這又增大了視差範圍和待比對特征間的差别,進而使比對問題複雜化了。為了解決這一問題出現了各種比對政策,如由粗到精政策,松馳法等。
在很多情況下,比對精度通常是一個象素。但是,實際上區域相關法和特征比對法都可以獲得更好的精度。區域相關法要達到半個象素的精度需要對相關面進行内插。盡管有些特征抽取方法可以得到比一個象素精度更好的特征,但這直接依賴于所使用的算子類型,不存在普遍可用的方法。
另一種提高精度的方法是采用一個象素精度的算法,但是利用多幅圖象的比對,通過多組比對的統計平均結果獲得較高精度的估計。每組比對結果對于最後深度估計的貢獻可以根據該比對結果的可靠性或精度權重處理。
總之,提高深度計算精度的途徑有三條,各自涉及了一些附加的計算量:
(a) 半象素精度估計 (subpixel estimation),
(b) 加長基線長 (increased stereo baseline),
(c) 幾幅圖的統計平均 (statistical averaging over several views)。
(6) 内插 (interpolation).
在立體視覺的應用領域中,一般都需要一個稠密的深度圖。基于特征比對的算法得到的僅是一個稀疏而且分布并不均勻的深度圖。在這種意義下,基于區域相關比對的算法更适合于獲得稠密的深度圖,但是該方法在那些幾乎沒有資訊(灰階均勻)的區域上的比對往往不可靠。是以,兩類方法都離不開某種意義的内插過程。最為直接的将稀疏深度圖内插成稠密的深度圖的方法是将稀疏深度圖看作為連續深度圖的一個采樣,用一般的内插方法(如樣條逼近)來近似該連續深度圖。當稀疏深度圖足以反映深度的重要變化時,該方法可能是合适的。如起伏地貌的航空立體照片的進行中用這種方式的内插也許是比較合适的。但是這種方法在許多應用領域中,尤其是在有遮掩邊界的圖象的領域中,就不适用了。
Grimson 指出可比對特征的遺漏程度反映了待内插表面變化程度的相應限度,在這種基礎上,他提出了一個内插過程[2]。換一角度來看,根據單幅圖象的“由影到形”的技術,用已經比對上的特征來建立輪廓條件和光滑的交接表面可以確定内插的有效性。這些方法結合起來,可以使内插過程達到合乎要求的目标。内插的另一種途徑是在已有的幾何模型與稀疏深度圖之間建立映射關系,這是模型比對過程。一般而言,要進行模型比對,預先應将稀疏深度圖進行聚類,形成若幹子集,各自相應于一種特殊結構。然後找每一類的最佳對應模型,該模型為這種特殊結構(物體)提供參數和内插函數。如 Gennery用這種方法來發現立體對圖檔中的橢園結構,Moravec 用于為自主車探測地面。
2. 雙目立體視覺(Binocular Stereo Vision)
2.1 雙目立體視覺模型
雙目立體視覺理論建立在對人類視覺系統研究的基礎上,通過雙目立體圖象的處理,擷取場景的三維資訊,其結果表現為深度圖,再經過進一步處理就可得到三維空間中的景物,實作二維圖象到三維空間的重構。Marr-Poggio-Grimson [1] 最早提出并實作了一種基于人類視覺系統的計算視覺模型及算法。雙目立體視覺系統中,擷取深度資訊的方法比其它方式(如由影到形方法)較為直接,它是被動方式的,因而較主動方式(如程距法)适用面寬,這是它的突出特點。
雙目立體視覺系統中,深度資訊的獲得是分如下兩步進行的:
(1) 在雙目立體圖象間建立點點對應,
(2) 根據對應點的視差計算出深度。
第一部分,也就是對應點問題,是雙目立體視覺的關鍵; 第二部分是錄影機模型問題。雙目立體視覺模型中,雙錄影機彼此參數一緻,光軸平行且垂直于基線,構成一共極性 (epipolar) 結構,這樣做是為了縮小對應的搜尋空間,隻有水準方向的視差,簡化了對應過程,如下圖所示。
如上圖所示,設空間一點P(X,Y,Z)在兩個平行放置的完全相同的攝象機中像點分别是(x1,y1).(x2,y2),則在知道基線長B和焦距f的情況下,可以計算出深度
這是雙目立體視覺的基本原理,即根據視差來恢複立體資訊。
2.2 比對基元
比對基元是指比對算法的最小比對對象,它是由特征抽取算法産生的。在建立立體視覺系統時,必須根據環境的特點和應用的領域選擇适當的比對基元。比對基元可以是:
(1) 過零點 (zero-crossings),
(2) 邊界與線片段 (edge and line fragments),
(3) 線性特征 (linear features),
(4) 邊緣輪廓 (object boundaries),
(5) 興趣算子抽取的特征點(如角點等)
基元作為比對算法處理的基本機關,是局部特征,應包含以下一些資訊:
(1) 維量(點、線、邊界等) (dimensionality),
(2) 尺度(空間頻度,長短、大小、方向等)(size (spatial frequency)),
(3) 亮度(對比度) (contrast),
(4) 語義量 (semantic content),
(5) 稠密度 (density of occurrence),
(6) 簡單可量度的分布特征 (easily measurable attributes),
(7) 唯一性/突出性 (uniqueness/distinguishability)
2.3 比對算法
比對算法就是在兩幅圖象的比對基元之間建立對應關系的過程,它是雙目立體視覺系統的關鍵。實際上,任何計算機視覺系統中都包含一個作為其核心的比對算法,因而對于比對算法的研究是極為重要的。
為了比較全面地考察比對算法,這裡不妨将雙目立體視覺的比對算法擴充到更一般的情況來分析:假設給定兩幅同一環境的圖象,這兩幅圖象可能由于攝取的時間、方位或方式的不同而有差别,如雙目立體視覺系統所攝取的兩幅圖象、地圖與遙感或航測圖象等,如何找到彼此對應的部分? 對于這個問題,一般有兩種考慮途徑:
(1) 灰階分布的相關性,
(2) 特征分布的相似性。
因而就有兩類算法:
(1) 基于灰階的算法 (intensity based),
(2) 基于特征的算法 (feature based)。
如果按照控制政策分,有如下幾種:
(1) 粗到精多層次結構 (coarse-to-fine,hierarchical),
(2) 引入限制條件的松馳法 (constraints, relaxation),
(3) 多級表示的決策結構 (multilevel representation)。
2.3.1 基于灰階的比對算法
基于灰階的算法是指圖象進行中所稱的區域相關方法 (area-correlation technique),它是解決對應問題的一個最直覺最簡單的方法。在一幅圖象中以一點為中心標明一區域(視窗),在另一幅圖象中尋找與該區域相關系數最大的區域,把該找到的區域的中心認為是原來那區域中心的對應點。這裡所說的圖象包括經過某種特殊處理如Gauss濾波後的圖象。
這種算法計算量大,但可以得到整幅圖象的視差圖。該算法對噪音很敏感,考慮到計算量,視窗不宜開得過大,因而可能比對的選擇較大,誤對應可能性大,不适于灰階分布均勻的圖象,較适于灰階分布很複雜的圖象,如自然景物等。采用該方法的關鍵在于排除或減輕噪音的影響。通常采用多層次相關對應及多幅圖象的統計平均處理方式來實作。如 D. B. Gennery [2]采用九幅圖象多級處理方式來實作對應求解。
2.3.2 基于特征的比對算法
鑒于灰階區域相關方法的局限性,現在大部分研究集中在這方面。在許多環境(如有線條輪廓特征可尋的人工環境 (man-made structured world))中,圖象的特征是很有規律地分布的,反映了場景的核心,數量少,處理友善。基于特征的比對算法特别适用于特殊的比較簡單的環境如室内環境,具有速度快、精度高的特點,但對于自然環境,由于缺少顯著的主導特征,該方法也遇到了很大困難。
基于特征的雙目立體視覺的對應算法,通過建立所選基元的對應關系,旨在擷取一稀疏深度圖,如果需要再經過内插等方法可以得到整幅深度圖。這一類算法因各自采用的比對基元不同而相異。概括而言,該類比對算法都是建立在比對基元之間的相似性度量基礎上的。這種相似性度量被稱為親合性 (affinity)[2], 它是以比對基元的各項參數資訊為依據的局部特征相似程度的度量。這種度量方法與錄影機模型相結合,可以大大減小比對時的搜尋空間。
由于僅利用親合性建立比對是模糊的,可能比對的空間仍舊很大(多對一的),是以有必要引入其它限制條件及控制政策來限制搜尋空間,減小模糊程度。比對算法中常引入的兩種限制條件及控制政策是:
(1) 共極性 (epipolar) (雙目立體視覺模型特點),
(2) 連續性 (continuity),
(3) 分層次的比對政策(即由粗到精政策)(hierarchical (e.g.,coarse-fine) matching strategy)。
這種引入限制的方法實際上是将有關環境模型的知識融于算法之中。
這種算法的具體實作,可以采用機率度量、松馳法疊代或者聚類等模式識别算法來實作。作為最後結果的1-1 對應,可以利用啟發式搜尋方法從已經大大減小了的搜尋空間中獲得。這部分可望能利用現代 AI 研究的許多手段如專家系統等研究方法,作為承上啟下,建立更高層次描述的先導。
可以從以下幾個角度來比較各種比對算法,
(1) 精度 (accuracy),
(2) 可靠性(排除總體分類誤差的程度)(reliability),
(3) 通用性(适于不同場景的能力)(available of performance models),
(4) 預見性 (predictability),
(5) 複雜性(裝置及計算量的代價)(complexity (cost implementation,
computational requirements))。
立體視覺的比對算法有:
(1) Marr-Poggio-Grimson算法,以過零點為基元,采用由粗到精的控制政策,用精度較低層次的比對來限定精度較高層次比對的搜尋空間,最後利用連續性限制通過疊代方式實作比對過程。處理對象是自然景物的雙目立體圖象。
(2) R. Nevatia-G.Medioni算法,以線片段 (segments) 為基元,以最小差别視差 (minimum differential disparity) 為基準,建立比對過程。該基準實際上是連續性限制的一種表現形式,在對應線片段各自鄰域記憶體在的對應線片段的視差與其視差相近。處理對象是人工環境的雙目立體圖象。
(3) R. Y. Wong算法,旨在建立兩類圖象的對應關系,如航空照片、遙感圖象與灰階圖象之間的對應關系。以邊界特征(edge feature)為依據采用順序的 (sequential)、多層次結構 (hierarchical structure)的搜尋政策實作比對過程。
(4) K. Price-R. Reddy算法,依據場景的線條特征模型,将自頂向下(人工智能)(top-down (artificial intelligence))與自底向上(模式識别)(bottom-up (pattern recognition)) 兩種控制政策有效地結合起來,采用廣義的相關方法進行比對,旨在建立形态差别較大的兩幅圖象(一幅是參照圖或參考模型,另一幅是待對應的圖象)的對應關系。如機場模型與機場的航空照片之間的對應關系。
(5) C. S. Clark-A. L. Luck-C. A. McNary算法,抽取線條輪廓特征建立模型,在模型間建立對應。适于存在較大差别的圖象的比對。
(6) K. E. Price算法,用于在圖象間建立區域對應。該算法利用區域間的互相關系,以松馳法為基本思想實作了多層次表示結構下的比對過程。突出特點是比對算法考慮了圖象本身區域間的互相關系(如包含、子部分等)的比對,具有類似于某種語義網絡式的啟發性。
(7) R. Horaud-T. Skorads算法,以線條特征為比對基元,每個線條特征不僅含有其本身的端點坐标及方向矢量資訊,而且含有它同那些與其相鄰的線條特征之間存在的相對位置及結構關系的資訊。這些特征将每幅圖象表示成為一個關系圖,根據該關系圖對于每個線條特征确定它在另一幅圖象中的可能對應集合,以每組對應為一結點構造對應圖,依據關系圖的相容性通過利益函數(benefit function)确定最佳對應。它處理的對象是室内環境的雙目立體圖象。
(8) W. Hoff-N. Ahuja算法,以過零點為最小特征,将特征比對、輪廓檢測以及表面内插這三個過程結合在一起,采用基于多層表示的由粗到精的控制政策,根據對于表面的光滑性限制重構三維表面。這是一種與傳統方法大不相同的算法,适合于有紋理特征的環境如工作台上的物品,不适合于稀疏特征環境如室内環境。另外 S. I. Olsen提出的算法與此相似,它将表面的重構過程(reconstruction process)結合在對應比對過程中,基于多重屬性用松弛法進行比對,逐漸提高重構的視差表面與實際的視差資料的一緻性。
2.4 雙目立體視覺系統
雙目立體視覺經過幾十年的研究已經取得了顯著了成果,出現了各種專門的硬體設計和視訊速率(實時)的立體視覺系統,在理論和技術方面都比較成熟了。但是,從普遍的意義來講,由于很難徹底地解決對應點問題,具體的立體視覺系統一般都是有針對性的、不是普遍适用的,還無法與人類的雙目視覺系統相媲美。
下圖是SRI的內建在電路闆上的雙目立體視覺系統。CMU設計了Stereo Machine, 可以實時地擷取深度資訊。
立體攝象機校準 Stereo Camera Calibration
三維視覺
Milan Sonka, 3D Vision
內建在電路闆上的立體攝象機對SRI Stereo Engine, Stereo head onboard
立體幾何模型 SRI Stereo Geometry
雙目立體視覺Introduction to Stereo Imaging -- Theory
3. 結構光方法(Structured Light)
将平面光束照射在物體上可以形成光帶,光帶的偏轉資料反映了物體表面的三維形狀資訊,用這種方法可以精确地擷取物體的三維資訊。借助于一組平行的平面光,或将物體置于專門的旋轉工作台上通過一束平面光,都可以利用偏轉資料直接地計算出深度資訊,稱這種方法為結構光方法。結構光方法适合于限制條件下,局部範圍内需要精确測量的情況,用于不規則表面的三維模組化。
結構光方法在工業上有重要的應用,例如從傳送帶上檢測工件,工件的逆工程(Reverse engineering);在圖形模組化方面也有重要的應用,如人體模組化,包括頭部等軀體模型,雕塑造型的數字化。實際上它是三維掃描器的基本原理。
如下圖所示的裝置,就是結構光方法的典型事例。
詳細可見:Our Active Stereo Vision System
4. 雷射雷達與程距資料(Range Data)處理
雷射雷達(Laser range finder)與結構光方法不同,它直接利用雷射光速掃描物體,通過測量光束從發出到反射回來的時間差來計算深度資訊。它提供的資料是深度圖,稱為程距資料(Range data)。雷射雷達可以用于比較大範圍的測量,如移動機器人可以用雷射雷達資訊來建立環境内模型,以實作自主導航、躲避障礙等功能。
程距資料實際上就是深度圖象,結構光方法和雷射雷達得到的資料最後都是深度資訊。程距資料處理主要是表面拟合,恢複物體的表面結構。
5. 視覺臨場感系統
臨場感(Telepresence)技術是新一代遙操作(Teleoperation)系統的重要組成部分。顧名思義,它的目的就是使人從遠地遙控操作時具有在現場處實地操作式的身臨其境的感覺。在理想情況下,這些感覺應該包括人的各種感官所能感受到的感覺,如視覺、聽覺、觸覺、味覺、體位覺、力感等。
臨場感系統因其面對的任務不同,所需的現場資訊有所差別,其中,視覺通常是最重要的資訊之一,其次才是聽覺、觸覺等。目前,臨場感技術主要涉及視覺和聽覺。
臨場感遙作業系統的主要優點是:将人與機器人有機地結合起來,能夠恰到好處地發揮出各自的特長。機器代替人去危險或人不可能到達的區域去工作,而人的判斷能力和決策水準又明顯地提高了系統的整體智能水準。
如下圖所示,室外車輛上的立體攝象機将視訊信号傳回基地端,操作員通過立體眼睛觀察環行螢幕,仿佛他親自在車上一樣能夠具有身臨其境的感覺。
(參見:艾海舟、張朋飛、何克忠、江濰、張軍宇,室外移動機器人的視覺臨場感系統,機器人,22(1):28-32,2000。)
有關立體視覺的前沿工作請參見微軟研究院張正友博士的網頁,他是這方面的著名學者:http://research.microsoft.com/~zhang/
參考文獻
1.馬松德、張正友,計算機視覺計算理論與算法基礎,科學出版社,1998。
2.艾海舟,關于雙目立體視覺的研究,碩士論文,121頁,1988.4.
3.艾海舟, 關于移動機器人自主式系統的研究, 博士論文, 153頁, 1991.3.
最近一直學習立體視覺,寫了很多的代碼,但是還沒整理具體的算法。使用左右兩張圖檔,計算深度圖
左圖如下:
右圖如下:
//SAD算法
#include<iostream>
#include<cv.h>
#include<highgui.h>
using namespace std;
int GetHammingWeight(unsigned int value);
int main(){
/*Half of the window size for the census transform*/
int hWin = 11;
int compareLength = (2*hWin+1)*(2*hWin+1);
cout<<"hWin: "<<hWin<<"; "<<"compare length: "<<compareLength<<endl;
cout<<"SAD test"<<endl;
// char stopKey;
IplImage * leftImage = cvLoadImage("left.bmp",0);
IplImage * rightImage = cvLoadImage("right.bmp",0);
int imageWidth = leftImage->width;
int imageHeight =leftImage->height;
IplImage * SADImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
IplImage * MatchLevelImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
int minDBounds = 0;
int maxDBounds = 31;
cvNamedWindow("Left",1);
cvNamedWindow("Right",1);
cvNamedWindow("Census",1);
cvNamedWindow("MatchLevel",1);
cvShowImage("Left",leftImage);
cvShowImage("Right",rightImage);
/*Census Transform */
int i,j ,m,n,k;
unsigned char centerPixel = 0;
unsigned char neighborPixel = 0;
int bitCount = 0;
unsigned int bigger = 0;
int sum = 0;
unsigned int *matchLevel = new unsigned int[maxDBounds - minDBounds + 1];
int tempMin = 0;
int tempIndex = 0;
unsigned char* dst;
unsigned char* leftSrc = NULL;
unsigned char* rightSrc = NULL;
unsigned char leftPixel = 0;
unsigned char rightPixel =0;
unsigned char subPixel = 0;
for(i = 0 ; i < leftImage->height;i++){
for(j = 0; j< leftImage->width;j++){
for (k = minDBounds;k <= maxDBounds;k++)
{
sum = 0;
for (m = i-hWin; m <= i + hWin;m++)
{
for (n = j - hWin; n <= j + hWin;n++)
{
if (m < 0 || m >= imageHeight || n <0 || n >= imageWidth )
{
subPixel = 0;
}else if (n + k >= imageWidth)
{
subPixel = 0;
}else
{
leftSrc = (unsigned char*)leftImage->imageData
+ m*leftImage->widthStep + n + k;
rightSrc = (unsigned char*)rightImage->imageData
+ m*rightImage->widthStep + n;
leftPixel = *leftSrc;
rightPixel = *rightSrc;
if (leftPixel > rightPixel)
{
subPixel = leftPixel - rightPixel;
}else
{
subPixel = rightPixel -leftPixel;
}
}
sum += subPixel;
}
}
matchLevel[k] = sum;
//cout<<sum<<endl;
}
/*尋找最佳比對點*/
// matchLevel[0] = 1000000;
tempMin = 0;
tempIndex = 0;
for ( m = 1;m < maxDBounds - minDBounds + 1;m++)
{
//cout<<matchLevel[m]<<endl;
if (matchLevel[m] < matchLevel[tempIndex])
{
tempMin = matchLevel[m];
tempIndex = m;
}
}
dst = (unsigned char *)SADImage->imageData + i*SADImage->widthStep + j;
//cout<<"index: "<<tempIndex<<" ";
*dst = tempIndex*8;
dst = (unsigned char *)MatchLevelImage->imageData + i*MatchLevelImage->widthStep + j;
*dst = tempMin;
//cout<<"min: "<<tempMin<<" ";
//cout<< tempIndex<<" " <<tempMin<<endl;
}
//cvWaitKey(0);
}
cvShowImage("Census",SADImage);
cvShowImage("MatchLevel",MatchLevelImage);
cvSaveImage("depth.jpg",SADImage);
cvSaveImage("matchLevel.jpg",MatchLevelImage);
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&leftImage);
cvReleaseImage(&rightImage);
return 0;
}
效果:
//SSD:
#include<iostream>
#include<cv.h>
#include<highgui.h>
using namespace std;
int GetHammingWeight(unsigned int value);
int main(){
/*Half of the window size for the census transform*/
int hWin = 11;
int compareLength = (2*hWin+1)*(2*hWin+1);
cout<<"hWin: "<<hWin<<"; "<<"compare length: "<<compareLength<<endl;
cout<<"SAD test"<<endl;
// char stopKey;
IplImage * leftImage = cvLoadImage("l2.jpg",0);
IplImage * rightImage = cvLoadImage("r2.jpg",0);
int imageWidth = leftImage->width;
int imageHeight =leftImage->height;
IplImage * SADImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
IplImage * MatchLevelImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
int minDBounds = 0;
int maxDBounds = 31;
cvNamedWindow("Left",1);
cvNamedWindow("Right",1);
cvNamedWindow("Census",1);
cvNamedWindow("MatchLevel",1);
cvShowImage("Left",leftImage);
cvShowImage("Right",rightImage);
/*Census Transform */
int i,j ,m,n,k;
unsigned char centerPixel = 0;
unsigned char neighborPixel = 0;
int bitCount = 0;
unsigned int bigger = 0;
int sum = 0;
unsigned int *matchLevel = new unsigned int[maxDBounds - minDBounds + 1];
int tempMin = 0;
int tempIndex = 0;
unsigned char* dst;
unsigned char* leftSrc = NULL;
unsigned char* rightSrc = NULL;
unsigned char leftPixel = 0;
unsigned char rightPixel =0;
unsigned char subPixel = 0;
for(i = 0 ; i < leftImage->height;i++){
for(j = 0; j< leftImage->width;j++){
for (k = minDBounds;k <= maxDBounds;k++)
{
sum = 0;
for (m = i-hWin; m <= i + hWin;m++)
{
for (n = j - hWin; n <= j + hWin;n++)
{
if (m < 0 || m >= imageHeight || n <0 || n >= imageWidth )
{
subPixel = 0;
}else if (n + k >= imageWidth)
{
subPixel = 0;
}else
{
leftSrc = (unsigned char*)leftImage->imageData
+ m*leftImage->widthStep + n + k;
rightSrc = (unsigned char*)rightImage->imageData
+ m*rightImage->widthStep + n;
leftPixel = *leftSrc;
rightPixel = *rightSrc;
if (leftPixel > rightPixel)
{
subPixel = leftPixel - rightPixel;
}else
{
subPixel = rightPixel -leftPixel;
}
}
sum += subPixel*subPixel;
}
}
matchLevel[k] = sum;
//cout<<sum<<endl;
}
/*尋找最佳比對點*/
// matchLevel[0] = 1000000;
tempMin = 0;
tempIndex = 0;
for ( m = 1;m < maxDBounds - minDBounds + 1;m++)
{
//cout<<matchLevel[m]<<endl;
if (matchLevel[m] < matchLevel[tempIndex])
{
tempMin = matchLevel[m];
tempIndex = m;
}
}
dst = (unsigned char *)SADImage->imageData + i*SADImage->widthStep + j;
//cout<<"index: "<<tempIndex<<" ";
*dst = tempIndex*8;
dst = (unsigned char *)MatchLevelImage->imageData + i*MatchLevelImage->widthStep + j;
*dst = tempMin;
//cout<<"min: "<<tempMin<<" ";
//cout<< tempIndex<<" " <<tempMin<<endl;
}
//cvWaitKey(0);
}
cvShowImage("Census",SADImage);
cvShowImage("MatchLevel",MatchLevelImage);
cvSaveImage("depth.jpg",SADImage);
cvSaveImage("matchLevel.jpg",MatchLevelImage);
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&leftImage);
cvReleaseImage(&rightImage);
return 0;
}
//ZSSD
#include<iostream>
#include<cv.h>
#include<highgui.h>
using namespace std;
int GetHammingWeight(unsigned int value);
int main(){
/*Half of the window size for the census transform*/
int hWin = 11;
int compareLength = (2*hWin+1)*(2*hWin+1);
cout<<"hWin: "<<hWin<<"; "<<"compare length: "<<compareLength<<endl;
cout<<"ZSSD test"<<endl;
// char stopKey;
/* IplImage * leftImage = cvLoadImage("l2.jpg",0);
IplImage * rightImage = cvLoadImage("r2.jpg",0);*/
IplImage * leftImage = cvLoadImage("left.bmp",0);
IplImage * rightImage = cvLoadImage("right.bmp",0);
int imageWidth = leftImage->width;
int imageHeight =leftImage->height;
IplImage * SADImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
IplImage * MatchLevelImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
int minDBounds = 0;
int maxDBounds = 31;
cvNamedWindow("Left",1);
cvNamedWindow("Right",1);
cvNamedWindow("Census",1);
cvNamedWindow("MatchLevel",1);
cvShowImage("Left",leftImage);
cvShowImage("Right",rightImage);
/*Census Transform */
int i,j ,m,n,k;
unsigned char centerPixel = 0;
unsigned char neighborPixel = 0;
int bitCount = 0;
unsigned int bigger = 0;
int sumLeft = 0;
int sumRight = 0;
int sum =0;
int zSumLeft = 0;
int zSumRight = 0;
unsigned int *matchLevel = new unsigned int[maxDBounds - minDBounds + 1];
int tempMin = 0;
int tempIndex = 0;
unsigned char* dst;
unsigned char* leftSrc = NULL;
unsigned char* rightSrc = NULL;
unsigned char leftPixel = 0;
unsigned char rightPixel =0;
unsigned char subPixel = 0;
unsigned char meanLeftPixel = 0;
unsigned char meanRightPixel = 0;
for(i = 0 ; i < leftImage->height;i++){
for(j = 0; j< leftImage->width;j++){
/*均值計算 */
for (k = minDBounds;k <= maxDBounds;k++)
{
sumLeft = 0;
sumRight = 0;
for (m = i-hWin; m <= i + hWin;m++)
{
for (n = j - hWin; n <= j + hWin;n++)
{
if (m < 0 || m >= imageHeight || n <0 || n >= imageWidth )
{
sumLeft += 0;
}else {
leftSrc = (unsigned char*)leftImage->imageData
+ m*leftImage->widthStep + n + k;
leftPixel = *leftSrc;
sumLeft += leftPixel;
}
if (m < 0 || m >= imageHeight || n + k <0 || n +k >= imageWidth)
{
sumRight += 0;
}else
{
rightSrc = (unsigned char*)rightImage->imageData
+ m*rightImage->widthStep + n;
rightPixel = *rightSrc;
sumRight += rightPixel;
}
}
}
meanLeftPixel = sumLeft/compareLength;
meanRightPixel = sumRight/compareLength;
/*ZSSD*/
sum = 0;
for (m = i-hWin; m <= i + hWin;m++)
{
for (n = j - hWin; n <= j + hWin;n++)
{
if (m < 0 || m >= imageHeight || n <0 || n >= imageWidth )
{
//zSumLeft += 0;
leftPixel = 0;
}else {
leftSrc = (unsigned char*)leftImage->imageData
+ m*leftImage->widthStep + n + k;
leftPixel = *leftSrc;
//zSumLeft += (leftPixel - meanLeftPixel)*(leftPixel -meanLeftPixel);
}
if (m < 0 || m >= imageHeight || n + k <0 || n +k >= imageWidth)
{
//zSumRight += 0;
rightPixel = 0;
}else
{
rightSrc = (unsigned char*)rightImage->imageData
+ m*rightImage->widthStep + n;
rightPixel = *rightSrc;
// zSumRight += (rightPixel - meanRightPixel)*(rightPixel - meanRightPixel);
}
sum += ((rightPixel - meanRightPixel)-(leftPixel -meanLeftPixel))
*((rightPixel - meanRightPixel)-(leftPixel -meanLeftPixel));
}
}
matchLevel[k] = sum;
//cout<<sum<<endl;
}
/*尋找最佳比對點*/
// matchLevel[0] = 1000000;
tempMin = 0;
tempIndex = 0;
for ( m = 1;m < maxDBounds - minDBounds + 1;m++)
{
//cout<<matchLevel[m]<<endl;
if (matchLevel[m] < matchLevel[tempIndex])
{
tempMin = matchLevel[m];
tempIndex = m;
}
}
dst = (unsigned char *)SADImage->imageData + i*SADImage->widthStep + j;
//cout<<"index: "<<tempIndex<<" ";
*dst = tempIndex*8;
dst = (unsigned char *)MatchLevelImage->imageData + i*MatchLevelImage->widthStep + j;
*dst = tempMin;
//cout<<"min: "<<tempMin<<" ";
//cout<< tempIndex<<" " <<tempMin<<endl;
}
// cvWaitKey(0);
}
cvShowImage("Census",SADImage);
cvShowImage("MatchLevel",MatchLevelImage);
cvSaveImage("depth.jpg",SADImage);
cvSaveImage("matchLevel.jpg",MatchLevelImage);
cout<<endl<<"Over"<<endl;
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&leftImage);
cvReleaseImage(&rightImage);
return 0;
}
//census
#include<iostream>
#include<cv.h>
#include<highgui.h>
using namespace std;
int GetHammingWeight(unsigned int value);
int main(){
/*Half of the window size for the census transform*/
int hWin = 11;
int bitlength = 0;
if ((2*hWin+1)*(2*hWin+1)%32 == 0)
{
bitlength = (2*hWin+1)*(2*hWin+1)/32;
}else {
bitlength = (2*hWin+1)*(2*hWin+1)/32 + 1;
}
cout<<"hWin: "<<hWin<<"; "<<"bit length: "<<bitlength<<endl;
cout<<"Census test"<<endl;
// char stopKey;
IplImage * leftImage = cvLoadImage("left.bmp",0);
IplImage * rightImage = cvLoadImage("right.bmp",0);
int imageWidth = leftImage->width;
int imageHeight =leftImage->height;
IplImage * CensusImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
IplImage * MatchLevelImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
int minDBounds = 0;
int maxDBounds = 31;
// int leftCensus[imageHeight][imageWidth][bitlength] = {0};
unsigned int *leftCensus = new unsigned int[imageHeight*imageWidth*bitlength];
unsigned int *rightCensus = new unsigned int[imageHeight*imageWidth*bitlength];
for (int i = 0;i < imageHeight*imageWidth*bitlength;i++)
{
leftCensus[i] = 0;
rightCensus[i] = 0;
}
int pointCnt = 0;
cvNamedWindow("Left",1);
cvNamedWindow("Right",1);
cvNamedWindow("Census",1);
cvNamedWindow("MatchLevel",1);
cvShowImage("Left",leftImage);
cvShowImage("Right",rightImage);
/*Census Transform */
int i,j ,m,n,k,l;
unsigned char centerPixel = 0;
unsigned char neighborPixel = 0;
int bitCount = 0;
unsigned int bigger = 0;
for(i = 0 ; i < leftImage->height;i++){
for(j = 0; j< leftImage->width;j++){
centerPixel = *((unsigned char *)leftImage->imageData + i*leftImage->widthStep + j);
bitCount = 0;
for (m = i - hWin; m <= i + hWin;m++)
{
for (n = j - hWin; n<= j+hWin;n++)
{
bitCount++;
if (m < 0 || m >= leftImage->height || n < 0 || n >= leftImage->width)
{
neighborPixel = 0;
}else{
neighborPixel = *((unsigned char *)leftImage->imageData + m*leftImage->widthStep + n);
}
bigger = (neighborPixel > centerPixel)?1:0;
leftCensus[(i*imageWidth + j)*bitlength + bitCount/32] |= (bigger<<(bitCount%32));
}
}
}
}
for(i = 0 ; i < rightImage->height;i++){
for(j = 0; j< rightImage->width;j++){
centerPixel = *((unsigned char *)rightImage->imageData + i*rightImage->widthStep + j);
bitCount = 0;
for (m = i - hWin; m <= i + hWin;m++)
{
for (n = j - hWin; n<= j+hWin;n++)
{
bitCount++;
if (m < 0 || m >= rightImage->height || n < 0 || n >= rightImage->width)
{
neighborPixel = 0;
}else{
neighborPixel = *((unsigned char *)rightImage->imageData + m*rightImage->widthStep + n);
}
bigger = (neighborPixel > centerPixel)?1:0;
rightCensus[(i*imageWidth + j)*bitlength + bitCount/32] |= (bigger<<(bitCount%32));
}
}
}
}
int sum = 0;
unsigned int *matchLevel = new unsigned int[maxDBounds - minDBounds + 1];
int tempMin = 0;
int tempIndex = 0;
unsigned char *dst;
unsigned char pixle = 0;
for(i = 0 ; i < rightImage->height;i++){
for(j = 0; j< rightImage->width;j++){
for (k = minDBounds;k <= maxDBounds;k++)
{
sum = 0;
for (l = 0;l< bitlength;l++)
{
if (((i*imageWidth+j+k)*bitlength + l) < imageHeight*imageWidth*bitlength)
{
sum += GetHammingWeight(rightCensus[(i*imageWidth+j)*bitlength + l]
^ leftCensus[(i*imageWidth+j+k)*bitlength + l]);
}else {
//sum += 0;
// cout<<".";
}
}
matchLevel[k] = sum;
}
/*尋找最佳比對點*/
tempMin = 0;
tempIndex = 0;
for ( m = 1;m < maxDBounds - minDBounds + 1;m++)
{
if (matchLevel[m] < matchLevel[tempIndex])
{
tempMin = matchLevel[m];
tempIndex = m;
}
}
if (tempMin > (2*hWin+1)*(2*hWin+1)*0.2)
{
tempMin = 0;
pointCnt++;
}else{
tempMin = 255;
}
dst = (unsigned char *)CensusImage->imageData + i*CensusImage->widthStep + j;
*dst = tempIndex*8;
dst = (unsigned char *)MatchLevelImage->imageData + i*MatchLevelImage->widthStep + j;
*dst = tempMin;
//cout<< tempIndex<<" " <<tempMin<<endl;;
}
}
cout<<"pointCnt: "<<pointCnt<<endl;
cvShowImage("Census",CensusImage);
cvShowImage("MatchLevel",MatchLevelImage);
cvSaveImage("depth.jpg",CensusImage);
cvSaveImage("matchLevel.jpg",MatchLevelImage);
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&leftImage);
cvReleaseImage(&rightImage);
return 0;
}
int GetHammingWeight(unsigned int value)
{
if(value == 0) return 0;
int a = value;
int b = value -1;
int c = 0;
int count = 1;
while(c = a & b)
{
count++;
a = c;
b = c-1;
}
return count;
}
//NCC
#include<iostream>
#include<cv.h>
#include<highgui.h>
#include <cmath>
using namespace std;
int main(){
/*Half of the window size for the census transform*/
int hWin = 11;
int compareLength = (2*hWin+1)*(2*hWin+1);
cout<<"hWin: "<<hWin<<"; "<<"compare length: "<<compareLength<<endl;
cout<<"NCC test"<<endl;
/* IplImage * leftImage = cvLoadImage("l2.jpg",0);
IplImage * rightImage = cvLoadImage("r2.jpg",0);*/
IplImage * leftImage = cvLoadImage("left.bmp",0);
IplImage * rightImage = cvLoadImage("right.bmp",0);
int imageWidth = leftImage->width;
int imageHeight =leftImage->height;
IplImage * NCCImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
IplImage * MatchLevelImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
int minDBounds = 0;
int maxDBounds = 31;
cvNamedWindow("Left",1);
cvNamedWindow("Right",1);
cvNamedWindow("Census",1);
cvNamedWindow("MatchLevel",1);
cvShowImage("Left",leftImage);
cvShowImage("Right",rightImage);
/*Census Transform */
int i,j ,m,n,k;
unsigned char centerPixel = 0;
unsigned char neighborPixel = 0;
int bitCount = 0;
unsigned int bigger = 0;
unsigned int sum =0;
unsigned int leftSquareSum = 0;
unsigned int rightSquareSum = 0;
double *matchLevel = new double[maxDBounds - minDBounds + 1];
double tempMax = 0;
int tempIndex = 0;
unsigned char* dst;
unsigned char* leftSrc = NULL;
unsigned char* rightSrc = NULL;
unsigned char leftPixel = 0;
unsigned char rightPixel =0;
unsigned char subPixel = 0;
unsigned char meanLeftPixel = 0;
unsigned char meanRightPixel = 0;
for(i = 0 ; i < leftImage->height;i++){
for(j = 0; j< leftImage->width;j++){
/*均值計算 */
for (k = minDBounds;k <= maxDBounds;k++)
{
sum = 0;
leftSquareSum = 0;
rightSquareSum = 0;
for (m = i-hWin; m <= i + hWin;m++)
{
for (n = j - hWin; n <= j + hWin;n++)
{
if (m < 0 || m >= imageHeight || n <0 || n >= imageWidth )
{
leftPixel = 0;
}else {
leftSrc = (unsigned char*)leftImage->imageData
+ m*leftImage->widthStep + n + k;
leftPixel = *leftSrc;
}
if (m < 0 || m >= imageHeight || n + k <0 || n +k >= imageWidth)
{
rightPixel = 0;
}else
{
rightSrc = (unsigned char*)rightImage->imageData
+ m*rightImage->widthStep + n;
rightPixel = *rightSrc;
}
sum += leftPixel*rightPixel;
leftSquareSum += leftPixel*leftPixel;
rightSquareSum += rightPixel*rightPixel;
}
}
matchLevel[k] = (double)sum/(sqrt(double(leftSquareSum))*sqrt((double)rightSquareSum));
}
tempMax = 0;
tempIndex = 0;
for ( m = 1;m < maxDBounds - minDBounds + 1;m++)
{
if (matchLevel[m] > matchLevel[tempIndex])
{
tempMax = matchLevel[m];
tempIndex = m;
}
}
dst = (unsigned char *)NCCImage->imageData + i*NCCImage->widthStep + j;
*dst = tempIndex*8;
dst = (unsigned char *)MatchLevelImage->imageData + i*MatchLevelImage->widthStep + j;
*dst = (unsigned char)(tempMax*255);
}
}
cvShowImage("Census",NCCImage);
cvShowImage("MatchLevel",MatchLevelImage);
cvSaveImage("depth.jpg",NCCImage);
cvSaveImage("matchLevel.jpg",MatchLevelImage);
cout<<endl<<"Over"<<endl;
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&leftImage);
cvReleaseImage(&rightImage);
return 0;
}
//DP
//例如,X=“ABCBDAB”,Y=“BCDB”是X的一個子序列
#include <cstdio>
#include <cstring>
#include <iostream>
#include<cv.h>
#include<highgui.h>
#include <cmath>
using namespace std;
const int Width = 1024;
const int Height = 1024;
int Ddynamic[Width][Width];
int main()
{
/*Half of the window size for the census transform*/
int hWin = 11;
int compareLength = (2*hWin+1)*(2*hWin+1);
cout<<"hWin: "<<hWin<<"; "<<"compare length: "<<compareLength<<endl;
cout<<"belief propagation test"<<endl;
IplImage * leftImage = cvLoadImage("l2.jpg",0);
IplImage * rightImage = cvLoadImage("r2.jpg",0);
// IplImage * leftImage = cvLoadImage("left.bmp",0);
// IplImage * rightImage = cvLoadImage("right.bmp",0);
int imageWidth = leftImage->width;
int imageHeight =leftImage->height;
IplImage * DPImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
//IplImage * MatchLevelImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
unsigned char * pPixel = NULL;
unsigned char pixel;
for (int i = 0; i< imageHeight;i++)
{
for (int j =0; j < imageWidth;j++ )
{
pPixel = (unsigned char *)DPImage->imageData + i*DPImage->widthStep + j;
*pPixel = 0;
}
}
int minDBounds = 0;
int maxDBounds = 31;
cvNamedWindow("Left",1);
cvNamedWindow("Right",1);
cvNamedWindow("Depth",1);
cvNamedWindow("MatchLevel",1);
cvShowImage("Left",leftImage);
cvShowImage("Right",rightImage);
int minD = 0;
int maxD = 31;
//假設圖像是經過矯正的,那麼每次都隻是需要搜搜同一行的内容
int max12Diff = 10;
for (int i = 0;i < imageWidth;i++)
{
Ddynamic[0][i] = 0;
Ddynamic[i][0] = 0;
}
unsigned char * pLeftPixel = NULL;
unsigned char * pRightPixel = NULL;
unsigned char leftPixel = 0;
unsigned char rightPixel =0;
int m,n,l;
for (int i = 0 ; i < imageHeight;i++)
{
for (int j = 0; j<imageWidth;j++)
{
for (int k = j + minD; k <= j + maxD;k++)
{
if (k <0 || k >= imageWidth)
{
}else {
pLeftPixel = (unsigned char*)leftImage->imageData + i*leftImage->widthStep + k;
pRightPixel= (unsigned char*)rightImage->imageData+i*rightImage->widthStep + j;
leftPixel = *pLeftPixel;
rightPixel = *pRightPixel;
if (abs(leftPixel - rightPixel) <= max12Diff)
{
Ddynamic[j + 1][k + 1] = Ddynamic[j][k] +1;
}else if (Ddynamic[j][k+1] > Ddynamic[j+1][k])
{
Ddynamic[j + 1][k + 1] = Ddynamic[j][k+1];
}else{
Ddynamic[j+1][k+1] = Ddynamic[j+1][k];
}
//cout<<Ddynamic[j +1][k+1]<<" ";
}
}
//cout<<"\n";
}
//逆向搜尋,找出最佳路徑
m = imageWidth;
n = imageWidth;
l = Ddynamic[imageWidth][imageWidth];
while( l>0 )
{
if (Ddynamic[m][n] == Ddynamic[m-1][n])
m--;
else if (Ddynamic[m][n] == Ddynamic[m][n-1])
n--;
else
{
//s[--l]=a[i-1];
pPixel = (unsigned char *)DPImage->imageData + i*DPImage->widthStep + m;
*pPixel = (n-m)*8;
l--;
m--;
n--;
}
}
//cvWaitKey(0);
}
cvShowImage("Depth",DPImage);
cvSaveImage("depth.jpg",DPImage);
cvWaitKey(0);
return 0;
}
//貼一張清楚的
//DP5
//引入機率公式
//
#include <cstdio>
#include <cstring>
#include <iostream>
#include<cv.h>
#include<highgui.h>
#include <cmath>
using namespace std;
const int Width = 1024;
const int Height = 1024;
int Ddynamic[Width][Width];
//使用鐘形曲線作為比對機率,內插補點越小則比對的機率越大,最終的要求是使比對的機率最大,機率曲線使用matlab生成
int Probability[256] = {
255, 255, 254, 252, 250, 247, 244, 240, 235, 230, 225, 219, 213, 206, 200, 192, 185, 178, 170, 162,
155, 147, 139, 132, 124, 117, 110, 103, 96, 89, 83, 77, 71, 65, 60, 55, 50, 46, 42, 38, 35, 31, 28,
25, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int main()
{
IplImage * leftImage = cvLoadImage("l2.jpg",0);
IplImage * rightImage = cvLoadImage("r2.jpg",0);
//IplImage * leftImage = cvLoadImage("left.bmp",0);
//IplImage * rightImage = cvLoadImage("right.bmp",0);
int imageWidth = leftImage->width;
int imageHeight =leftImage->height;
IplImage * DPImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
IplImage * effectiveImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
IplImage * FilterImage = cvCreateImage(cvGetSize(leftImage),leftImage->depth,1);
unsigned char * pPixel = NULL;
unsigned char pixel;
unsigned char * pPixel2 = NULL;
unsigned char pixel2;
for (int i = 0; i< imageHeight;i++)
{
for (int j =0; j < imageWidth;j++ )
{
pPixel = (unsigned char *)DPImage->imageData + i*DPImage->widthStep + j;
*pPixel = 0;
pPixel = (unsigned char *)effectiveImage->imageData + i*effectiveImage->widthStep + j;
*pPixel = 0;
}
}
cvNamedWindow("Left",1);
cvNamedWindow("Right",1);
cvNamedWindow("Depth",1);
cvNamedWindow("effectiveImage",1);
cvShowImage("Left",leftImage);
cvShowImage("Right",rightImage);
int minD = 0;
int maxD = 31;
//假設圖像是經過矯正的,那麼每次都隻是需要搜搜同一行的内容
int max12Diff = 5;
for (int i = 0;i < imageWidth;i++)
{
Ddynamic[0][i] = 0;
Ddynamic[i][0] = 0;
}
unsigned char * pLeftPixel = NULL;
unsigned char * pRightPixel = NULL;
unsigned char leftPixel = 0;
unsigned char rightPixel =0;
int m,n,l;
int t1 = clock();
for (int i = 0 ; i < imageHeight;i++)
{
for (int j = 0; j<imageWidth;j++)
{
for (int k = j + minD; k <= j + maxD;k++)
{
if (k <0 || k >= imageWidth)
{
}else {
pLeftPixel = (unsigned char*)leftImage->imageData + i*leftImage->widthStep + k;
pRightPixel= (unsigned char*)rightImage->imageData+i*rightImage->widthStep + j;
leftPixel = *pLeftPixel;
rightPixel = *pRightPixel;
//之前機率最大的點加上目前的機率
Ddynamic[j + 1][k + 1] = max(Ddynamic[j][k],max(Ddynamic[j][k+1],Ddynamic[j+1][k]))
+ Probability[abs(leftPixel - rightPixel)];
/* if (abs(leftPixel - rightPixel) <= max12Diff)
{
Ddynamic[j + 1][k + 1] = Ddynamic[j][k] +1;
}else if (Ddynamic[j][k+1] > Ddynamic[j+1][k])
{
Ddynamic[j + 1][k + 1] = Ddynamic[j][k+1];
}else{
Ddynamic[j+1][k+1] = Ddynamic[j+1][k];
}*/
//cout<<Ddynamic[j +1][k+1]<<" ";
}
}
//cout<<"\n";
}
//逆向搜尋,找出最佳路徑
m = imageWidth;
n = imageWidth;
l = Ddynamic[imageWidth][imageWidth];
while( m >= 1 && n >= 1)
{
pPixel = (unsigned char *)DPImage->imageData + i*DPImage->widthStep + m;
*pPixel = (n-m)*8;
//标記有效比對點
pPixel = (unsigned char *)effectiveImage->imageData + i*effectiveImage->widthStep + m;
*pPixel = 255;
if (Ddynamic[m-1][n] >= Ddynamic[m][n -1] && Ddynamic[m-1][n] >= Ddynamic[m-1][n -1])
m--;
else if (Ddynamic[m][n-1] >= Ddynamic[m-1][n] && Ddynamic[m][n -1] >= Ddynamic[m-1][n -1])
n--;
else
{
//s[--l]=a[i-1];
// l -= Ddynamic[m][n];
m--;
n--;
}
}
//cvWaitKey(0);
}
//refine the depth image 7*7中值濾波
//統計未能比對點的個數
int count = 0;
for (int i = 0 ;i< imageHeight;i++)
{
for (int j= 0; j< imageWidth;j++)
{
pPixel = (unsigned char *)effectiveImage->imageData + i*effectiveImage->widthStep + j;
pixel = *pPixel;
if (pixel == 0)
{
count++;
}
}
}
int t2 = clock();
cout<<"dt: "<<t2-t1<<endl;
cout<<"Count: "<<count<<" "<<(double)count/(imageWidth*imageHeight)<<endl;
cvShowImage("Depth",DPImage);
cvShowImage("effectiveImage",effectiveImage);
// cvWaitKey(0);
FilterImage = cvCloneImage(DPImage);
//7*7中值濾波
int halfMedianWindowSize = 3;
int medianWindowSize = 2*halfMedianWindowSize + 1;
int medianArray[100] = {0};
count = 0;
int temp = 0;
int medianVal = 0;
for (int i = halfMedianWindowSize + 1 ;i< imageHeight - halfMedianWindowSize;i++)
{
for (int j = halfMedianWindowSize; j< imageWidth - halfMedianWindowSize;j++)
{
pPixel = (unsigned char *)effectiveImage->imageData + i*effectiveImage->widthStep + j;
pixel = *pPixel;
if (pixel == 0)
{
count = 0;
for (int m = i - halfMedianWindowSize ; m <= i + halfMedianWindowSize ;m++)
{
for (int n = j - halfMedianWindowSize; n <= j + halfMedianWindowSize ;n++)
{
pPixel2 = (unsigned char *)DPImage->imageData + m*DPImage->widthStep + n;
pixel2 = *pPixel2;
if (pixel2 != 0)
{
medianArray[count] = pixel2;
count++;
}
}
//排序
for (int k = 0; k< count;k++)
{
for (int l = k + 1; l< count;l++)
{
if (medianArray[l] < medianArray[l-1] )
{
temp = medianArray[l];
medianArray[l] = medianArray[l-1];
medianArray[l-1] = temp;
}
}
}
medianVal = medianArray[count/2];
pPixel = (unsigned char *)FilterImage->imageData + i*DPImage->widthStep + j;
*pPixel = medianVal;
}
}
}
}
cvShowImage("Depth",DPImage);
cvShowImage("effectiveImage",effectiveImage);
cvShowImage("Filter",FilterImage);
cvSaveImage("depth.jpg",DPImage);
cvSaveImage("effective.jpg",effectiveImage);
cvWaitKey(0);
return 0;
}
給我寫信