來(lái)源:磐創(chuàng)AI
下面是一個(gè)關(guān)于使用Python在幾行代碼中分析城市輪廓線的快速教程。
說(shuō)一句顯而易見的話:輪廓線很美。
在本文中,我們將學(xué)習(xí)如何從圖片中獲取輪廓線輪廓。
讓我們開始吧。
0.理念
這個(gè)想法很簡(jiǎn)單。為了檢測(cè)輪廓線,我們只檢測(cè)天空并拍攝互補(bǔ)圖像。
在你之前看到的示例中,我們真正做的是識(shí)別天空。下一步當(dāng)然是獲取蒙版圖像。
那么,為什么探測(cè)天空比探測(cè)摩天大樓更容易呢?
好吧,這個(gè)概念是天空的圖片是相對(duì)平坦的。另一方面,摩天大樓是顏色、形狀、窗戶、水泥等的混合體。
從數(shù)學(xué)上講,天空的方差比摩天大樓的方差小,并且期望該參數(shù)在區(qū)分天空和摩天大樓時(shí)起決定性作用。
我想用一個(gè)例子來(lái)證明我所說(shuō)的話。讓我們拍下這張照片。
太棒了現(xiàn)在,讓我們?cè)谶@個(gè)區(qū)域修剪這張圖片:
現(xiàn)在,讓我們從0到50之間取一部分并打印標(biāo)準(zhǔn)偏差:
該方差變化可以使用二階導(dǎo)數(shù)來(lái)檢測(cè)。
當(dāng)我們討論離散二維情況時(shí),我們實(shí)際上是在討論拉普拉斯算子。拉普拉斯算子可以被視為卷積,這只是使用泰勒近似的導(dǎo)數(shù)的定義。
進(jìn)入下一節(jié)的主題。
1.算法
執(zhí)行圖(1)中所示操作的算法如下:
我明白這是一團(tuán)糟。讓我一步一步地解釋一下。
1.1將圖像轉(zhuǎn)換為黑白
我知道你知道這一切。但重要的是要說(shuō)明我們?yōu)槭裁匆@樣做。正如你所知,當(dāng)你將它們應(yīng)用于矩陣時(shí),所有的模糊步驟和過(guò)濾都是有意義的。彩色圖像在技術(shù)上是一個(gè)張量,因?yàn)樗哂行袛?shù)X列數(shù)X 3個(gè)通道值(紅、綠和藍(lán))。B&W圖像是由行數(shù)X列數(shù)組成的矩陣。
將此應(yīng)用于彩色圖像的一個(gè)簡(jiǎn)單方法是重復(fù)上述相同的過(guò)程三次,但我認(rèn)為沒有必要。最終,即使使用B&W圖像,我們也能分辨出輪廓線。
1.2模糊步驟
中值和歸一化濾波器步驟都是用于在保持邊的同時(shí)對(duì)信號(hào)的噪聲進(jìn)行濾波的步驟。
1.3拉普拉斯濾波器
拉普拉斯濾波器被認(rèn)為是離散空間的二階時(shí)間導(dǎo)數(shù)。
為什么我們首先需要二階時(shí)間導(dǎo)數(shù)?
我們說(shuō)過(guò),天空和摩天大樓之間的標(biāo)準(zhǔn)差是不同的。這種標(biāo)準(zhǔn)差的變化發(fā)生在一個(gè)特定的點(diǎn)上,即圖像(和摩天大樓)的邊緣。
所以我們希望看到圖像的快速變化。特別是,我們希望變化最大。這意味著我們需要二階導(dǎo)數(shù)為空的點(diǎn)(或點(diǎn)的鄰居)。
當(dāng)我們討論離散二維情況時(shí),我們實(shí)際上是在討論拉普拉斯算子。拉普拉斯算子可以被視為卷積,這只是使用泰勒近似的導(dǎo)數(shù)的定義。
二階導(dǎo)數(shù)是這樣的:
這是一個(gè)核,我們將在圖像上運(yùn)行,它將為我們提供二階導(dǎo)數(shù)圖像。
1.4應(yīng)用1/0閾值
我們不關(guān)心二階導(dǎo)數(shù)是正還是負(fù)。我們所關(guān)心的只是我們有0的一小部分,因?yàn)檫@是我們認(rèn)為的邊緣。
這就是為什么我們應(yīng)用這個(gè)1/0閾值。
1.5侵蝕濾波器
侵蝕濾波器是我們用來(lái)平滑圖像的東西。這背后的想法是,我們希望使圖像更清晰。用更專業(yè)的話來(lái)說(shuō),有一個(gè)核在圖像上傳遞,并用它們的最小值替換值。同樣,由于我們現(xiàn)在有一張1/0的圖像,它只是讓我們的圖像更清晰。
1.6將掩碼設(shè)置為0,直到找到最后一個(gè)索引
這一步有點(diǎn)難解釋,但很容易理解。完成所有這些操作后,圖像的一列中可能有一個(gè)0和1的序列。這沒有太多意義,因?yàn)槟悴荒茉贀碛小皊kyscraper-sky-skyscraper again”這樣的東西了。因此,我們?cè)诹兄姓业街禐?的最大索引,并將所有值設(shè)置為0,直到找到該值。那么,其他的都是0。
2.實(shí)際實(shí)現(xiàn)
這解釋起來(lái)有點(diǎn)長(zhǎng),但非常容易實(shí)現(xiàn)。
讓我們循序漸進(jìn):
importnumpyasnp importpandasaspd fromosimportlistdir fromPILimportImage importmatplotlib.pyplotasplt fromos.pathimportisfile,join importcv2 fromscipy.signalimportmedfilt fromscipyimportndimage importnumpyasnp frommatplotlibimportpyplotasplt importos fromsklearn.metricsimportplot_confusion_matrix fromsklearn.metricsimportconfusion_matrix
2.1導(dǎo)入庫(kù):
mypath='data/images' subfolders=[f.pathforfinos.scandir(mypath)iff.is_dir()] images=[] images_baw=[] labels=[] label=0 size=256 string_labels=[] forfolderinsubfolders: onlyfiles=[fforfinlistdir(folder)ifisfile(join(folder,f))] forfileinonlyfiles: image_file=Image.open(folder+'/'+file).resize((size,size)) images.append(np.array(image_file)) images_baw.append(np.array(image_file.convert('1'))) labels.append(label) string_labels.append(folder.split('/')[-1]) label=label+1 labels=np.array(labels) images=np.array(images) image_baw=np.array(images_baw)
2.1導(dǎo)入數(shù)據(jù):
我從Kaggle那里得到了數(shù)據(jù)。數(shù)據(jù)集是開源的,沒有版權(quán)(CC0:公共域)。特別是,我只下載了數(shù)據(jù)集的一部分,其中包含12個(gè)城市的圖像,每個(gè)城市有10座摩天大樓:
mypath='data/images' subfolders=[f.pathforfinos.scandir(mypath)iff.is_dir()] images=[] images_baw=[] labels=[] label=0 size=256 string_labels=[] forfolderinsubfolders: onlyfiles=[fforfinlistdir(folder)ifisfile(join(folder,f))] forfileinonlyfiles: image_file=Image.open(folder+'/'+file).resize((size,size)) images.append(np.array(image_file)) images_baw.append(np.array(image_file.convert('1'))) labels.append(label) string_labels.append(folder.split('/')[-1]) label=label+1 labels=np.array(labels) images=np.array(images) image_baw=np.array(images_baw)
2.2數(shù)據(jù)可視化
plt.figure(figsize=(20,20)) foriinrange(1,13): plt.subplot(4,3,i) identify_label=np.where(labels==i-1)[0] identify_label=np.random.choice(identify_label) plt.title('Citylabel=%s'%(string_labels[identify_label])) plt.imshow(images[identify_label])
2.3定義函數(shù):
以上所有理論都以以下方式實(shí)現(xiàn):
defcal_skyline(mask): h,w=mask.shape foriinrange(w): raw=mask[:,i] after_median=medfilt(raw,19) try: first_zero_index=np.where(after_median==0)[0][0] first_one_index=np.where(after_median==1)[0][0] iffirst_zero_index>20: mask[first_one_index:first_zero_index,i]=1 mask[first_zero_index:,i]=0 mask[:first_one_index,i]=0 except: continue returnmask defget_sky_region_gradient(img): h,w,_=img.shape img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) img_gray=cv2.blur(img_gray,(9,3)) cv2.medianBlur(img_gray,5) lap=cv2.Laplacian(img_gray,cv2.CV_8U) gradient_mask=(lap6).astype(np.uint8) ????kernel?=?cv2.getStructuringElement(cv2.MORPH_RECT,?(9,?3)) ????mask?=?cv2.morphologyEx(gradient_mask,?cv2.MORPH_ERODE,?kernel) ????#?plt.imshow(mask) ????#?plt.show() ????mask?=?cal_skyline(mask) ????after_img?=?cv2.bitwise_and(img,?img,?mask=mask) ????return?after_img
2.4應(yīng)用算法
這是算法在整個(gè)數(shù)據(jù)集上的應(yīng)用:
zero_images=[] zero_images_plot=[] forKinrange(len(images)): zero_image_plot=np.zeros((size,size)) zero_image=zero_image_plot.copy() foriinrange(size): zero_image_plot[i,tot_profiles[K][i]-2:tot_profiles[K][i]+2]=1 zero_image[i,tot_profiles[K][i]]=1 zero_images_plot.append(zero_image_plot.T) zero_images.append(zero_image.T)
示例:
K=0 plt.figure(figsize=(10,10)) plt.suptitle('City=%s'%(string_labels[K]),fontsize=20,y=0.72) plt.subplot(1,3,1) plt.title('OriginalImage') plt.imshow(images[K]) plt.subplot(1,3,3) plt.title('MaskedImage') plt.imshow(zero_images_plot[0]) plt.subplot(1,3,2) plt.title('ProfiledSkyline') plt.imshow(get_sky_region_gradient(images[K]))
2.5將其轉(zhuǎn)換為信號(hào)
為了獲得圖像(1)的正確圖像,我們應(yīng)用以下函數(shù):
defsignal_from_profile(K): x=np.arange(size) y=np.array(size-np.array(tot_profiles[K])) returnx,y
我們可以將其應(yīng)用于數(shù)據(jù)集的所有圖像:
plt.figure(figsize=(13,10)) #plt.suptitle('City=%s'%(string_labels[K]),fontsize=20) i=0 forqinrange(3): K=np.random.choice(len(images)) #print(K) skyline_signal_x,skyline_signal_y=signal_from_profile(K) plt.subplot(4,4,i+1) plt.title('OriginalImage') plt.imshow(images[K]) plt.subplot(4,4,i+3) plt.title('MaskedImage') plt.imshow(zero_images_plot[K]) plt.subplot(4,4,i+2) plt.title('ProfiledSkyline') plt.imshow(get_sky_region_gradient(images[K])) plt.subplot(4,4,i+4) plt.title('ExtractedSignal') plt.plot(skyline_signal_x,skyline_signal_y) plt.tight_layout() i=i+4
3.結(jié)尾
我認(rèn)為這項(xiàng)研究之所以有趣,有多種原因。首先,這很有趣,因?yàn)橛袃蓚€(gè)理論上合理的理由。
它解釋了如何使用拉普拉斯濾波器以非深度學(xué)習(xí)的方式應(yīng)用邊緣檢測(cè)
它解釋了如何使用圖像進(jìn)行從頭到腳的實(shí)驗(yàn),以及如何創(chuàng)建一個(gè)有效的圖像處理管道
當(dāng)然,這本身很有趣,因?yàn)樗鼮槟闾峁┝艘粋€(gè)分析不同城市輪廓線的工具!
你可以看到,城市A和城市B有不同的概況,特別是使用提取的信號(hào),我們可以通過(guò)以下方式深化這項(xiàng)研究:
提取輪廓線的平均值、中值和標(biāo)準(zhǔn)差
使用深度學(xué)習(xí)對(duì)城市輪廓線進(jìn)行分類
對(duì)輪廓線與時(shí)間進(jìn)行統(tǒng)計(jì)研究(輪廓線如何隨時(shí)間演變?)
記住,這個(gè)項(xiàng)目背后的整個(gè)想法是,天空的標(biāo)準(zhǔn)差比摩天大樓的標(biāo)準(zhǔn)差低。
我們還可以使用這種方法作為更復(fù)雜研究的起點(diǎn),并且可以使用編碼器-解碼器來(lái)改進(jìn)這些結(jié)果。
-
圖像處理
+關(guān)注
關(guān)注
27文章
1289瀏覽量
56720 -
AI
+關(guān)注
關(guān)注
87文章
30728瀏覽量
268874 -
代碼
+關(guān)注
關(guān)注
30文章
4779瀏覽量
68519 -
python
+關(guān)注
關(guān)注
56文章
4792瀏覽量
84626
原文標(biāo)題:使用Python進(jìn)行圖像處理
文章出處:【微信號(hào):vision263com,微信公眾號(hào):新機(jī)器視覺】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論