版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
第12章圖像特征的提取與分析圖像特征提取與分析什么是特征:特征是某一類對象區(qū)別于其他類對象的相應(yīng)(本質(zhì))特點或特性,或是這些特點和特性的集合。特征是通過測量或處理能夠抽取的數(shù)據(jù)。什么是圖像特征:對于圖像而言,每一幅圖像都具有能夠區(qū)別于其他類圖像的自身特征,有些是可以直觀地感受到的自然特征,如亮度、邊緣、紋理和色彩等;有些則是需要通過變換或處理才能得到的,如矩、直方圖以及主成份等。圖像特征提取和表達技術(shù)是將分割后的目標(biāo)轉(zhuǎn)換成為能較好地描述圖像主要特征和屬性的技術(shù),以便進一步進行圖像的識別和分類等。特征提取是對一幅圖像中的某些感興趣的特征進行檢測和描述,是計算機視覺和圖像處理中的關(guān)鍵步驟,提取的圖像特征既可以是自然特征,也可以是通過圖像處理和測量獲得的某些特征。目錄CONTENTS圖像特征簡介01圖像輪廓特征02圖像幾何特征03圖像特征矩04圖像角點檢測05圖像匹配06綜合實例0712.1圖像特征簡介圖像特征簡介圖像特征主要有圖像的顏色特征、紋理特征、形狀特征和空間關(guān)系特征。顏色特征是一種全局特征,描述了圖像或圖像區(qū)域所對應(yīng)景物的表面性質(zhì)。紋理特征也是一種全局特征,它也描述了圖像或圖像區(qū)域所對應(yīng)景物的表面性質(zhì)。圖像形狀特征有輪廓特征和區(qū)域特征兩類,其中圖像的輪廓特征主要針對物體的外邊界,而圖像的區(qū)域特征則關(guān)系到整個形狀區(qū)域。圖像空間關(guān)系是指圖像中分割出來的多個目標(biāo)之間的相互的空間位置或相對方向關(guān)系,這些關(guān)系包含連接/鄰接關(guān)系、交疊/重疊關(guān)系和包含/包容關(guān)系等??臻g位置信息又可以分為相對空間位置信息和絕對空間位置信息兩類,其中前一種關(guān)系強調(diào)的是目標(biāo)之間的相對情況,如上下左右關(guān)系等,后一種關(guān)系強調(diào)的是目標(biāo)之間的距離大小以及方位。圖像特征簡介(1)邊界特征法邊界特征法通過對邊界特征的描述來獲取圖像的形狀參數(shù)。其中Hough變換檢測平行直線方法和邊界方向直方圖方法是經(jīng)典方法。Hough變換是利用圖像全局特性而將邊緣像素連接起來,組成區(qū)域封閉邊界的一種方法,其基本思想是點—線的對偶性;邊界方向直方圖法利用微分圖像求得圖像邊緣,構(gòu)造圖像灰度梯度方向矩陣。(2)傅里葉形狀描述符法傅里葉形狀描述符是用物體邊界的傅里葉變換作為形狀描述,利用區(qū)域邊界的封閉性和周期性,將二維問題轉(zhuǎn)化為一維問題,由邊界點導(dǎo)出曲率函數(shù)、質(zhì)心距離、復(fù)坐標(biāo)函數(shù)三種形狀表達形式。圖像的形狀特征(輪廓特征和區(qū)域特征)常用的特征描述方法有:圖像特征簡介(3)幾何參數(shù)法幾何參數(shù)法中形狀的表達和匹配采用有關(guān)形狀定量測量,如面積、周長、矩等的形狀參數(shù)法。(4)形狀不變矩法利用目標(biāo)所占區(qū)域的矩作為形狀描述參數(shù)。(5)其它方法近年來,在圖像形狀的表示和匹配方面的還出現(xiàn)了有限元法(FiniteElementMethod或FEM)、旋轉(zhuǎn)函數(shù)(Turning)和小波描述符(Waveletdescriptors)等方法。12.2圖像輪廓特征圖像輪廓特征輪廓是圖像中一系列連續(xù)的像素點沿著邊界連接在一起的曲線,這些像素有相同的顏色或者灰度,這些連接在一起的曲線,代表了物體的基本外形。輪廓在形狀分析和物體檢測和識別上有著重要的應(yīng)用,它與邊緣的區(qū)別是:(1)輪廓是連續(xù)的,邊緣并不全都連續(xù);(2)邊緣主要作為圖像中物體特征,而輪廓主要用來分析物體的形態(tài),如周長和面積等;(3)邊緣包括輪廓。一般在二值圖像中尋找輪廓,要進行閾值化處理或者Canny邊緣檢測,尋找輪廓是針對白色物體,即物體是白色,而背景是黑色。1.圖像輪廓的查找和繪制OpenCV中查找圖像輪廓函數(shù)是cv2.findContours(),其語法格式為:contours,hierarchy=cv2.findContours(image,mode,method[,contours[,hierarchy[,offset]]])其中函數(shù)輸入?yún)?shù)有三個:第一個參數(shù)是輸入源圖像image,8位單通道二值圖像,可以使用比較、閾值、自適應(yīng)閾值、Canny和其他方法從灰度或彩色圖像中獲得二值圖像。第二個參數(shù)mode,輪廓檢索模式,通常使用RETR_TREE找出所有的輪廓值。mode輪廓檢索模式如下表所示,mode輪廓檢索模式RETR_EXTERNAL只檢索最外面的輪廓RETR_LIST檢索所有的輪廓,并將其保存到一個list鏈表中RETR_CCOMP檢索所有的輪廓,并將他們組織為兩層的層次結(jié)構(gòu):頂層為連通域的外部邊界,次層為空洞的內(nèi)層邊界RETR_TREE檢索所有的輪廓,并重構(gòu)嵌套輪廓的整個層次第三個參數(shù)method,是輪廓近似方法,有如下4種方法:
cv2.CHAIN_APPROX_NONE:存儲所有邊界點,顯示所有輪廓;
cv2.CHAIN_APPROX_SIMPLE:壓縮垂直、水平、對角方向,只保留端點;
cv2.CHAIN_APPROX_TX89_L1:使用teh-Chinl近似算法;
cv2.CHAIN_APPROX_TC89_KCOS:使用teh-Chinlchain近似算法。第四個參數(shù)offset,每一個輪廓點的偏移量。當(dāng)輪廓是從圖像ROI中提取出來的時候,使用偏移量有用,因為可以從整個圖像上下文來對輪廓做分析。函數(shù)輸出參數(shù)有二個:第一個輸出參數(shù)contours為檢測到的輪廓,存儲輪廓點的矢量。第二個輸出參數(shù)hierarchy為層次結(jié)構(gòu),可選輸出向量,包含有關(guān)圖像拓?fù)涞男畔?。返回的純輪廓是一個python的列表,此處存儲所有圖像中的輪廓,每一個輪廓都是numpy數(shù)組,包含檢測物體的邊界點。圖像繪制輪廓函數(shù)是cv2.drawContours(),可根據(jù)用戶提供的邊界點繪制任何形狀的輪廓,其語法格式為:cv2.drawCountours(img,contours,-1,(0,0,255),2)其中,第一個輸入?yún)?shù)img表示輸入的源圖像;第二個輸入?yún)?shù)contours表示通過python列表傳遞的輪廓值(列表);第三個輸入?yún)?shù)表示輪廓索引,即繪制第幾個輪廓,-1代表繪制所有的輪廓;第四個輸入?yún)?shù)表示輪廓顏色,用RGB(0,0,255)表示顏色;第五個輸入?yún)?shù)輪廓線條粗細。常用的圖像繪制輪廓輸出格式有三種:(1)在圖像中繪制所有輪廓:cv2.drawCountours(img,contours,-1,(0,0,255),3)(2)繪制單個輪廓,如第三個輪廓:cv2.drawCountours(img,contours,2,(0,0,255),3)(3)多數(shù)情況下使用以下方式:cnt=contours[3]cv2.drawCountours(img,[cnt],0,(0,0,255),3)例12.1在圖像中查找并繪制所有輪廓,程序代碼如下:importcv2#第一步讀入圖像,并顯示img=cv2.imread('D:/pics/logo7.jpg')cv2.imshow('Originalimage',img)#第二步:對圖像做灰度變化gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#第三步:對圖像做二值變化ret,thresh=cv2.threshold(gray,50,135,cv2.THRESH_BINARY)#第四步:獲得圖像的輪廓值contours,h=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)#第五步:在圖像中用黃色畫出圖像的輪廓draw_img=img.copy()ret=cv2.drawContours(draw_img,contours,-1,(0,255,255),2)#第六步:畫出帶有輪廓的原始圖像cv2.imshow('Contourimage',ret)cv2.waitKey(0)cv2.destroyAllWindows()程序運行輸出結(jié)果如圖所示。(a)原圖像(b)繪制輪廓后的圖像圖像輪廓的查找與繪制12.2.2.帶噪聲的輪廓在進行圖像輪廓查找時,如果圖像上有噪聲需要預(yù)先進行均值濾波、中值濾波或高斯濾波,或腐蝕后,再進行尋找輪廓和繪制輪廓。如果圖像背景灰度值為純白色,輪廓檢測后效果不是很好,這時就需要將閾值二值化方法函數(shù)中位置參數(shù)取反,即cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV|cv2.THRESH_TRIANGLE)例12.2在帶有噪聲的圖像中繪制所有輪廓,程序代碼如下:importcv2img=cv2.imread('d:/pics/coins1.jpg',1)#防止隨機噪聲影響效果,首先對原圖高斯濾波dst=cv2.GaussianBlur(img,(3,3),0)cv2.imshow("Originalimage",img)#將原圖像轉(zhuǎn)換為灰度圖像gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#圖像利用閾值化進行二值化ret,binary=cv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_TRIANGLE)cv2.imshow("Binaryimage",binary)#二值圖像中有噪聲點,腐蝕掉kernel=cv2.getStructuringElement(cv2.MORPH_RECT,(2,2))binary_ero=cv2.erode(binary,kernel)cv2.imshow("Binaryerodeimage",binary_ero)#在二值化圖像的基礎(chǔ)上進行尋找輪廓contours,heriachy=cv2.findContours(binary_ero,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#循環(huán)繪制出所有的輪廓fori,contourinenumerate(contours):#將最后一個參數(shù)修改為-1即為填充。
cv2.drawContours(img,contours,i,(255,0,255),2,-1)cv2.imshow("Contoursimage",img)cv2.waitKey(0)cv2.destroyAllWindows()程序運行輸出結(jié)果如圖所示。(a)原圖像(b)二值圖像(c)腐蝕后圖像(d)帶輪廓的圖像硬幣輪廓圖像12.3.邊緣檢測后的輪廓前面我們使用閾值函數(shù)cv2.threshold()處理圖像得到二值圖,我們也可以使用邊緣檢測的方法先把邊緣檢測出來,再繪制出目標(biāo)的輪廓,其中使用cv2.Canny()算子進行邊緣檢測,效果最好。例12.3
Canny邊緣檢測后繪制圖像的輪廓,程序代碼如下:importcv2img=cv2.imread('d:/pics/rice.png',1)cv2.imshow("Originalimage",img)blurred=cv2.GaussianBlur(img,(3,3),0)gray=cv2.cvtColor(blurred,cv2.COLOR_RGB2GRAY)edge_output=cv2.Canny(gray,220,250)cv2.imshow("CannyEdge",edge_output)contours,hierarchy=cv2.findContours(edge_output,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)fori,contourinenumerate(contours):cv2.drawContours(img,contours,-1,(0,0,255),1)cv2.imshow('Outputimage',img)cv2.waitKey(0)cv2.destroyAllWindows()(a)原圖像 (b)Canny邊緣圖像 (c)輪廓圖像輸出結(jié)果如圖所示。Canny邊緣檢測后的輪廓12.3圖像幾何特征圖像幾何特征圖像的幾何特征是指圖像中物體的面積位置、周長、長軸與短軸、距離等方面的特征。雖然幾何特征比較直觀和簡單,但在許多圖像目標(biāo)分析、圖像分類、模式識別中發(fā)揮著重要作用。圖像的幾何形狀參數(shù)的提取,必須以圖像處理及圖像分割為前提,參數(shù)的準(zhǔn)確性受到分割效果的影響,對分割效果很差的圖像,形狀參數(shù)甚至無法提取。12.3.1面積與周長1.面積面積指的是輪廓內(nèi)包含的所有像素的個數(shù),常用的計算輪廓的面積函數(shù)語法格式為:area=cv2.contourArea(cnt,True)其中,第一個參數(shù)cnt為輸入的單個輪廓值,第二參數(shù)用來指定對象的形狀是閉合輪廓(True),還是曲線。2.周長周長指的是輪廓像素點總數(shù),也常用各個像素點的中點連線的多邊形長度進行度量,常用的計算輪廓周長的函數(shù)語法格式為:perimeter=cv2.arcLength(cnt,True)其中,第一個參數(shù)cnt為輸入的單個輪廓值,第二參數(shù)用來指定對象的形狀是閉合輪廓(True),還是曲線。使用cv2.findCountor獲得的輪廓contours是一個嵌套的類型,即我們可以通過cnt=contours[0]獲得第一個物體的輪廓值,并計算出輪廓面積和周長等,其步驟如下:(1)載入圖像,做灰度值和二值化處理,并使用cv2.findCountor找出輪廓值,使用cv2.drawCountors畫出第一個圖像的輪廓。(2)通過索引取出第一個輪廓值cnt,使用cv2.ContourArea()計算輪廓的面積。(3)使用cv2.arcLength獲得輪廓的周長。
例12.4求六邊形圖像的輪廓、面積和周長,程序代碼如下:importcv2img=cv2.imread('D:/pics/contour1.png')gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)cv2.imshow(‘original’,gray)ret,thresh=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)contours,h=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)draw_img=img.copy()ret=cv2.drawContours(draw_img,contours,0,(0,0,255),2)cnt=contours[0]#取出單個的輪廓值area=cv2.contourArea(cnt)#計算輪廓的面積length=cv2.arcLength(cnt,True)#計算輪廓的周長print('Area=',area,'Length=',length)cv2.imshow('ret',ret)cv2.waitKey(0)cv2.destroyAllWindows()圖像的面積和周長程序運行輸出結(jié)果如圖所示。圖中左邊圖為原圖形,右邊為有輪廓標(biāo)記的圖形。輸出的面積和周長為:Area=5626.0Length=292.4507913589477512.3.2外接矩形有兩種類型的邊界外接矩形:直角矩形和旋轉(zhuǎn)矩形。1.直角矩形:取輪廓點集最上面的點、最下面的點、最左邊的點和最右邊的點作為外接矩形的四個點的坐標(biāo),形成的矩形不一定是最小外接矩形,其邊與坐標(biāo)軸平行或者垂直。獲得外接矩形數(shù)據(jù)點的函數(shù)語法格式為:x,y,w,h=cv2.boundingRect(cnt)其中,輸出參數(shù)x、y、w、h分別表示外接矩形的x軸和y軸的坐標(biāo),以及矩形的寬和高,(x,y)為矩形左上角的坐標(biāo),(w,h)是矩形的寬和高。輸入?yún)?shù)cnt表示輸入的輪廓值。根據(jù)函數(shù)cv2.boundingRect()獲得的坐標(biāo)值,在圖像上畫出矩形的函數(shù)語法格式為:img=cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)其中輸入?yún)?shù)img表示傳入的圖像,(x,y)表示矩形左上角的坐標(biāo)位置,(x+w,y+h)表示矩形右下角的坐標(biāo)位置,(0,255,0)表示顏色,2表示線條的粗細。2.旋轉(zhuǎn)矩形:由上述cv2.boundingRect()和cv2.rectangle()2個函數(shù)畫出的矩形不一定是最小面積的矩形,要想獲得最小外接矩形,就要考慮矩形的旋轉(zhuǎn)。求解最小外接矩形的方法就是將圖像沿逆時針或者順時針按照一定的度數(shù)進行旋轉(zhuǎn),每旋轉(zhuǎn)一次,求解一次輪廓的外接矩形的面積,記錄每次旋轉(zhuǎn)的角度、左上角點坐標(biāo)、矩形長和寬,根據(jù)三角函數(shù)可以得到旋轉(zhuǎn)后的角點坐標(biāo),等旋轉(zhuǎn)完成一圈后,取面積最小的即為最小外接矩形。使用的函數(shù)語法格式是:min_rect=cv2.minAreaRect(cnt)其中,輸入?yún)?shù)cnt就是輪廓的點集。返回的是一個Box2D結(jié)構(gòu),其中包含矩形左上角的坐標(biāo)(x,y),矩形的寬和高(w,h),以及旋轉(zhuǎn)角度θ,即min_rect=((x,y),(h,w),θ)要繪制這個矩形通過函數(shù)cv2.boxPoints()實現(xiàn),其具體實現(xiàn)程序代碼為:rect=cv2.minAreaRect(cnt)box=cv2.boxPoints(rect)box=0(box)cv2.drawContours(img,[box],0,(0,0,255),2)
例12.5求圖形輪廓的外接直角矩形和旋轉(zhuǎn)矩形,程序代碼如下:importcv2importnumpyasnpimg=cv2.imread('D:/pics/contour3.png')gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret,thresh=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)contours,h=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)draw_img=img.copy()#畫出原始圖像的輪廓ret=cv2.drawContours(draw_img,contours,0,(0,0,255),2)cnt=contours[0]#取出單個的輪廓值#根據(jù)坐標(biāo)在圖像上畫出直角矩形x,y,w,h=cv2.boundingRect(cnt)#獲得外接矩形img_rect=cv2.rectangle(draw_img,(x,y),(x+w,y+h),(0,255,255),2)#根據(jù)坐標(biāo)在圖像上畫出旋轉(zhuǎn)矩形rect=cv2.minAreaRect(cnt)#獲取最小外接矩陣,中心點坐標(biāo),寬高,旋轉(zhuǎn)角度#獲取矩形四個頂點,浮點型box=cv2.boxPoints(rect)box=0(box)min_rect=cv2.drawContours(ret,[box],0,(0,255,0),2)cv2.imshow('Rectangles',min_rect)cv2.waitKey(0)cv2.destroyAllWindows()圖形的外接直角矩形和旋轉(zhuǎn)矩形程序運行輸出結(jié)果如圖所示。兩個矩形都顯示在一張圖像中,其中黃色矩形為外接直角矩形,綠色矩形是最小外接旋轉(zhuǎn)矩形。12.3.3最小外接圓和橢圓1. 最小外接圓最小外接圓是一個以最小面積完全覆蓋物體的圓,使用函數(shù)cv2.minEnclosingCircle()查找圖像輪廓外接圓的位置信息,獲得外接圓的坐標(biāo)和半徑。函數(shù)語法格式如下:(x,y),radius=cv2.minEnclosingCircle(cnt)其中輸出參數(shù)(x,y)表示外接圓的圓心坐標(biāo),radius表示外接圓的半徑,輸入?yún)?shù)cnt表示圖像的輪廓。根據(jù)給定的圓心和半徑,利用函數(shù)cv2.circle()畫出外接圓。其函數(shù)語法格式為:cv2.circle(img,center,radius,color[,thickness[,lineType[,shift]]])其中,輸入?yún)?shù)如下:
img:輸入的圖形;
center:圓心位置;
radius:圓的半徑;
color:圓的顏色;thickness:圓形輪廓的粗細(為正)。負(fù)厚度表示要繪制實心圓;lineType:圓邊界的類型;shift:中心坐標(biāo)和半徑值中的小數(shù)位數(shù)。2. 內(nèi)接橢圓OpenCV中通過最小二乘法把一個橢圓擬合到一個物體上,其橢圓就是旋轉(zhuǎn)矩形的內(nèi)切圓。函數(shù)fitEllipse語法格式為:ellipse=cv2.fitEllipse(cnt)其中輸入?yún)?shù)cnt類型是numpy.array([[x,y],[x1,y1]...]),并不是把所有點都包括在橢圓里面,而是擬合出一個橢圓盡量使得點都在圓上。輸出參數(shù)ellipse是橢圓長短軸的長度。使用cv2.ellipse來畫橢圓,其函數(shù)語法格式為:cv2.ellipse(img,center,axes,angle,startAngle,endAngle,color[,thickness[,lineType[,shift]]])其中輸入輸出參數(shù)如下:
Img:圖像;
center:中心坐標(biāo);
axes:橢圓的尺寸(長短軸);
angle:旋轉(zhuǎn)角度;startAngle:起始角度;endAngle:終止角度。后面參數(shù)都是跟線條有關(guān)的。
例12.6求圖形輪廓的最小外接圓和內(nèi)接橢圓,程序代碼如下:importcv2importnumpyasnpimg=cv2.imread('D:/pics/contour3.png')gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret,thresh=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)contours,h=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)#畫出圖像的輪廓draw_img=img.copy()ret=cv2.drawContours(draw_img,contours,0,(0,0,255),2)#取出單個的輪廓值cnt=contours[0]#獲得輪廓外接圓的位置信息(x,y),radius=cv2.minEnclosingCircle(cnt)centers=(int(x),int(y))radius=int(radius)cv2.circle(ret,centers,radius,(0,255,255),2)#畫出外接圓的輪廓ellipse=cv2.fitEllipse(cnt)#畫出內(nèi)接橢圓cv2.ellipse(ret,ellipse,(0,255,0),2)cv2.imshow('ret''Result',ret)cv2.waitKey(0)cv2.destroyAllWindows()圖形的最小外接圓和內(nèi)接橢圓程序運行輸出結(jié)果如圖所示。兩個圓形都顯示在一張圖像中。黃色顯示的外接圓,綠色顯示的是內(nèi)接橢圓。12.3.4近似輪廓有時我們獲取的圖像邊緣并不是平坦的,可能有凹陷或凸起,我們就不能得到一個完美的矩形,這時可以利用cv2.aprroxPolyDP()函數(shù)來近似這個形狀了,即將輪廓形狀近似到另外一種由更少點組成的輪廓形狀,新輪廓點的數(shù)目由我們設(shè)定的準(zhǔn)確度來決定。cv2.aprroxPolyDP()函數(shù)語法格式如下:cv2.aprroxPolyDP(cnt,epsilon,True)其中第一個參數(shù)cnt為輸入的輪廓值;第二個參數(shù)epsilon為閾值T,表示多邊形的輪廓接近實際輪廓的程度,通常使用輪廓的周長作為閾值,值越小越精確,也越近似輪廓邊界;第三個參數(shù)True表示輪廓是閉合的。
例7獲得輪廓的近似值,并使用cv2.drawCountors進行畫圖操作,程序代碼如下:importcv2importnumpyasnp#1.先找到輪廓img=cv2.imread('D:/pics/contour6.png',0)_,thresh=cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)contours,hierarchy=cv2.findContours(thresh,3,2)cnt=contours[0]#2.進行多邊形逼近,得到多邊形的角點epsilon1=0.1*cv2.arcLength(cnt,True)epsilon2=0.01*cv2.arcLength(cnt,True)epsilon3=0.001*cv2.arcLength(cnt,True)approx1=cv2.approxPolyDP(cnt,epsilon1,True)approx2=cv2.approxPolyDP(cnt,epsilon2,True)approx3=cv2.approxPolyDP(cnt,epsilon3,True)#3.畫出多邊形image=cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)cv2.imshow('Orignal',img)image1=cv2.drawContours(image,[approx1],0,(0,0,255),2)#紅色cv2.imshow('approxPloyDP10%',image1)image2=cv2.drawContours(image,[approx2],0,(255,0,0),2)#藍色cv2.imshow('approxPloyDP!%',image2)image3=cv2.drawContours(image,[approx3],0,(0,255,255),2)#黃色cv2.imshow('approxPloyDP0.1%',image3)print(len(approx1),len(approx2),len(approx3))#角點的個數(shù)cv2.waitKey(0)cv2.destroyAllWindows()(a)原圖像
(b)epsilon=10%周長時近似輪廓輸出圖像近似輪廓如圖所示,打印出的角點個數(shù)為4、24、45。其中圖(a)原圖像;圖(b)epsilon=10%周長時得到的近似輪廓,角點的個數(shù)4;圖(c)epsilon=1%周長時得到的近似輪廓,角點的個數(shù)24;圖(d)epsilon=0.1%周長時得到的近似輪廓,角點的個數(shù)45。可以看到,cv.approxPolyDP函數(shù)中參數(shù)epsilon越小,得到的多邊形角點越多,對原圖像的多邊形近似效果越好。(c)epsilon=1%周長時近似輪廓
(d)epsilon=0.1%周長時近似輪廓12.3.5輪廓凸包輪廓凸包就是給定二維平面上的點集,將最外層的點連接起來構(gòu)成的凸多邊形,它能包含點集中所有的點。凸包的計算函數(shù)語法格式為:hull=cv2.convexHull(points,clockwise,returnpoints)其中,輸出參數(shù)hull為凸包結(jié)果,n*1*2數(shù)據(jù)結(jié)構(gòu),n為外包圍圈點數(shù)。第一個輸入?yún)?shù)points是傳入的輪廓坐標(biāo)點,通常為1*n*2結(jié)構(gòu),n為所有坐標(biāo)點的數(shù)目;第二個參數(shù)clockwise方向標(biāo)記,TRUE為順時針,否則為逆時針;第三個輸入?yún)?shù)returnpoints默認(rèn)為TRUE,返回凸包上點的坐標(biāo),如果設(shè)置為FALSE,會返回與凸包點對應(yīng)的輪廓上的點。一般直接寫為:hull=cv2.convexHull(points)即可。但是,如果要查找凸度缺陷,則需要傳遞參數(shù)returnPoints=False。
例12.8求圖形的輪廓凸包點和畫線標(biāo)記,程序代碼如下:importcv2img=cv2.imread('D:/pics/contour2.png',1)gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret,thresh=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)contours,hierarchy=cv2.findContours(thresh,2,1)cnt=contours[0]#尋找凸包并繪制凸包(輪廓)hull=cv2.convexHull(cnt,True,False)#繪制凸包外連接線length=len(hull)foriinrange(len(hull)):cv2.line(img,tuple(hull[i][0]),tuple(hull[(i+1)%length][0]),(0,255,0),2)#顯示凸包坐標(biāo)點cv2.drawContours(img,hull,-1,(0,0,255),3)cv2.imshow('line&points',img)cv2.waitKey()cv2.destroyAllWindows()凸包點和連線輸出結(jié)果如圖所示,凸包坐標(biāo)點用紅色標(biāo)記,連線用綠色標(biāo)記。使用函數(shù)cv2.isContourConvex()可以檢查曲線是否凸出,有凸出返回True,無凸出返回False。代碼如下:k=cv2.isContourConvex(cnt)print("是否凸性:",k)12.3.6擬合直線可以根據(jù)一組點擬合出一條直線,同樣也可以為圖像中的白色點擬合出一條直線。OpenCV中擬合函數(shù)cv2.fitLine()的調(diào)用形式如下:[vx,vy,x,y]=cv2.fitLine(points,distType,param,reps,aeps)其中輸入輸出參數(shù)如下:
points:待擬合直線的集合,矩陣形式;
distType:距離類型。fitline為距離最小化函數(shù),擬合直線時,要使輸入點到擬合直線的距離和最小化。param:距離參數(shù),跟所選的距離類型有關(guān),值可以設(shè)置為0;
reps,aeps:第5/6個參數(shù)用于表示擬合直線所需要的徑向和角度精度參數(shù),通常情況下兩個值均被設(shè)定為1e-2; 輸出參數(shù)[vx,vy,x,y]:vx,vy代表擬合出的直線方向的角度,x,y代表直線上的一點。這里的距離類型有以下幾種:
cv2.DIST_USER:用戶自定義距離;
cv2.DIST_L1:distance=|x1-x2|+|y1-y2|;
cv2.DIST_L2:歐式距離,此時與最小二乘法相同;
cv2.DIST_C:distance=max(|x1-x2|,|y1-y2|);
cv2.DIST_L12:L1-L2metric:distance=2(sqrt(1+x*x/2)-1));
cv2.DIST_FAIR:distance=c^2(|x|/c-log(1+|x|/c)),c=1.3998;
cv2.DIST_WELSCH:distance=c2/2(1-exp(-(x/c)2)),c=2.9846;
cv2.DIST_HUBER:distance=|x|<c?x^2/2:c(|x|-c/2),c=1.345。
例9根據(jù)圖形擬合出圖形直線,程序代碼如下:importcv2importnumpyasnp#先找到輪廓img=cv2.imread('D:/pics/contour3.png',1)gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret,thresh=cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)contours,hierarchy=cv2.findContours(thresh,3,2)cnt=contours[0][vx,vy,x,y]=cv2.fitLine(cnt,cv2.DIST_L2,0,0.01,0.01)print([vx,vy,x,y])rows,cols=img.shape[:2]lefty=int((-x*vy/vx)+y)righty=int(((cols-x)*vy/vx)+y)img=cv2.line(img,(cols-1,righty),(0,lefty),(0,0,255),2)cv2.imshow('Line',img)cv2.waitKey()cv2.destroyAllWindows()擬合的圖形直線程序運行擬合直線的結(jié)果如圖所示。輸出顯示的[vx,vy,x,y]值分別為:[array([0.706464],dtype=float32),array([0.707749],dtype=float32),array([122.86943],dtype=float32),array([116.99682],dtype=float32)]12.3.7形狀特征長寬比
即一個圖像的長度除以它的寬度所得的比例,OpenCV中使用如下函數(shù)語句實現(xiàn):x,y,w,h=cv2.boundingRect(cnt)aspect_ratio=float(w)/h2.輪廓面積與邊界矩形面積的比(Extent)輪廓面積與邊界矩形面積的比,使用如下函數(shù)語句實現(xiàn):area=cv2.contourArea(cnt)x,y,w,h=cv2.boundingRect(cnt)rect_area=w*hextent=float(area)/rect_area3.輪廓面積與凸包面積的比(Solidity)輪廓面積與凸包面積的比,使用如下函數(shù)語句實現(xiàn):area=cv2.contourArea(cnt)hull=cv2.convexHull(cnt)hull_area=cv2.contourArea(hull)solidity=float(area)/hull_area4.求與輪廓面積相等的圓形直徑(EquivalentDiameter)使用如下函數(shù)語句實現(xiàn):area=cv2.contourArea(cnt)equi_diameter=np.sqrt(4*area/np.pi)5.方向
圖像分析需要知道物體的具體位置和方向,使用如下函數(shù)語句實現(xiàn):(x,y),(MA,ma),angle=cv2.fitEllipse(cnt)6.掩模和像素點在需要構(gòu)成物體對象的所有像素點時,使用如下函數(shù)語句實現(xiàn):mask=np.zeros(imgray.shape,np.uint8)cv2.drawContours(mask,[cnt],0,255,-1)#使用參數(shù)-1,繪制填充的輪廓pixelpoints=np.transpose(np.nonzero(mask))7.最大值和最小值及它們的位置使用掩模圖像得到最大值和最小值及它們的位置參數(shù)為:min_val,max_val,min_loc,max_loc=cv2.minMaxLoc(imgray,mask=mask)8.平均顏色及平均灰度使用相同的掩??梢郧蟮靡粋€對象的平均顏色或平均灰度為:mean_val=cv2.mean(im,mask=mask)9.極點獲得圖形對象的最上面、最下面、最左邊、最右邊點的函數(shù)如下:leftmost=tuple(cnt[cnt[:,:,0].argmin()][0])rightmost=tuple(cnt[cnt[:,:,0].argmax()][0])topmost=tuple(cnt[cnt[:,:,1].argmin()][0])bottommost=tuple(cnt[cnt[:,:,1].argmax()][0])10.點到輪廓距離獲得圖形中點與輪廓之間的最短距離的函數(shù)為:dist=cv2.pointPolygonTest(cnt,(x,y),True)其中第一個參數(shù)cnt為輸入的輪廓值;第二個輸入?yún)?shù)(x,y)為點的坐標(biāo);第三個輸入?yún)?shù)為True時表示計算距離值,點在輪廓外面值為負(fù),點在輪廓上值為0,點在輪廓里面值為正;當(dāng)?shù)谌齻€輸入?yún)?shù)為False時,返回-1、0、1,表示點相對輪廓的位置,不計算距離。12.4圖像特征矩圖像特征矩對于一幅圖像,我們把像素的坐標(biāo)看成是一個二維隨機變量(X,Y),那么一幅灰度圖像可以用二維灰度密度函數(shù)來表示,每個像素點的值可以看成是該處的密度,對某點求期望就是該圖像在該點處的矩(原點矩),一階矩和零階矩可以計算某個圖像形狀的重心,二階矩可以計算圖像形狀的方向,因此可以用矩來描述灰度圖像的特征。圖像的幾何矩包括空間矩、中心矩和中心歸一化矩。幾何矩具有平移、旋轉(zhuǎn)和尺度不變性,通過圖像的矩可以計算出圖像的質(zhì)心、面積等。從概率的觀點來理解,灰度出現(xiàn)的頻率可看作其出現(xiàn)的概率,這樣直方圖就對應(yīng)于概率密度函數(shù)(probabilitydensityfunction),而概率分布函數(shù)就是直方圖的累積和,即概率密度函數(shù)的積分。12.4.1圖像特征矩圖像的特征矩信息包含了對應(yīng)目標(biāo)對象不同類型的幾何特征值,如大小、位置、角度、形狀等。矩特征被廣泛地應(yīng)用在模式識別、圖像分類等方面。OpenCV提供了函數(shù)cv2.moments()來獲取圖像的矩特征。其語法格式為:retval=cv2.moments(array[,binaryImage])其中,輸入?yún)?shù):
array:可以是點集,也可以是灰度圖像或者二值圖像。當(dāng)array是點集時,函數(shù)會把這些點集當(dāng)成輪廓中的頂點,把整個點集作為一條輪廓,而不是把它們當(dāng)成獨立的點來看待。binaryImage:該參數(shù)為True時,array內(nèi)所有的非零值都被處理為1。該參數(shù)僅在參數(shù)array為圖像時有效。函數(shù)cv2.moments()的輸出參數(shù)retval是特征矩輸出值,主要包括:(1)空間矩
零階矩:m00;一階矩:m10,m01;二階矩:m20,m11,m02;三階矩:m30,m21,m12,m03(2)中心矩
二階中心矩:mu20,mu11,mu02;
三階中心矩:mu30,mu21,mu12,mu03(3)歸一化中心矩
二階Hu矩:nu20,nu11,nu02;
三階Hu矩:nu30,nu21,nu12,nu0312.4.1圖像特征矩上述矩都是通過數(shù)學(xué)公式計算得到的抽象特征,但是零階矩“m00”的含義比較直觀,它表示一個輪廓的面積。矩特征函數(shù)cv2.moments()所返回的特征值,能夠用來比較兩個輪廓是否相似。例如,有兩個輪廓,不管它們出現(xiàn)在圖像的哪個位置,我們都可以通過函數(shù)cv2.moments()的m00矩判斷其面積是否一致。在位置發(fā)生變化時,雖然輪廓的面積、周長等特征不變,但是更高階的特征會隨著位置的變化而發(fā)生變化。引入中心矩,中心矩通過減去均值而獲取平移不變性,因而能夠比較不同位置的兩個對象是否一致。因此中心矩具有的平移不變性,使它能夠忽略兩個對象的位置關(guān)系,幫助我們比較不同位置上兩個對象的一致性。12.4.1圖像特征矩除了考慮平移不變性外,我們還要考慮經(jīng)過縮放后大小不一致目標(biāo)對象的一致性問題。即我們希望圖像在縮放前后能夠擁有一個穩(wěn)定的特征值,顯然中心矩不具有這個屬性,如兩個形狀一致、大小不一的目標(biāo)對象,其中心矩是有差異的。歸一化中心矩通過除以物體總尺寸而獲得縮放不變性,它通過cv2.moments()函數(shù)計算提取目標(biāo)對象的歸一化中心矩屬性值,該屬性值既具有平移不變性,又具有縮放不變性。在OpenCV中,函數(shù)cv2.moments()同時輸出空間矩、中心矩和歸一化中心距。
例10使用函數(shù)cv2.moments()提取一幅圖像的特征,即空間矩、中心矩和歸一化中心矩。程序代碼如下:importcv2importnumpyasnpimg=cv2.imread('D:/pics/contours2.png')cv2.imshow("original",img)gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)contours,hierarchy=cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)n=len(contours)contoursImg=[]foriinrange(n):temp=np.zeros(image.shape,np.uint8)contoursImg.append(temp)contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,(0,255,255),3)cv2.imshow("contours["+str(i)+"]",contoursImg[i])print("各輪廓的矩(moments)如下:")foriinrange(n): print("輪廓"+str(i)+"的矩:\n",cv2.moments(contours[i]))print("各輪廓的面積如下:")foriinrange(n): print("輪廓"+str(i)+"的面積:%d"%cv2.moments(contours[i])['m00'])cv2.waitKey(0)cv2.destroyAllWindows()在實例中,使用函數(shù)cv2.moments()提取各個輪廓的特征值,通過cv2.moments(contours[i])[‘m00’])語句提取各個輪廓矩的面積信息。運行程序顯示出如圖所示的圖像。同時程序輸出各輪廓的矩值和面積。各輪廓的矩(moments)如下:輪廓0的矩:{'m00':11525.0,'m10':5244003.0,'m01':3636490.5,'m20':2397253322.1666665,'m11':1654642234.5833333,'m02':1157577087.0,'m30':1100945113725.5,'m21':756405574513.25,'m12':526709691329.4167,'m03':371658202723.25,'mu20':11173715.745061398,'mu11':-1330.8371872901917,'mu02':10152951.937939167,'mu30':-101977.62060546875,'mu21':-63172'mu12':100196.60257816315,'mu03':41644.57598876953,'nu20':0.08412319343546396,'nu11':-1.0019431019354824e-05,'nu02':0.07643820187512136,'nu30':-7.151588863331995e-06,'nu21':-4.430199176682604e-06,'nu12':7.026687844717826e-06,'nu03':2.920492595249822e-06}輪廓1的矩:{'m00':7062.5,'m10':1861003.8333333333,'m01':1507184.1666666665,'m20':495515231.75,'m11':397132802.125,'m02':326863087.0833333,'m30':133274943683.95001,'m21':105738333686.48334,'m12':86122659797.48334,'m03':71979581754.45,'mu20':5131477.034055054,'mu11':-17712.8068190217,'mu02':5220026.941642106,'mu30':-120758.3695526123,'mu21':1443855.2641823292,'mu12':172701.79757094383,'mu03':-3137315.5422973633,'nu20':0.10287870003274288,'nu11':-0.0003551161833870746,'nu02':0.10465399773360318,'nu30':-2.8808529356439663e-05,'nu21':0.0003444510464885352,'nu12':4.120033107158499e-05,'nu03':-0.0007484487181760963}各輪廓的面積如下:輪廓0的面積:11525輪廓1的面積:7062輪廓2的面積:9280輪廓2的矩:{'m00':9280.0,'m10':1057920.0,'m01':770240.0,'m20':131008853.33333333,'m11':87807360.0,'m02':68879253.33333333,'m30'0,'m21':10873734826.666666,'m12':7852234880.0,'m03':6538567360.0,'mu20':10405973.333333328,'mu11':0.0,'mu02':4949333.333333328,'mu30':0.0,'mu21':-2.384185791015625e-07,'mu12':5.960464477539062e-07,'mu03':9.5367431640625e-07,'nu20':0.12083333333333328,'nu11':0.0,'nu02':0.057471264367816036,'nu30':0.0,'nu21':-2.873890090203737e-17,'nu12':7.184725225509342e-17,'nu03':1.1495560360814947e-16}(a)原始圖像(b)圖像的第0個輪廓(c)圖像的第1個輪廓(d)圖像的第2個輪廓圖像各目標(biāo)的輪廓12.4.2Hu矩
12.4.2Hu矩在OpenCV中,使用函數(shù)cv2.HuMoments()可以得到Hu矩。函數(shù)cv2.HuMoments()的返回值參數(shù)為7個Hu矩值,其語法格式為:hu=cv2.HuMoments(m)其中輸出參數(shù)hu表示返回的Hu矩陣,輸入?yún)?shù)m是cv2.moments()計算得到的矩特征值。Hu矩是歸一化中心矩的線性組合,每一個矩都是通過歸一化中心矩的組合運算得到的,函數(shù)cv2.moments()返回的歸一化中心矩中包含:二階Hu矩:m20,m11,m02三階Hu矩:m30,m21,m12,m03
例12.11計算4種不同形狀圖像的Hu矩,并比較它們的差值。程序代碼如下:importcv2img1=cv2.imread('d:/pics/heart1.png')gray1=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)HuM1=cv2.HuMoments(cv2.moments(gray1)).flatten()print("\nHuM1=",HuM1)img2=cv2.imread('d:/pics/heart2.png')gray2=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)HuM2=cv2.HuMoments(cv2.moments(gray2)).flatten()print("\nHuM2=",HuM2)img3=cv2.imread('d:/pics/heart3.png')gray3=cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)HuM3=cv2.HuMoments(cv2.moments(gray3)).flatten()print("\nHuM3=",HuM3)img4=cv2.imread('d:/pics/heart4.png')gray4=cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)HuM4=cv2.HuMoments(cv2.moments(gray4)).flatten()print("\nHuM4=",HuM4)#計算Hu矩的差值print("\nHuM1-HuM2=",HuM1-HuM2)print("\nHuM2-HuM3=",HuM2-HuM3)print("\nHuM3-HuM4=",HuM3-HuM4)cv2.imshow("original1",img1)cv2.imshow("original2",img2)cv2.imshow("original3",img3)cv2.imshow("original4",img4)cv2.waitKey(0)cv2.destroyAllWindows()程序運行結(jié)果如圖所示,圖中顯示出了4幅大小、位置和形狀不同的圖形,并輸出了它們的Hu矩值,列成表格形式如下表所示。大小、位置和形狀不同的4幅圖形它們Hu之間的差值如下:HuM1-HuM2=[-2.97936322e-06-3.89584067e-09-7.91068532e-13-2.26453186e-131.89672586e-243.52665213e-176.27070529e-26]HuM2-HuM3=[1.23191592e-055.32992133e-098.67012469e-126.37953073e-13-4.31007126e-24-5.94539365e-17-3.57110783e-26]HuM3-HuM4=[0.0.0.0.0.0.0.]
HuM1HuM2HuM3HuM4H16.67160100e-046.70139463e-046.57820304e-046.57820304e-04H21.66216955e-095.55801022e-092.28088891e-102.28088891e-10H34.55809774e-114.63720459e-113.77019212e-113.77019212e-11H45.44173360e-137.70626546e-131.32673473e-131.32673473e-13H5-2.70993998e-24-4.60666585e-24-2.96594585e-25-2.96594585e-25H6-2.21837171e-17-5.74502384e-172.00369809e-182.00369809e-18H73.58783834e-26-2.68286695e-268.88240880e-278.88240880e-27由上表可以看出,將圖image1的Hu矩值與圖image2的Hu矩值相減,得到HuM1-HuM2的差值;將圖image2的Hu矩值與圖image3的Hu矩值相減,得到HuM2-HuM3的差值;如果將它們的差值誤差設(shè)定小于1e-5,那么它們的差值將為0,表明它們是同一個目標(biāo)對象。將圖image3的Hu矩值與圖image4的Hu矩值相減,得到HuM3-HuM4的差值為0,表明圖3與圖4是同一個目標(biāo)。說明Hu矩在圖像旋轉(zhuǎn)、縮放、平移等操作后,仍能保持矩的不變性,可以用于目標(biāo)的分類和識別。12.4.3形狀匹配使用Hu矩來找出兩個圖像之間的距離。如果距離小,圖像形狀的外觀差異較小,如果距離大,圖像形狀的外觀差異較大。OpenCV提供了一個名為cv2.matchShapes()的實用函數(shù),它可以獲取兩幅圖像(或輪廓)Hu矩值,并使用Hu矩查找它們之間的距離。利用兩個圖像的不變矩來進行距離計算,其函數(shù)語法格式是:dist=cv2.matchShapes(contour1,contour2,method,parameter)其中,前兩個輸入?yún)?shù)contour1和contour2是兩個圖像的輪廓值,第三個參數(shù)method是進行距離計算的方法;第四個輸入?yún)?shù)parameter一般設(shè)置為0即可。如果兩個圖像(img1和img2)是相似的,返回值越小,匹配就越好。1
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025死亡賠償協(xié)議書格式
- 黑素瘤病因介紹
- 協(xié)議書汽車轉(zhuǎn)讓模板
- 合同戰(zhàn)略合作協(xié)議
- 代理合作協(xié)議范本大全
- 公司保密協(xié)議案例
- 顱內(nèi)靜脈血栓形成病因介紹
- 2023夫妻結(jié)婚前協(xié)議書七篇
- 關(guān)于采購協(xié)議
- 中醫(yī)藥健康知識講座
- 2023年報告文學(xué)研究(自考)(重點)題庫(帶答案)
- 國軍淞滬會戰(zhàn)
- 2023年湖南體育職業(yè)學(xué)院高職單招(語文)試題庫含答案解析
- GB/T 39314-2020鋁合金石膏型鑄造通用技術(shù)導(dǎo)則
- 裝飾裝修施工質(zhì)量檢查評分表
- 非開挖施工技術(shù)講稿課件
- 單絨毛膜雙羊膜囊雙胎2022優(yōu)秀課件
- 《思想道德與法治》 課件 第四章 明確價值要求 踐行價值準(zhǔn)則
- 北師大版八年級上數(shù)學(xué)競賽試卷
- 幼兒園講座:課程游戲化、生活化建設(shè)的背景與目的課件
- 地理信息系統(tǒng)(GIS)公開課(課堂)課件
評論
0/150
提交評論