原文鏈接:http://www.aosabook.org/en/itk.html
作者:Luis Ibanez 和 Brad King
譯按:原文的二級(jí)和三級(jí)標(biāo)題并無(wú)章節(jié)號(hào),只有字號(hào)區(qū)別。
ITK,又名Insight Toolkit,是一種用于圖像分析的庫(kù),它由美國(guó)國(guó)家醫(yī)學(xué)圖書(shū)館(US National Libraray of Medicine)發(fā)起并資助開(kāi)發(fā)的。ITK可以看作是一個(gè)方便使用的圖像分析算法百科全書(shū),特別是它包含了圖像濾波、圖像分割和圖像配準(zhǔn)。該庫(kù)由一個(gè)大學(xué)和商業(yè)公司組成的聯(lián)合組織、以及來(lái)自世界各地的代碼提交者共同開(kāi)發(fā)。ITK的開(kāi)發(fā)工作始于1999年,在其最近的十周年紀(jì)念過(guò)后不久,全庫(kù)經(jīng)歷了一次重構(gòu)過(guò)程,這次重構(gòu)旨在去除代碼庫(kù)中的頑固代碼;并對(duì)其重塑,以適應(yīng)下一個(gè)十年的發(fā)展。
軟件工具箱與他們的社區(qū)有一種密切的關(guān)系。他們以一個(gè)持續(xù)迭代的周期塑造彼此。軟件被持續(xù)改進(jìn),直到它能滿足社區(qū)的需要,與此同時(shí),社區(qū)基于軟件準(zhǔn)許或者約束他們要怎樣做來(lái)制約他們自身的行為。因此,為了更好地理解ITK架構(gòu)的天性,了解ITK社區(qū)經(jīng)常提出何種問(wèn)題,以及他們?nèi)绾沃纸鉀Q這些問(wèn)題,是非常有用的。
如果你不了解野獸的天性,那這就對(duì)理解它們解剖結(jié)構(gòu)的機(jī)制毫無(wú)用處。
--?Dee Hock, One from Many: VISA and the Rise of Chaordic Organization
一個(gè)典型的圖像分析問(wèn)題中,研究者或者工程師會(huì)取一個(gè)輸入圖像,通過(guò)降噪或是提高對(duì)比度來(lái)改善圖像的某些特性,然后進(jìn)行處理以辨別圖像中的某些特征,比如拐角和強(qiáng)邊緣。這種類型的處理很自然地符合一種數(shù)據(jù)管線架構(gòu),如圖9.1所示。
圖9.2:MRI腦部圖像,中值濾波器,邊緣檢測(cè)濾波器
對(duì)于圖中的每一項(xiàng)任務(wù),圖像處理社區(qū)都已經(jīng)開(kāi)發(fā)出了各種算法,并且繼續(xù)開(kāi)發(fā)新的算法。為什么他們繼續(xù)做這些?你可能會(huì)問(wèn),答案就是圖像處理是一種科學(xué)、工程、藝術(shù)、以及“烹飪”技術(shù)的組合。公然宣稱某種算法組合對(duì)于一個(gè)圖像處理任務(wù)來(lái)說(shuō)是“對(duì)的”無(wú)異于類似宣布正餐上要備“對(duì)的”巧克力甜點(diǎn)一樣的誤導(dǎo)。不是追求完美,社區(qū)奮力制造出豐富的工具來(lái)確保在面對(duì)一項(xiàng)挑戰(zhàn)性的圖像處理任務(wù)時(shí),不會(huì)出現(xiàn)可選項(xiàng)的短缺。當(dāng)然,事情發(fā)展的狀態(tài)是要付出代價(jià)的。代價(jià)就是圖像分析人員有一個(gè)困難的任務(wù),就是在從幾十個(gè)不同工具中選擇可用的不同組合,而這些組合可以得出類似的結(jié)果。
圖像分析社區(qū)與研究社區(qū)聯(lián)系緊密。某一個(gè)研究小組與某一個(gè)算法群相關(guān)聯(lián)是尋常現(xiàn)象。“品牌命名”的風(fēng)俗,以及某種程度的“市場(chǎng)化”,導(dǎo)致了一種這樣的情況:軟件工具箱可以盡可能好地為社區(qū)提供一個(gè)非常完整的算法實(shí)現(xiàn)集,然后將之混合并匹配,以創(chuàng)建一個(gè)滿足社區(qū)需要的菜譜。
為什么ITK要被設(shè)計(jì)并實(shí)現(xiàn)成一個(gè)巨大的某種程度獨(dú)立、且有條理的工具——圖像濾波器——的原因有很多,多數(shù)濾波器用于解決類似的問(wèn)題。在本文中,某種程度的“冗余”——打個(gè)比方,提供高斯濾波器的三種不同實(shí)現(xiàn)方法——這不應(yīng)該被看做是問(wèn)題,而應(yīng)該是一種有價(jià)值的特性,因?yàn)椴煌膶?shí)現(xiàn)可以可交換地使用,以滿足約束并且發(fā)掘與圖像尺寸、處理器數(shù)量、以及可能與某個(gè)給定圖像處理應(yīng)用程序中的特定高斯核尺度相關(guān)的效率潛能。
該工具箱還被創(chuàng)建成一個(gè)成長(zhǎng)的、不斷更新自身的資源,因?yàn)樾碌乃惴ê透玫膶?shí)現(xiàn)出現(xiàn)了,取代了現(xiàn)有的;還因?yàn)闉榱藨?yīng)對(duì)不斷涌現(xiàn)的新的醫(yī)學(xué)影像處理技術(shù)而開(kāi)發(fā)的新工具。
快速了解了ITK社區(qū)中的圖像分析人員的每日例行公事,我們現(xiàn)在開(kāi)始深入架構(gòu)的主要特性:
模塊化是ITK的主要特性之一。這個(gè)需求源于圖像分析社區(qū)的人們解決問(wèn)題時(shí)的工作方式。大多數(shù)圖像分析問(wèn)題將一幅或多幅輸入圖像放入處理濾波器的組合中,這些濾波器用于增強(qiáng)或是提取圖像中的某些特定的信息片段。因此這中間就沒(méi)有大的處理對(duì)象,而是許多小的。邏輯上講,這種圖像處理問(wèn)題的結(jié)構(gòu)性本質(zhì)特征意味著要實(shí)現(xiàn)一個(gè)由許多圖像處理濾波器組成的軟件,這些濾波器就可以以不同的方式組合使用了。
將某些特定的處理濾波器聚合為一個(gè)家族也是如此,其中的某些實(shí)現(xiàn)上的特性可以被分解。這就導(dǎo)致圖像濾波器自然分組為模塊以及模塊群。
至此,模塊化存在于ITK中的三個(gè)自然層次上:
在圖像濾波器層次上,ITK大約擁有700個(gè)濾波器??紤]到ITK是以C++實(shí)現(xiàn)的,這個(gè)層次中的每一個(gè)濾波器都是以C++類輔以面向?qū)ο蟮脑O(shè)計(jì)模式來(lái)實(shí)現(xiàn)的。在濾波器家族層次上,ITK根據(jù)濾波器進(jìn)行處理時(shí)的方式將其分組。例如,所有與傅里葉變換有關(guān)的濾波器將會(huì)放入同一個(gè)模塊。在C++層次上,模塊映射于源代碼文件樹(shù),并且映射于軟件編譯成二進(jìn)制形式后的庫(kù)文件。ITK擁有120個(gè)這種模塊。每個(gè)模塊包含:
圖9.4:ITK中50個(gè)最大的模塊的大小分布,單位:字節(jié)
ITK中的模塊化也應(yīng)用于其中的第三方庫(kù),這些庫(kù)并不是工具箱的直接組成部分,但是工具箱依賴它們,因此將這些第三方庫(kù)與工具箱中的其余代碼一起發(fā)行,以方便使用者。尤其是圖像文件格式庫(kù):HDF5、PNG、TIFF、JPEG、OpenJPEG等。這里強(qiáng)調(diào)第三方庫(kù)是因?yàn)榧s占ITK總大小的56%。這一點(diǎn)反映了開(kāi)源應(yīng)用建立在現(xiàn)有平臺(tái)之上的自然特征。第三方庫(kù)的大小分布固然不能反映ITK的組織架構(gòu),因?yàn)槲覀儾捎昧诉@些有用的庫(kù),僅僅是由于它們屬于上游開(kāi)發(fā)產(chǎn)物。然而, 第三方庫(kù)的代碼與工具箱一并發(fā)行、并且將之分割,是模塊化過(guò)程的關(guān)鍵驅(qū)動(dòng)因素之一。
這里給出模塊大小的分布,因?yàn)樗且环N代碼合理模塊化的量度??梢园汛a的模塊化看做是一個(gè)連續(xù)譜,分布于從只有一個(gè)巨大的、單體的模塊的一端,到將代碼分割成許多相等大小的模塊的另一端。大小分布是一種工具,它用于顯示模塊化過(guò)程的進(jìn)展,尤其是確保同一個(gè)模塊中沒(méi)有大塊的代碼,除非有真實(shí)的邏輯依賴關(guān)系需要這樣的分組。
ITK的模塊化架構(gòu)使下面的事項(xiàng)成為可能或有助于它們實(shí)現(xiàn):
模塊化過(guò)程使顯式地辨別并聲明工具箱中不同部分的依賴關(guān)系成為可能,當(dāng)然,這些不同的部分是要放在模塊中的。在許多情況下,這種做法暴露了做作的以及不正確的依賴關(guān)系,隨著時(shí)間的變化,這些依賴關(guān)系被引入工具箱,當(dāng)大多數(shù)代碼被放入一些大的家族群中的時(shí)候,這些依賴關(guān)系就會(huì)被忽視。
評(píng)估各模塊的質(zhì)量指標(biāo)的用處是雙重的。首先,它使開(kāi)發(fā)者對(duì)其維護(hù)的模塊負(fù)責(zé)變得容易。其次,它使得參與由若干開(kāi)發(fā)者集中短期時(shí)間來(lái)提高某個(gè)特定模塊的質(zhì)量的清理行動(dòng)成為可能。當(dāng)集中精力于工具箱的一小部分的時(shí)候,它使我們更容易看到我們的努力、并且更容易地保持開(kāi)發(fā)者的參與、受到激勵(lì)。
對(duì)于重新迭代,我們發(fā)現(xiàn)工具箱架構(gòu)反映了社區(qū)的組織,以及在有些情況下,被用于軟件的持續(xù)成長(zhǎng)和質(zhì)量控制的過(guò)程。
多數(shù)圖像分析任務(wù)具有的階段性特征很自然地導(dǎo)致我們選擇了數(shù)據(jù)管線架構(gòu)作為數(shù)據(jù)處理的基礎(chǔ)設(shè)施。數(shù)據(jù)管線是下列成為可能:
圖9.1和9.2已經(jīng)從圖像處理的角度展示了一種數(shù)據(jù)管線的簡(jiǎn)化表示。圖像濾波器一般都具有數(shù)值型參數(shù),用于調(diào)整濾波器的行為。每次有參數(shù)發(fā)生變更,數(shù)據(jù)管線就會(huì)將其輸出標(biāo)記為“臟的”,并且知道這個(gè)濾波器及其下游使用它的輸出的各濾波器應(yīng)該重新執(zhí)行。管線設(shè)施的特性減少了探測(cè)參數(shù)空間的困難,同時(shí)為實(shí)驗(yàn)中的各個(gè)示例分配最少的處理能力。
更新管線的過(guò)程可以通過(guò)每次只處理圖像的一部分的方式來(lái)驅(qū)動(dòng)。這是一種對(duì)于支持動(dòng)態(tài)載入處理功能來(lái)說(shuō)很有必要的機(jī)制。實(shí)踐中,該過(guò)程被一種從一個(gè)RequestedRegion
規(guī)范的內(nèi)部傳遞所控制,這種傳遞過(guò)程將規(guī)范從下游的濾波器傳向其上游的濾波器。這種通信過(guò)程是通過(guò)一個(gè)內(nèi)部API來(lái)實(shí)現(xiàn)的,并且可供應(yīng)用程序開(kāi)發(fā)者直接調(diào)用。
舉一個(gè)更具體些的例子,如果一個(gè)高斯模糊圖像濾波器以一幅由中值濾波器處理過(guò)的100×100像素的圖像作為輸入,那么該模糊濾波器可以向中值濾波器請(qǐng)求只處理原圖像的四分之一,也就是說(shuō),一個(gè)大小為100×25像素的圖像區(qū)域。該請(qǐng)求還會(huì)繼續(xù)向上游傳播,同時(shí)警告沿途各濾波器為了生成請(qǐng)求中規(guī)定大小的圖像區(qū)域,將不得不向圖像區(qū)域的尺寸附加邊界。后面還將講述更多關(guān)于數(shù)據(jù)流的內(nèi)容。
不論是對(duì)給定濾波器的參數(shù)做出的改變,還是該濾波器所要處理的特定請(qǐng)求區(qū)域所做的改變,都會(huì)將管線標(biāo)記為“臟的”、并提示管線的下游濾波器需要重新執(zhí)行。
有兩種主要的對(duì)象類型被設(shè)計(jì)用于存儲(chǔ)管線的基本結(jié)構(gòu)。它們是DataObject
和ProcessObject
。DataObject
是承載數(shù)據(jù)的類的抽象;例如:圖像和幾何網(wǎng)格。ProcessObject
為處理上述數(shù)據(jù)的圖像濾波器和網(wǎng)格濾波器提供抽象。ProcessObject
以DataObject
為輸入,并對(duì)其進(jìn)行某種算法變換,例如圖9.2中的那些。
DataObject
是由ProcessObject
生成的。這個(gè)鏈條通常自從磁盤(pán)讀取DataObject
開(kāi)始,例如通過(guò)使用一種ProcessObject
類型的ImageFileReader
。唯一能夠修改某個(gè)DataObject
的就是生成該DataObject
的ProcessObject
。輸出的DataObject
一般連入管線中下游的濾波器作為它們的輸入。
圖9.5:ProcessObject
與DataObject
之間的關(guān)系
這種序列關(guān)系如圖9.5所示。同一個(gè)DataObject
可能會(huì)傳給多個(gè)ProcessObject
作為它們的輸入,如圖中所示,DataObject
由管線開(kāi)端的文件reader生成。在這種特定情況下,文件reader是ImageFileReader
的實(shí)例,而它所生成的、作為其輸出的DataObject
是Image
類的一個(gè)實(shí)例。某些濾波器需要兩個(gè)DataObject
作為輸入也是很平常的現(xiàn)象,比如上圖中右半部出現(xiàn)的相減濾波器就是這樣的例子。
ProcessObject
和DataObject
連接起來(lái) 構(gòu)建管線的副作用。從應(yīng)用程序開(kāi)發(fā)者的角度來(lái)看,管線是通過(guò)涉及到一連串的調(diào)用連接起來(lái)的,如:
writer->SetInput(canny->GetOutput());
canny->SetInput(median->GetOutput());
median->SetInput(reader->GetOutput());
然而在內(nèi)部,連接在一起的并非以這中一連串的ProcessObject
,而是下游的ProcessObject
與其上游ProcessObject
生成的DataObject
。
管線內(nèi)部的鏈條結(jié)構(gòu)通過(guò)三種類型的連接維持在一起:
ProcessObject
保有一系列指向其輸出的DataObject
的指針。ProcessObject
擁有并控制著其生成的DataObject
。ProcessObject
保有一系列指向作為其輸入的DataObject
的指針。輸入的DataObject
由上游的ProcessObject
擁有。DataObject
保有指向生成它的ProcessObject
的指針。該ProcessObject
正好還擁有和控制著這個(gè)DataObject
。這些內(nèi)部鏈接隨后被用于在管線內(nèi)部向上游或下游傳遞調(diào)用信息。在所有這些互動(dòng)過(guò)程中,ProcessObject
都保持對(duì)其所生成的DataObject
的控制和所有權(quán)。下游的濾波器通過(guò)指針的鏈接來(lái)獲得對(duì)一個(gè)給定DataObject
的信息的訪問(wèn)權(quán)限,這種鏈接是由一連串的對(duì)SetInput()
和GetOutput()
的調(diào)用建立起來(lái)的,它甚至無(wú)需獲得對(duì)輸入數(shù)據(jù)的控制。出于實(shí)踐的目的,濾波器應(yīng)當(dāng)將其各自的輸入數(shù)據(jù)看作是只讀的對(duì)象。這一點(diǎn)在API中通過(guò)在SetInput()
方法的變量中使用C++的const
關(guān)鍵字得到了加強(qiáng)。作為一個(gè)通用的規(guī)則,ITK還是包含了一個(gè)const-correct的外部API,盡管從內(nèi)部來(lái)看,這種const-correctness被某些管線操作重載。
圖9.7:UML時(shí)序圖
當(dāng)應(yīng)用程序調(diào)用管線中最后一個(gè)濾波器的Update()
方法時(shí),整個(gè)流程即被觸發(fā);在這個(gè)具體的例子當(dāng)中,這個(gè)濾波器就是ImageFileWriter
。Update()
調(diào)用指向上游方向以初始化第一階段。也就是說(shuō),從管線中的最后一個(gè)濾波器起,朝向管線中的第一個(gè)濾波器。
第一個(gè)環(huán)節(jié)的目的是為了查詢這樣的問(wèn)題,“你能為我生成多少數(shù)據(jù)?”這個(gè)問(wèn)題轉(zhuǎn)化為代碼就是UpdateOutputInformation()
。這個(gè)方法中,各個(gè)濾波器根據(jù)其輸入中的可用數(shù)據(jù)量來(lái)計(jì)算可作為輸出的圖像數(shù)據(jù)量。考慮到必須在該濾波器回應(yīng)輸出數(shù)據(jù)量之前獲知輸入數(shù)據(jù)量,這個(gè)問(wèn)題就得傳導(dǎo)至上游的濾波器,一直傳至某個(gè)能夠回應(yīng)該問(wèn)題的源濾波器。在這個(gè)示例中,源濾波器就是ImageFileReader
。它能夠通過(guò)從其所讀入的圖像文件收集信息,得出其輸出的數(shù)據(jù)大小。一旦管線中的第一個(gè)濾波器對(duì)問(wèn)題做出了回應(yīng),該濾波器下游的一系列濾波器就能夠依次計(jì)算其各自的輸出數(shù)據(jù)量,并一直運(yùn)行至管線中的最末一個(gè)濾波器。
第二個(gè)環(huán)節(jié)的處理方向也是向上游方向的,用于告知各濾波器應(yīng)該輸出的數(shù)據(jù)量,此數(shù)據(jù)量是管線運(yùn)行過(guò)程中所需要的。Requested Region是支持ITK的流處理能力的基本概念。它使“告知濾波器不要生成整個(gè)完整圖像、而只是關(guān)注圖像的某個(gè)子區(qū)域(即:Requested Region)”成為可能。這在手頭的圖像大于系統(tǒng)內(nèi)存的時(shí)候是非常有用的。調(diào)用請(qǐng)求從最后一個(gè)濾波器傳導(dǎo)至第一個(gè),在途中的每個(gè)濾波器,requested region的尺寸都會(huì)被修正,這些修正要考慮到該濾波器輸入中可能需要的任何附加的邊界,這樣該濾波器才能生成給定區(qū)域尺寸的輸出。在我們的這個(gè)示例中,中位數(shù)濾波器一般會(huì)向其輸入中加入2-像素的邊界。也就是說(shuō),如果writer向中位數(shù)濾波器請(qǐng)求一個(gè)500×500尺寸的區(qū)域,那么中位數(shù)濾波器就會(huì)相應(yīng)地向reader請(qǐng)求一個(gè)502×502尺寸的區(qū)域,因?yàn)橹形粩?shù)濾波器在缺省情況下計(jì)算一個(gè)輸出像素,需要一個(gè)3×3像素的鄰域。這個(gè)環(huán)節(jié)被寫(xiě)入PropagateRequestedRegion()
方法。
第三個(gè)環(huán)節(jié)要觸發(fā)Requested Region內(nèi)的數(shù)據(jù)的計(jì)算。該環(huán)節(jié)的處理方向也是向上游,它被定義為UpdateOutputData()
方法。由于各個(gè)濾波器在其計(jì)算出輸出結(jié)果之前都需要輸入數(shù)據(jù),本環(huán)節(jié)的調(diào)用請(qǐng)求先向其上游的濾波器傳遞,然后再向上游傳導(dǎo)。然后返回到實(shí)際進(jìn)行數(shù)據(jù)計(jì)算的當(dāng)前濾波器。
第四個(gè)環(huán)節(jié)(最后一個(gè)環(huán)節(jié))的處理方向是向下游的,它由每個(gè)實(shí)際執(zhí)行運(yùn)算的濾波器組成。該環(huán)節(jié)被寫(xiě)為GenerateData()
。下游方向并不是一個(gè)濾波器向其下游發(fā)送調(diào)用請(qǐng)求的結(jié)果,而是UpdateOutputData()
的調(diào)用以從管線中的第一個(gè)濾波器到最后一個(gè)的順序執(zhí)行。也就是說(shuō),所發(fā)生的下游方向的順序,要?dú)w因于調(diào)用的時(shí)機(jī),而不要?dú)w因于什么濾波器在驅(qū)動(dòng)這一調(diào)用。這個(gè)說(shuō)明是很重要的,因?yàn)镮TK的管線從本質(zhì)上講是Pull Pipeline,其中的數(shù)據(jù)是管線的末端所請(qǐng)求的,而且這種邏輯也是由管線的末端來(lái)控制的。
ITK的基礎(chǔ)設(shè)計(jì)需求之一是提供多平臺(tái)支持。這一需求出現(xiàn)于追求使該工具箱的影響最大化,通過(guò)使工具箱能夠?yàn)樯鐓^(qū)所廣泛使用,而無(wú)需考慮其各自的平臺(tái)。ITK采用工廠設(shè)計(jì)模式來(lái)應(yīng)對(duì)這樣的挑戰(zhàn):支持多種不同硬件和軟件平臺(tái)、而不犧牲一個(gè)解決方案在不同平臺(tái)上的實(shí)用性。
ITK中的工廠模式使用類的名稱作為向構(gòu)造函數(shù)注冊(cè)的鍵值。工廠的注冊(cè)在運(yùn)行時(shí)進(jìn)行,這一過(guò)程可以在ITK應(yīng)用程序啟動(dòng)時(shí),通過(guò)簡(jiǎn)單地將動(dòng)態(tài)鏈接庫(kù)放入指定路徑來(lái)完成。后一種特性提供了一種以干凈、透明的方式實(shí)現(xiàn)插件架構(gòu)的基本機(jī)制。其影響是減少可擴(kuò)展圖像分析應(yīng)用程序的開(kāi)發(fā)難度,同時(shí)滿足了提供持續(xù)成長(zhǎng)的圖像分析能力的需要。
工廠機(jī)制對(duì)于IO操作尤為重要。
圖像分析社群開(kāi)發(fā)了非常多的文件格式來(lái)儲(chǔ)存圖像數(shù)據(jù)。這些文件格式中的大多數(shù)都是為了滿足特定的需要而設(shè)計(jì)和實(shí)現(xiàn)的,因此為支持特定類型的圖像而進(jìn)行了微調(diào)。結(jié)果,新的文件格式定期涌現(xiàn)并推廣到這個(gè)社群。注意到這一形勢(shì),ITK開(kāi)發(fā)團(tuán)隊(duì)設(shè)計(jì)了一個(gè)IO架構(gòu),適于減輕擴(kuò)展性工作,向這樣的架構(gòu)中定期添加越來(lái)越多的文件格式是簡(jiǎn)單的。
,第I卷,Naval Center for Cost Analysis, Air Force Cost Analysis Agency, 2008。)維護(hù)估計(jì)要占到一個(gè)軟件開(kāi)發(fā)人員實(shí)際工作的大約80%,而當(dāng)忙于維護(hù)的時(shí)候,開(kāi)發(fā)人員的大部分時(shí)間都被用于閱讀他人的代碼,試圖看懂這些代碼的意圖(見(jiàn)Clean Code, A Handbook of Agile Software Craftsmanship,Robert C. Martin,Prentice Hall,2009)。統(tǒng)一的風(fēng)格確實(shí)想減少開(kāi)發(fā)人員將自己沉浸于一個(gè)新近的開(kāi)源文件、并在對(duì)該文件做出任何修改之前理解其中的代碼的工作中所花費(fèi)的時(shí)間。出于同樣的原因,統(tǒng)一的風(fēng)格降低了開(kāi)發(fā)人員嘗試修復(fù)舊有的bug時(shí)、由于對(duì)代碼的誤解并隨之做出的引入新的bug的修改的概率(The Art of Readable Code,Dustin Boswell,Trevor Foucher, O'Reilly,2012)。
使這些工具有效的關(guān)鍵在于確保它們:
能夠?yàn)槊恳粋€(gè)開(kāi)發(fā)人員所使用,因此我們傾向于開(kāi)源工具。
能夠運(yùn)行于一個(gè)正規(guī)的基礎(chǔ)上。在ITK中,這些工具已被整合到由CDash管理的每日構(gòu)建和Continuous Dashboard構(gòu)建中去。
ITK始于2000年,并持續(xù)發(fā)展至2010年。2011年,幸虧融入了聯(lián)邦資助基金,開(kāi)發(fā)團(tuán)隊(duì)才有了真正的專門(mén)的機(jī)會(huì)進(jìn)行重構(gòu)的努力。該基金由國(guó)家醫(yī)學(xué)圖書(shū)館提供,作為美國(guó)恢復(fù)和再投資法案(ARRA,American Recovery and Reinvestment Act)所發(fā)倡議的一部分。這不是一個(gè)小小的承諾。想象一下你一直致力于一個(gè)軟件超過(guò)十年時(shí)間,然后你獲得了一個(gè)把它清理干凈的機(jī)會(huì);你該改動(dòng)些什么呢?
這個(gè)做廣泛重構(gòu)的機(jī)會(huì)十分難得。在之前的十年里,我們依賴于每天的努力來(lái)進(jìn)行小規(guī)模的、局部的重構(gòu),清理那些我們走進(jìn)的特殊的角落。這個(gè)持續(xù)的清理和提高過(guò)程利用了開(kāi)源社群的大規(guī)模協(xié)作的優(yōu)勢(shì),該過(guò)程由CDash驅(qū)動(dòng)的測(cè)試基礎(chǔ)設(shè)施確保安全,此基礎(chǔ)設(shè)施通常進(jìn)行工具包中84%的代碼的測(cè)試。注意,與此相反,軟件工業(yè)的平均測(cè)試覆蓋率估計(jì)只有50%。
在重構(gòu)的努力過(guò)程里被改動(dòng)的許多事物當(dāng)中,與架構(gòu)最為相關(guān)的有:
工具包中引入了模塊化
整型被標(biāo)準(zhǔn)化
typedef被修復(fù),從而能夠在所有平臺(tái)上進(jìn)行大于4GB的圖像數(shù)據(jù)的處理
軟件過(guò)程被修正:
從CVS遷移到Git
利用Gerrit引入代碼審查
根據(jù)CDash@home的要求引入測(cè)試
廢棄對(duì)過(guò)時(shí)的編譯器的支持
對(duì)許多IO圖像文件格式的改進(jìn)支持,包括:
DICOM
JPEG2000
TIFF(BigTIFF)
引入支持GPU計(jì)算的框架
引入視頻處理的支持
加入OpenCV橋
基于遞增修正的維護(hù)——諸如為濾波器添加特性、提高一個(gè)給定算法的性能等任務(wù)——對(duì)于特定的C++類的局部改進(jìn)很奏效。然而,基礎(chǔ)設(shè)施的修改需要大規(guī)模的重構(gòu),這會(huì)影響整個(gè)工具包中大量的類,像是上面所講到的那些。舉個(gè)例子,這些為支持大于4GB圖像的處理所需的變動(dòng)有可能是迄今為止給ITK所打的最大的補(bǔ)丁之一。它要求對(duì)數(shù)以百計(jì)的類進(jìn)行修改,并且無(wú)法在不經(jīng)受巨大的痛苦的情況下完成。模塊化是這個(gè)任務(wù)中的另一個(gè)實(shí)例,它并沒(méi)有增量地完成。這確實(shí)影響了整個(gè)工具包的組織,它的測(cè)試基礎(chǔ)設(shè)施是如何工作的、測(cè)試數(shù)據(jù)是如何被管理的、工具包是如何被打包并發(fā)行的、以及新的代碼貢獻(xiàn)將如何被封裝以添加的未來(lái)的工具包中。
ITK在其早期所接受的教訓(xùn)之一,就是發(fā)表在這個(gè)領(lǐng)域的許多論文的實(shí)現(xiàn)并不像我們所了解的那么容易。計(jì)算領(lǐng)域傾向于過(guò)度褒獎(jiǎng)算法,而輕視作為“只是實(shí)現(xiàn)細(xì)節(jié)”的這一編寫(xiě)軟件的實(shí)際工作。
那種輕視的態(tài)度對(duì)這個(gè)領(lǐng)域具有相當(dāng)?shù)钠茐男?,因?yàn)樗H低了通過(guò)編寫(xiě)代碼和恰當(dāng)?shù)氖褂盟@得的第一手經(jīng)驗(yàn)的重要性。后果是大多數(shù)發(fā)表的論文就是不能重現(xiàn),而且當(dāng)研究人員和學(xué)生想使用這些技術(shù)的時(shí)候,他們都以花費(fèi)了大量時(shí)間在這一(重現(xiàn))過(guò)程中、并且引入了對(duì)原作的變動(dòng)而結(jié)束。在實(shí)踐中,要驗(yàn)證一個(gè)實(shí)現(xiàn)是否與一篇文章中所描述的內(nèi)容是否契合,確實(shí)是相當(dāng)困難的。
ITK出于良善的目的,破壞了那種環(huán)境,并且在這樣一個(gè)領(lǐng)域恢復(fù)了一種DIY文化,這個(gè)領(lǐng)域已經(jīng)變得習(xí)慣于理論推理、并且已經(jīng)樹(shù)立起輕視實(shí)驗(yàn)工作的風(fēng)氣。由ITK帶來(lái)的新文化是一種實(shí)踐的、實(shí)用主義的文化,這種文化中,軟件的性能的判定是基于其自身的實(shí)踐結(jié)果的,而不是基于其自身看起來(lái)所具有的復(fù)雜性,這種復(fù)雜性被許多科學(xué)出版物推崇備至。事實(shí)證明,在實(shí)踐中,最有效的處理方法恰恰是那些看起來(lái)太簡(jiǎn)單而不能以科學(xué)論文的形式被接受的方法。
可重現(xiàn)的文化是測(cè)試驅(qū)動(dòng)型開(kāi)發(fā)哲學(xué)的一種延續(xù),并且有條不紊地做出更好的軟件;更高的清晰度,可讀性,魯棒性,以及專注的方向。
為了填補(bǔ)缺乏可重現(xiàn)出版物的空白,ITK社群創(chuàng)建了Insight Journal。它是可以公開(kāi)訪問(wèn)的、完全在線的出版物,它要求投稿都要包含代碼,數(shù)據(jù),參數(shù),和測(cè)試,使可重現(xiàn)性的驗(yàn)證成為可能。文章在提交后的24小時(shí)內(nèi)發(fā)表上線。然后社群中的任何成員就能夠?qū)@些文章進(jìn)行同行評(píng)審。讀者能夠獲得隨文章一起的所有材料:源代碼,數(shù)據(jù),參數(shù),和測(cè)試腳本。這個(gè)期刊一直提供一個(gè)多產(chǎn)的空間,用于共享新的代碼貢獻(xiàn),這些代碼貢獻(xiàn)將會(huì)在這里走上進(jìn)入代碼主倉(cāng)庫(kù)的道路。期刊最近收到了它的第500篇投遞文章,還將繼續(xù)作為向ITK添加新代碼的正式門(mén)戶。
更多建議: