日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

图像处理职位面试题汇总(1)

發布時間:2024/3/12 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图像处理职位面试题汇总(1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Matlab編程部分

1. Matlab 中讀、寫及顯示一幅圖像的命令各是什么?

解:第一、Matlab中讀圖像函數是imread( )。imread 函數用于讀入各種圖像文件,其一般的用法為:[X,MAP]=imread(‘filename’,‘fmt’)

其中,X,MAP分別為讀出的圖像數據和顏色表數據,fmt為圖像的格式,filename為讀取的圖像文件(可以加上文件的路徑)。如: [X,MAP]=imread(’flowers.tif’,’tif’);比較讀取二值圖像,灰度圖像,索引圖像,彩色圖像的X和MAP的特點。

第二、Matlab中讀圖像函數是imwrite( ),imwrite函數用于輸出圖像,其語法格式為: imwrite(X,map,filename,fmt)

按照fmt指定的格式將圖像數據矩陣X和調色板map寫入文件filename。

第三、Matlab中顯示圖像函數是imshow( ),imshow函數是最常用的顯示各種圖像的函數,其語法如:imshow(X,map)

其中X是圖像數據矩陣,map是其對應的顏色矩陣,若進行圖像處理后不知道圖像數據的值域可以用[]代替map。

  • 二進制(二值)圖像顯示方法,在MATLAB中一幅二值圖像是uint8或雙精度的,該矩陣僅包含0和1。如果希望工具箱中的函數能將圖像理解為二進制的,那么所有數據都要是邏輯數據,必須對其進行設置(將所有數據標志均設置on).可以對數據利用“~”取反操作實現圖像逆轉即黑白反色。
  • 灰度圖像的顯示方法,正常情況下無需指定灰度圖像的調色板格式??梢允鞘褂胕mshow函數指定要顯示灰度級數目,格式 imshow(I,n),n為指定的灰度級數目。用戶也可以指定數據的范圍,格式imshow(I,[low high])其中low 和high參數分別為數據數組的最小值和最大值。如果為空矩陣([]),那么imshow函數將自動進行數據標度。
  • 索引圖像,imshow(x,map)對于x的每個個像素,imshow顯示存儲map中相應行的顏色。
  • RGB圖像的顯示,它直接對顏色進行描述而不使用調色板,格式imshow(RGB)。 RGB(:,:,1) RGB(:,:,2)   RGB(:,:,3)
  • 特殊顯示,如多幅圖像的顯示,需要顯示多幅圖像時。可以使用figure語句,它的功能就是重新打開一個圖像顯示窗口.

2. Matlab 與VC++混合編程有哪幾種方式?

解:Matlab與VC++混合編程主要有三種方式:Matlab引擎方式、Matlab編譯器及COM組件。

第一種:Matlab引擎方式。Matlab引擎采用客戶機/服務器(Client/Server)的方式,提供了一組Matlab API函數,通過調用這些函數實現以用程序進程之間的數據傳遞。VC程序作為前端客戶機,向Matlab引擎傳遞命令和數據,并從Matlab引擎接受數據信息,實現動態通信。采用這種方法幾乎能利用MATLAB全部功能,但是需要在機器上安裝MATLAB軟件,而且執行效率低,因此在實際應用中不采用這種方法,在軟件開發中也不可行。

第二種:Matlab編譯器。MATLAB Compiler可以將M語言函數文件自動轉化產生獨立應用程序或者軟件組件,生成的組件或者獨立應用程序可以與其他用戶共享。使用MATLAB Compiler創建的獨立應用程序或者軟件組件能夠完全脫離MATLAB環境。MATLAB Compiler能夠顯著的縮短桌面應用程序的開發時間,僅僅通過簡單的指令就可以將M語言函數轉變為獨立的應用程序或者軟件組件,然后將它們打包發布給最終用戶。這里所指的利用M語言開發的MATLAB應用程序可以包括數學計算、圖形應用和GUIDE開發的圖形界面等,而最終用戶根本不需要擁有MATLAB。

其特點:1、自動將M語言函數文件轉換為可執行應用程序,脫離MATLAB環境2、簡單易用的發布過程3、支持所有MATLAB的M語言特性,例如MATLAB對象、Java對象等等。4、支持大多數工具箱函數,允許將MATLAB基本算法免費發布使用強大功能。 5、用戶可以利用MATLAB集成環境開發自己的算法原型和應用程序,然后利用MATLAB Compiler將開發的算法發布給最終用戶,最終用戶可以通過可執行應用程序或者軟件組件應用開發完好的算法。用戶在進行算法維護的時候無需針對C代碼進行操作。

算法開發僅僅需要三個步驟:第一步:創建算法,MATLAB本身是一種集成化的算法開發環境,它提供了各種工具用于完成算法快速原型的開發、測試。其中包括了高級的基于矩陣運算的向量化算法語言M語言,并且內建了大量用于數學計算、數據分析和圖形可視化的算法函數。MATLAB開發工具提供了語言編輯器、調試工具和性能分析器,并且可以利用交互式圖形界面開發工具開發自定義的圖形界面工具。第二步:轉化應用程序。使用MATLAB Compiler可以將開發好的M語言算法函數轉變成為:獨立可執行應用程序;C/C++算法共享庫;軟件組件,例如COM對象或者Excel插件;獨立可執行應用程序;MATLAB Compiler可以自動地將MATLAB應用程序轉變為獨立可執行應用程序;自動確定相關的MATLAB函數 ;生成C/C++接口代碼文件 ;將所有相關的文件打包壓縮保存在單一壓縮文件中;可在最終的應用程序中集成用戶的C或C++代碼。第三步:算法函數庫。使用與創建獨立可執行應用程序相同的指令就可以創建MATLAB函數庫。MATLAB? Compiler將自動創建相應的頭文件和共享庫文件,以便集成自定義的C/C++代碼文件,最終完成應用程序的開發。通過MATLAB Compiler完成應用程序的發布之后,可以將應用程序打包、發布給任意的最終用戶。MATLAB Compiler提供了相應的應用軟件可以將運行應用程序必需的庫文件打包。

第三種:COM組件。COM(Component Object Model,組件對象模型)是以組件為發布單元的對象模型,是一系列面向對象技術和工具的集合。由于COM是建立在二進制級別上的規范,所以組件對象之間的交互規范不依賴于任何特定的語言。MATLAB提供了COM生成器。COM生成器提供了實現MATLAB獨立應用的一種新途徑。它能把MATLAB開發的算法做成組件,這些組件作為獨立的COM對象,可以直接被C++、VB、VC、C#、JAVA或其他支持COM的語言所引用,只要相應的MATLAB編譯器和C/C+ +編譯器都已經安裝及配置成功,MATLAB COM編譯器即可開始使用,并不需要特別的設置。該方法實現簡單,通用性強,而且幾乎可以使用MATLAB的任何函數(注意:不支持腳本文件,腳本文件使用時要改為函數文件),因此在程序較大、調用工具箱函數或調用函數較多時推薦使用。Matlab的COM 編譯器是在Matlab6.5中才開始提供的一個新工具,從Matlab7.0起,這個產品改名為MatlabBuilder for COM?;贑OM的混合編程方法也是Mathworks公司推薦使用的方法。

以上3種方法中,采用Matlab引擎方式,應用程序整體性能好,Matlab引擎支持功能全面,但需要Matlab后臺運行,不能脫離Matlab 環境。而MCC方法和COM組件方法均可以脫離Matlab環境,應用程序運行效率高,利于軟件的開發。

3.Matlab運算中 . *和 * 的區別?

解:MATLAB中 帶“.” (讀作“點”)的運算符都表示點運算。這就要求A.*B中的A、B必須同規格,然后對應點的數據相乘,結果也是一個與A、B相同規格的矩陣。(標量是1*1矩陣)MATLAB的數據單元是矩陣,*表示的是矩陣相乘。要求A*B中A的列數等于B的行數。

圖像處理基礎部分

1. Intel指令集中MMX,SSE,SSE2,SSE3和SSE4指的是什么?

解:Intel指令集中MMX(Multi Media eXtension,多媒體擴展指令集指令集是Intel公司于1996年推出的一項多媒體指令增強技術。MMX指令集中包括有57條多媒體指令,通過這些指令可以一次處理多個數據,在處理結果超過實際處理能力的時候也能進行正常處理,這樣在軟件的配合下,就可以得到更高的性能。MMX的益處在于,當時存在的操作系統不必為此而做出任何修改便可以輕松地執行MMX程序。但是,問題也比較明顯,那就是MMX指令集與x87浮點運算指令不能夠同時執行,必須做密集式的交錯切換才可以正常執行,這種情況就勢必造成整個系統運行質量的下降。

Intel指令集中SSE(Streaming SIMD Extensions,單指令多數據流擴展)指令集是Intel在Pentium III處理器中率先推出的。其實,早在PIII正式推出之前,Intel公司就曾經通過各種渠道公布過所謂的KNI(Katmai New Instruction)指令集,這個指令集也就是SSE指令集的前身,并一度被很多傳媒稱之為MMX指令集的下一個版本,即MMX2指令集。究其背景,原來"KNI"指令集是Intel公司最早為其下一代芯片命名的指令集名稱,而所謂的"MMX2"則完全是硬件評論家們和媒體憑感覺和印象對"KNI"的 評價,Intel公司從未正式發布過關于MMX2的消息。而最終推出的SSE指令集也就是所謂勝出的"互聯網SSE"指令集。SSE指令集包括了70條指令,其中包含提高3D圖形運算效率的50條SIMD(單指令多數據技術)浮點運算指令、12條MMX 整數運算增強指令、8條優化內存中連續數據塊傳輸指令。理論上這些指令對目前流行的圖像處理、浮點運算、3D運算、視頻處理、音頻處理等諸多多媒體應用起到全面強化的作用。S SE指令與3DNow!指令彼此互不兼容,但SSE包含了3DNow!技術的絕大部分功能,只是實現的方法不同。SSE兼容MMX指令,它可以通過SIMD和單時鐘周期并行處理多個浮點數據來有效地提高浮點運算速度。

Intel指令集中SSE2(Streaming SIMD Extensions 2,Intel官方稱為SIMD 流技術擴展 2或數據流單指令多數據擴展指令集 2)指令集是Intel公司在SSE指令集的基礎上發展起來的。相比于SSE,SSE2使用了144個新增指令,擴展了MMX技術和SSE技術,這些指令提高了廣大應用程序的運行性能。隨MMX技術引進的SIMD整數指令從64位擴展到了128 位,使SIMD整數類型操作的有效執行率成倍提高。雙倍精度浮點SIMD指令允許以 SIMD格式同時執行兩個浮點操作,提供雙倍精度操作支持有助于加速內容創建、財務、工程和科學應用。除SSE2指令之外,最初的SSE指令也得到增強,通過支持多種數據類型(例如,雙字和四字)的算術運算,支持靈活并且動態范圍更廣的計算功能。SSE2指令可讓軟件開發員極其靈活的實施算法,并在運行諸如MPEG-2、MP3、3D圖形等之類的軟件時增強性能。Intel是從Willamette核心的Pentium 4開始支持SSE2指令集的,而AMD則是從K8架構的SledgeHammer核心的Opteron開始才支持SSE2指令集的。

Intel指令集中SSE3(Streaming SIMD Extensions 3,Intel官方稱為SIMD 流技術擴展 3或數據流單指令多數據擴展指令集 3)指令集是Intel公司在SSE2指令集的基礎上發展起來的。相比于SSE2,SSE3在SSE2的基礎上又增加了13個額外的SIMD指令。SSE3 中13個新指令的主要目的是改進線程同步和特定應用程序領域,例如媒體和游戲。這些新增指令強化了處理器在浮點轉換至整數、復雜算法、視頻編碼、SIMD浮點寄存器操作以及線程同步等五個方面的表現,最終達到提升多媒體和游戲性能的目的。Intel是從Prescott核心的Pentium 4開始支持SSE3指令集的,而AMD則是從2005年下半年Troy核心的Opteron開始才支持SSE3的。但是需要注意的是,AMD所支持的SSE3與Intel的SSE3并不完全相同,主要是刪除了針對Intel超線程技術優化的部分指令。

Intel指令集中SSE4 (Streaming SIMD Extensions 4) 是英特爾自從SSE2之后對ISA擴展指令集最大的一次的升級擴展。新指令集增強了從多媒體應用到高性能計算應用領域的性能,同時還利用一些專用電路實現對于特定應用加速。IntelSSE4 由一套全新指令構成,旨在提升一系列應用程序的性能和能效。Intel SSE4 構建于英特爾64指令集架構(Intel64 ) (ISA)。Intel SSE4 是英特爾與其獨立軟件開發商 (ISV) 團體精誠合作的成果,它可以支持開發人員輕松改進產品,同時保持必要的應用級兼容性,以適應處理器不斷迭代的需求。

2. 并行計算有哪些實現方式?

解:并行計算就是在并行計算或分布式計算機等高性能計算系統上所做的超級計算。實現方式有:單指令多數據流SIMD、對稱多處理機SMP、大規模并行處理機MPP、工作站機群COW、分布共享存儲DSM多處理機。

3. 彩色圖像、灰度圖像、二值圖像和索引圖像區別?

解:彩色圖像,每個像素通常是由紅(R)、綠(G)、藍(B)三個分量來表示的,分量介于(0,255)。RGB圖像與索引圖像一樣都可以用來表示彩色圖像。與索引圖像一樣,它分別用紅(R)、綠(G)、藍(B)三原色的組合來表示每個像素的顏色。但與索引圖像不同的是,RGB圖像每一個像素的顏色值(由RGB三原色表示)直接存放在圖像矩陣中,由于每一像素的顏色需由R、G、B三個分量來表示,M、N分別表示圖像的行列數,三個M x N的二維矩陣分別表示各個像素的R、G、B三個顏色分量。RGB圖像的數據類型一般為8位無符號整形,通常用于表示和存放真彩色圖像,當然也可以存放灰度圖像。

灰度圖像(gray image)是每個像素只有一個采樣顏色的圖像,這類圖像通常顯示為從最暗黑色到最亮的白色的灰度,盡管理論上這個采樣可以任何顏色的不同深淺,甚至可以是不同亮度上的不同顏色。灰度圖像與黑白圖像不同,在計算機圖像領域中黑白圖像只有黑色與白色兩種顏色;但是,灰度圖像在黑色與白色之間還有許多級的顏色深度。灰度圖像經常是在單個電磁波頻譜可見光內測量每個像素的亮度得到的,用于顯示的灰度圖像通常用每個采樣像素8位的非線性尺度來保存,這樣可以有256級灰度(如果用16位,則有65536級)。

二值圖像(binary image),即一幅二值圖像的二維矩陣僅由0、1兩個值構成,“0”代表黑色,“1”代白色。由于每一像素(矩陣中每一元素)取值僅有0、1兩種可能,所以計算機中二值圖像的數據類型通常為1個二進制位。二值圖像通常用于文字、線條圖的掃描識別(OCR)和掩膜圖像的存儲。

索引圖像即它的文件結構比較復雜,除了存放圖像的二維矩陣外,還包括一個稱之為顏色索引矩陣MAP的二維數組。MAP的大小由存放圖像的矩陣元素值域決定,如矩陣元素值域為[0,255],則MAP矩陣的大小為256Ⅹ3,用MAP=[RGB]表示。MAP中每一行的三個元素分別指定該行對應顏色的紅、綠、藍單色值,MAP中每一行對應圖像矩陣像素的一個灰度值,如某一像素的灰度值為64,則該像素就與MAP中的第64行建立了映射關系,該像素在屏幕上的實際顏色由第64行的[RGB]組合決定。也就是說,圖像在屏幕上顯示時,每一像素的顏色由存放在矩陣中該像素的灰度值作為索引通過檢索顏色索引矩陣MAP得到。索引圖像的數據類型一般為8位無符號整形(int8),相應索引矩陣MAP的大小為256Ⅹ3,因此一般索引圖像只能同時顯示256種顏色,但通過改變索引矩陣,顏色的類型可以調整。索引圖像的數據類型也可采用雙精度浮點型(double)。索引圖像一般用于存放色彩要求比較簡單的圖像,如Windows中色彩構成比較簡單的壁紙多采用索引圖像存放,如果圖像的色彩比較復雜,就要用到RGB真彩色圖像。

4. 常用邊緣檢測有哪些算子,各有什么特性?

解:常用邊緣檢測算子如下所述:

  • Sobel算子其主要用于邊緣檢測,在技術上它是以離散型的差分算子,用來運算圖像亮度函數的梯度的近似值,?Sobel算子是典型的基于一階導數的邊緣檢測算子,由于該算子中引入了類似局部平均的運算,因此對噪聲具有平滑作用,能很好的消除噪聲的影響。Sobel算子對于象素的位置的影響做了加權,與Prewitt算子、Roberts算子相比因此效果更好。Sobel算子包含兩組3x3的矩陣,分別為橫向及縱向模板,將之與圖像作平面卷積,即可分別得出橫向及縱向的亮度差分近似值。缺點是Sobel算子并沒有將圖像的主題與背景嚴格地區分開來,換言之就是Sobel算子并沒有基于圖像灰度進行處理,由于Sobel算子并沒有嚴格地模擬人的視覺生理特征,所以提取的圖像輪廓有時并不能令人滿意。

  • Isotropic Sobel算子 Sobel算子另一種形式是(Isotropic Sobel)算子,加權平均算子,權值反比于鄰點與中心點的距離,當沿不同方向檢測邊緣時梯度幅度一致,就是通常所說的各向同性Sobel(Isotropic Sobel)算子。模板也有兩個,一個是檢測水平邊沿的 ,另一個是檢測垂直平邊沿的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加權系數更為準確,在檢測不同方向的邊沿時梯度的幅度一致。
  • Roberts算子 羅伯茨算子、Roberts算子是一種最簡單的算子,是一種利用局部差分算子尋找邊緣的算子,他采用對角線方向相鄰兩象素之差近似梯度幅值檢測邊緣。檢測垂直邊緣的效果好于斜向邊緣,定位精度高,對噪聲敏感,無法抑制噪聲的影響。1963年,Roberts提出了這種尋找邊緣的算子。Roberts邊緣算子是一個2x2的模板,采用的是對角方向相鄰的兩個像素之差。從圖像處理的實際效果來看,邊緣定位較準,對噪聲敏感。適用于邊緣明顯且噪聲較少的圖像分割。Roberts邊緣檢測算子是一種利用局部差分算子尋找邊緣的算子,Robert算子圖像處理后結果邊緣不是很平滑。經分析,由于Robert算子通常會在圖像邊緣附近的區域內產生較寬的響應,故采用上述算子檢測的邊緣圖像常需做細化處理,邊緣定位的精度不是很高。
  • Prewitt算子 Prewitt算子是一種一階微分算子的邊緣檢測,利用像素點上下、左右鄰點的灰度差,在邊緣處達到極值檢測邊緣,去掉部分偽邊緣,對噪聲具有平滑作用 。其原理是在圖像空間利用兩個方向模板與圖像進行鄰域卷積來完成的,這兩個方向模板一個檢測水平邊緣,一個檢測垂直邊緣。經典Prewitt算子認為:凡灰度新值大于或等于閾值的像素點都是邊緣點。即選擇適當的閾值T,若P(i,j)≥T,則(i,j)為邊緣點,P(i,j)為邊緣圖像。這種判定是欠合理的,會造成邊緣點的誤判,因為許多噪聲點的灰度值也很大,而且對于幅值較小的邊緣點,其邊緣反而丟失了。Prewitt算子對噪聲有抑制作用,抑制噪聲的原理是通過像素平均,但是像素平均相當于對圖像的低通濾波,所以Prewitt算子對邊緣的定位不如Roberts算子。因為平均能減少或消除噪聲,Prewitt梯度算子法就是先求平均,再求差分來求梯度。該算子與Sobel算子類似,只是權值有所變化,但兩者實現起來功能還是有差距的,據經驗得知Sobel要比Prewitt更能準確檢測圖像邊緣
  • Laplacian算子Laplace算子是一種各向同性算子,二階微分算子,在只關心邊緣的位置而不考慮其周圍的象素灰度差值時比較合適。Laplace算子對孤立象素的響應要比對邊緣或線的響應要更強烈,因此只適用于無噪聲圖象。存在噪聲情況下,使用Laplacian算子檢測邊緣之前需要先進行低通濾波。所以,通常的分割算法都是把Laplacian算子和平滑算子結合起來生成一個新的模板。拉普拉斯算子也是最簡單的各向同性微分算子,具有旋轉不變性。一個二維圖像函數的拉普拉斯變換是各向同性的二階導數。拉式算子用來改善因擴散效應的模糊特別有效,因為它符合降制模型。擴散效應是成像過程中經常發生的現象。Laplacian算子一般不以其原始形式用于邊緣檢測,因為其作為一個二階導數,Laplacian算子對噪聲具有無法接受的敏感性;同時其幅值產生算邊緣,這是復雜的分割不希望有的結果;最后Laplacian算子不能檢測邊緣的方向;所以Laplacian在分割中所起的作用包括:(1)利用它的零交叉性質進行邊緣定位;(2)確定一個像素是在一條邊緣暗的一面還是亮的一面;一般使用的是高斯型拉普拉斯算子(Laplacian of a Gaussian,LoG),由于二階導數是線性運算,利用LoG卷積一幅圖像與首先使用高斯型平滑函數卷積改圖像,然后計算所得結果的拉普拉斯是一樣的。所以在LoG公式中使用高斯函數的目的就是對圖像進行平滑處理,使用Laplacian算子的目的是提供一幅用零交叉確定邊緣位置的圖像;圖像的平滑處理減少了噪聲的影響并且它的主要作用還是抵消由Laplacian算子的二階導數引起的逐漸增加的噪聲影響。
  • Canny算子Canny算子是一個具有濾波,增強,檢測的多階段的優化算子,在進行處理前,Canny算子先利用高斯平滑濾波器來平滑圖像以除去噪聲,Canny分割算法采用一階偏導的有限差分來計算梯度幅值和方向,在處理過程中,Canny算子還將經過一個非極大值抑制的過程,最后Canny算子還采用兩個閾值來連接邊緣。邊緣提取的基本問題是解決增強邊緣與抗噪能力間的矛盾,由于圖像邊緣和噪聲在頻率域中同是高頻分量,簡單的微分提取運算同樣會增加圖像中的噪聲,所以一般在微分運算之前應采取適當的平滑濾波,減少噪聲的影響。Canny運用嚴格的數學方法對此問題進行了分析,推導出由# 個指數函數線性組合形式的最佳邊緣提取算子網,其算法的實質是用一個準高斯函數作平滑運算,然后以帶方向的一階微分定位導數最大值,Canny算子邊緣檢測是一種比較實用的邊緣檢測算子,具有很好的邊緣檢測性能。Canny邊緣檢測法利用高斯函數的一階微分,它能在噪聲抑制和邊緣檢測之間取得較好的平衡。
  • Laplacian of Gaussian(LoG)算子 利用圖像強度二階導數的零交叉點來求邊緣點的算法對噪聲十分敏感,所以,希望在邊緣增強前濾除噪聲.為此,將高斯濾波和拉普拉斯邊緣檢測結合在一起,形成LoG(Laplacian of Gaussian, LoG)算法,也稱之為拉普拉斯高斯算法.LoG邊緣檢測器的基本特征是: 平滑濾波器是高斯濾波器.增強步驟采用二階導數(二維拉普拉斯函數).邊緣檢測判據是二階導數零交叉點并對應一階導數的較大峰值.使用線性內插方法在子像素分辨率水平上估計邊緣的位置.這種方法的特點是圖像首先與高斯濾波器進行卷積,這一步既平滑了圖像又降低了噪聲,孤立的噪聲點和較小的結構組織將被濾除.由于平滑會導致邊緣的延展,因此邊緣檢測器只考慮那些具有局部梯度最大值的點為邊緣點.這一點可以用二階導數的零交叉點來實現.拉普拉斯函數用作二維二階導數的近似,是因為它是一種無方向算子.為了避免檢測出非顯著邊緣,應選擇一階導數大于某一閾值的零交叉點作為邊緣點.
  • 5.? 簡述BP神經網絡,AdBoost的基本原理

    解:BP神經網絡模型處理信息的基本原理是:輸入信號Xi通過中間節點(隱層點)作用于輸出節點,經過非線形變換,產生輸出信號Yk,網絡訓練的每個樣本包括輸入向量X和期望輸出量t,網絡輸出值Y與期望輸出值t之間的偏差,通過調整輸入節點與隱層節點的聯接強度取值Wij和隱層節點與輸出節點之間的聯接強度Tjk以及閾值,使誤差沿梯度方向下降,經過反復學習訓練,確定與最小誤差相對應的網絡參數(權值和閾值),訓練即告停止。此時經過訓練的神經網絡即能對類似樣本的輸入信息,自行處理輸出誤差最小的經過非線形轉換的信息。

    AdBoost是一個廣泛使用的BOOSTING算法,其中訓練集上依次訓練弱分類器,每次下一個弱分類器是在訓練樣本的不同權重集合上訓練。權重是由每個樣本分類的難度確定的。分類的難度是通過分類器的輸出估計的。

    C/C++部分

    1.? 關鍵字static的作用是什么?

    解:1)在函數體,一個被聲明為靜態的變量在這一函數被調用過程中維持其值不變。2)在模塊內(但在函數體外),一個被聲明為靜態的變量可以被模塊內所用函數訪問,但不能被模塊外其它函數,它是一個本地的全局變量。3)在模塊內,一個被聲明為靜態的函數只可被這一模塊的它函數調用。那就是,這個函數被限制在聲明它的模塊的本地范圍內使用。

    2. 嵌入式系統總是用戶對變量或寄存器進行位操作。給定一個整型變量a,寫兩段代碼,第一個設置a的bit3,第二消除a的 bit 3。在以上兩個操作中,要保持其它位不變.

    解:

    #define BIT3(0x1<<3) static int a; void set_bit3(void) {a|=BIT3; } void clear_bits(void) {a&=~BIT3; }

    3. 簡述C,C++程序編譯的內存分配情況?

    解:C,C++中內存分配方式可以分為三種:

  • 從靜態存儲區域分配:內存在程序編譯時就已經分配好,這塊內存在程序的整個運行期間都存在。速度快,不容易出錯,因有系統自行管理。
  • 在棧上分配:在執行函數時,函數內局部變量的存儲單元都在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置于處理器的指令集中,效率很高,但是分配的內存容量有限。
  • 從堆上分配:即運態內存分配。程序在運行時候用malloc或new申請任意大小的內存,程序員自己負責在何進用free 和delete釋放內存。
  • 一個C、C++程序編譯時內存分為5大存儲區:堆區、棧區、全局區、文字常量區和程序代碼區。

    4. 給定一個矩陣intmaxtrixA[m][n],每行和每列都是增序的,實現一個算法去找矩陣中的某個元素element.

    解:方法一:

    #include<iostream> using namespace std; const int M = 4; const int N = 4; int main { int matrix[M][N] = {}; double element; int flag = 1; for(int j=0; j<N; j++) { if(matrix[i][j] == element) cout<<"位置"<<endl; while( flag<M && matrix[i][j]<element ) --flag; while( flag<M && matrix[i][j]>element ) ++flag; } } 方法二:

    bool Find(int *matrixA, int m, int n, int element) { bool found = false; if(matrixA != NULL & m & n) { int i,j; i=0;j=n-1; while(i<m;j>=0) { if(maxtrixA[i*n+j] == element) { found = true; break; } else if(matrix[i*n+j]>element --j; else ++i } } }

    5. 從1到500的500個數,第一次刪除奇數位,第二次刪除剩下來的奇數位,以此類推,最后剩下的唯一一位數是什么?

    解:比如:1,2,刪除奇數位,那剩下的是2,1,2,3,刪除奇數位,剩下的是2,1,2,3,4,剩下的是4,1,2,3,4,5,6,7,剩下的是4,1,2,3,4,5,6,7,8 和1,2,3,4,5,6,7,8,9,10,11,12,13,14,15剩下的是8,這里有什么規律:就是當1~n,2^i<n<2^(i+1)時候,這樣刪除剩下的是2^i。2^8<500<2^9,所以剩下的就是2^8=256。

    6. 給出了一個n*n的矩形,編程求從左上角到右下角的路徑數(n > =2),限制只能向右或向下移動,不能回退。例如當n=2時,有6條路徑。

    解:一是利用數學知識,從左上角到右下角總共要走2n步,其中橫向要走n步,所以總共就是C2n~n。二是利用遞歸實現

    int getTotalPath(int m, int n) { if(m == 1) return n + 1; if(n == 1) return m + 1; return getTotalPath(m-1, n) + getTotalPath(m, n-1); }

    7. 給出一棵二叉樹的前序和中序遍歷,輸出后續遍歷的結果,假設二叉樹中存儲的均是ASCII碼。如前序:ABDHECFG,中序:HDBEAFCG,則輸出后序為:HDECFGCA,改正為:HDECFGBA,再次改正HDEBFGCA。

    解:先利用前序和中序構建出二叉樹,然后后序遍歷輸出結果

    Node* getBinaryTree(char* preOrder, char* inOrder, int len) { if(preOrder == NULL || *preOrder == '\0' || len<=0) return NULL; Node* root = (Node*) malloc(sizeof(Node)); if(root == NULL) exit(EXIT_FAILURE); root->data = *preOrder; int pos = 0; while(true) { if(*(inOrder+pos) == root->data) break; pos++; } if(pos == 0) root->lchild = NULL; else root->lchild = getBinaryTree(preOrder+1, inOrder, pos); if(len-pos-1 == 0) root->rchild = NULL; else root->rchild = getBinaryTree(preOrder+pos+1, inOrder+pos+1,len-pos-1); return root; } void postOrder(Node* root) { if(root == NULL) return; postOrder(root->lchild); postOrder(root->rchild); printf("%c", root->data); } void printPostOrderViaPreOrderAndInorder(char* preOrder, char* inOrder) { Node* root = getBinaryTree(preOrder, inOrder, strlen(preOrder)); postOrder(root); }

    8.自定義實現字符串轉為整數的算法,例如把“123456”轉成整數123456.(輸入中可能存在符號,和數字)

    解:

    enum Status {VALID,IN_VALID}; int gStatus = VALID; int strToInt(const char* str) { long long result = 0; gStatus = IN_VALID; if(str != NULL) { const char* digit = str; bool minus = false; if(*digit == '+') digit++; else if(*digit == '-'){ digit++; minus = true; } while(*digit != '\0') { if(*digit >= '0' && *digit <= '9'){ result = result * 10 + (*digit -'0'); if(result > std::numeric_limits<int>::max()){ result = 0; break; } digit++; } else { result = 0; break; } } if(*digit == '\0'){ gStatus = VALID; if(minus) result = 0 - result; } } return static_cast<int>(result); }

    9. 求2個字符串最長公共部分

    解:方法一:2個循環,遍歷2個字符串,這里記得要回溯,2個字符串都要有,否則,找不出來正確的結果。

    int main(){char a[80],b[80],c[80],d[500][80]; memset(c, 0, 80);int i,j,m,n,t,k; gets(a); gets(b);//輸入字符串 puts(a); puts(b);//輸出字符串 m=strlen(a); n=strlen(b);//計算字符串實際長度 int nFlag = 0;k = 0;int nTemp = 0;for(i=0;i<m;i++){nFlag = 0;t=0; nTemp = i;for(j=0;j<n;j++){ if(a[i]==b[j]){ nFlag = 1; c[t]=a[i]; t=t+1; i=i+1; //j=j+1; }else{if (nFlag == 1){strcpy(d[k++], c);memset(c, 0, 80);nFlag = 0;t=0;i = nTemp;j=j-1;}}} if (nFlag == 1){strcpy(d[k++], c);memset(c, 0, 80);i = nTemp;}}strcpy(c,d[0]);for(i=1;i<k-1;i++){ if(strlen(c)<strlen(d[i])) strcpy(c,d[i]);//如果d[i]字符串長度比c長就把d[i]中的字符串復制給c } puts(c); return 0; } 方法二

    //最長公共子序列字符個數 //c[i][j]保存字符串 {xi},{yj},(長度分別為i,j)的最長公共子序列的字符個數 //i=0或者是j=0 時,c[i][j]必定為零, i,j>=0 且 xi=yj, c[i][j]=c[i-1][j-1]+1 //若 i,j>0 但xi!=yj, c[i][j]=max{ c[i-1][j] , c[i][j-1] } #include <stdio.h> #include <string.h> int c[1001][1001]; void lcs(int a, int b, char x[], char y[], int c[][1001]){ int i,j; for(i=1;i<a;i++) c[i][0]=0; //if b==0, set c[i][j]=0; for(i=1;i<b;i++) c[0][i]=0; // if a==0; set c[i][j]=0; for(i=1;i<=a;i++) // if a!=0,b!=0 loop for(j=1;j<=b;j++){ if(x[i-1]==y[j-1]) c[i][j]=c[i-1][j-1]+1; else if (c[i-1][j]>=c[i][j-1]) c[i][j]=c[i-1][j]; else c[i][j]=c[i][j-1]; } } int main() { char x[1001],y[1001]; while ( scanf("%s%s",x,y)!=EOF ){ int a=strlen(x); int b=strlen(y); memset(c,0,sizeof(c));lcs(a,b,x,y,c);printf("%d\n",c[a][b]);} return 0; }

    10.請實現一個函數:最長順子。輸入很多個整數(1<=數值<=13),返回其中可能組成的最長的一個順子(順子中數的個數代表順的長度); 其中數字1也可以代表14;

    順子包括單順\雙順\3順;單順的定義是連續5個及以上連續的數,比如1,2,3,4,5、3,4,5,6,7,8和10,11,12,13,1等; 雙順的定義是連續3個及以上連續的對(對:兩個相同的數被稱為對),比如1,1,2,2,3,3、4,4,5,5,6,6,7,7和11,11,12,12,13,13,1,1等; 3順的定義是連續2個及以上連續的3張(3張:3個相同的數被稱為3張),比如1,1,1,2,2,2、3,3,3,4,4,4,5,5,5,6,6,6和13,13,13,1,1,1等等;比如:輸入數組[1,5,2,3,4,4,5,9,6,7,2,3,3,4], 輸出數組[2,2,3,3,4,4,5,5]。

    解:實現代碼如下:

    int putList(int k, map<int, map<int, int>* >& listData, map<int, int>* mapData){ int nFlag =0;if (0 == k && mapData->size() >= 5){ nFlag =1;//listData.put(mapData.size(), mapData); listData.insert(pair <int, map<int, int>* >( mapData->size(), mapData));} if (1 == k && mapData->size() >= 3){ nFlag =1;//listData.put(2 * mapData.size(), mapData); listData.insert(pair <int, map<int, int>* >(2* mapData->size(), mapData));} if (2 == k && mapData->size() >= 2){ nFlag =1 ;//listData.put(3 * mapData.size(), mapData); listData.insert(pair <int, map<int, int>* >( 3*mapData->size(), mapData));} return nFlag; }map<int, int>* getList(int* count, int k, int num, int& nMaxCount){ map<int, map<int, int>* > listData;//= new map<int, map<int, int>*>(); map<int, int>* mapTemp = NULL; int flag = 0; int nRet = 0;for (int i = 1; i < num; i++){ if (count[i] > k && flag == 0){ flag = 1; mapTemp = new map<int, int>;//mapTemp.put(i, count[i]); mapTemp->insert(pair <int, int>( i, count[i]));} else if (count[i] > k && flag == 1) { //mapTemp.put(i, count[i]); mapTemp->insert(pair <int, int>( i, count[i]));if (13 == i){ if (count[14 - i] > k) { //mapTemp.put(14 - i, count[14 - i]); mapTemp->insert(pair <int, int>( 14 - i, count[14 - i]));nRet = putList(k, listData, mapTemp); if (nRet==0){delete mapTemp;mapTemp = NULL;}} else { flag = 0; nRet=putList(k, listData, mapTemp); if (nRet==0){delete mapTemp;mapTemp = NULL;}} } } else if (count[i] <= k && flag == 1){ flag = 0; nRet=putList(k, listData, mapTemp); if (nRet==0){delete mapTemp;mapTemp = NULL;}} } if (listData.size() > 0){listData.rend();map<int, map<int, int>* >::iterator it = listData.begin();nMaxCount = (*it).first;map<int, int>* mapReturn = (*it).second;map<int, int>* maptemp;it++;for (; it!=listData.end(); it++){maptemp = (*it).second;delete maptemp;maptemp = NULL;}return mapReturn;}else return NULL; } int* GetLongeststr(int* array, int nCount, int& outCount, int MaxNum){int* count = new int[MaxNum+1]; memset(count, 0, MaxNum*sizeof(int));int nMaxLoop=0;int nMaxTemp;int nMax1Loop=0;int nMax2Loop=0;int nMax3Loop=0;int nMaxkey =0;for (int i = 0; i < nCount; i++){ if (array[i] < 1 || array[i] > MaxNum) return NULL; ++count[array[i]];}map<int, map<int, int>*> allList;map<int, int>* mapTemp = NULL; map<int, int>* map1Temp = NULL;map<int, int>* map2Temp = NULL;map<int, int>* map3Temp = NULL;for (int k = 0; k < 3; k++){ mapTemp = getList(count, k, MaxNum, nMaxTemp);if (NULL != mapTemp){ if (0 == k) {map1Temp = mapTemp;nMax1Loop = nMaxTemp;nMaxLoop=nMaxTemp;}else if (1 == k){if (nMaxTemp>=nMaxLoop) {map2Temp = mapTemp;nMax2Loop = nMaxTemp;nMaxLoop = nMaxTemp;}else{delete mapTemp;mapTemp =NULL;}}else{if (nMaxTemp>=nMaxLoop) {map3Temp = mapTemp;nMax3Loop = nMaxTemp;nMaxLoop = nMaxTemp;}else{delete mapTemp;mapTemp =NULL;}}} }delete[] count;count = NULL;if (nMaxLoop>0) {if (nMaxLoop == nMax3Loop){nMaxkey = 3;mapTemp = map3Temp;}else if (nMaxLoop == nMax2Loop) {nMaxkey = 2;mapTemp = map2Temp;}else{nMaxkey = 1;mapTemp = map1Temp;}outCount = nMaxLoop;int* result = new int[outCount]; int k; int nAllCount = 0;map<int, int>::iterator itorResult;for (itorResult = mapTemp->begin(); itorResult!=mapTemp->end(); itorResult++){k = itorResult->first;for (int j =0; j<nMaxkey; j++){ result[nAllCount++] = k; cout << itorResult->first <<",";}}cout << endl;if (map1Temp!=NULL){delete map1Temp;map1Temp = NULL;}if (map2Temp!=NULL){delete map2Temp;map2Temp = NULL;}if (map3Temp!=NULL){delete map3Temp;map3Temp = NULL;}return result;}else {outCount = 0;return NULL;} }


    關于Image Engineering & Computer Vision的更多討論與交流,敬請關注本博和新浪微博songzi_tea.


    總結

    以上是生活随笔為你收集整理的图像处理职位面试题汇总(1)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。