教程:使用Python進行基本圖像數(shù)據(jù)分析!
本教程將介紹如何導(dǎo)入圖像并觀察其屬性、拆分圖層以及查看灰度。在正式開始之前,我們先來了解一些關(guān)于像素的基礎(chǔ)知識。
計算機將圖片以像素形式存儲,這就像馬賽克一樣。如果像素太大,很難制作光滑的邊緣和曲線。相反,我們使用的像素越多越小,看起來就會越平滑,或者說像素化程度越小,圖像就會越好看,有時,這也被稱為圖像分辨率。

矢量圖形是一種有點不同的存儲圖像方法,旨在避免與像素相關(guān)的問題。但是,即使是矢量圖像,最終也會顯示為像素一樣的馬賽克。顏色像素表示圖像元素,描述每個像素的簡單方法是使用三種顏色的組合,即紅色,綠色,藍色,這就是我們所說的RGB圖像。
在RGB圖像中,每個像素分別與紅色,綠色,藍色的值相關(guān)聯(lián)的三個8比特數(shù)字表示。最后,如果使用放大鏡觀察縮放的圖片,我們會看到圖片由微小的光點或更具體的像素組成,更有趣的是這些小光點實際上具有多個不同顏色。
每張照片都以數(shù)字形式由像素組成,它們是構(gòu)成圖片的最小信息單位,通常是圓形或方形,它們通常布置在二維網(wǎng)格中。

如果三個顏色都處于最大值,則意味著它們是255,那就會顯示為白色,如果三種顏色都處于最小值,或者值為0,則顏色顯示為黑色。反過來,這三者的組合將為我們提供特定的像素顏色。由于每個顏色數(shù)字都是8個比特,因此值范圍為0-255。

由于每個值可以具有256個不同的強度或亮度值,因此三種顏色總共有1680萬個shade。

以下是Numpyand非?;镜膱D像數(shù)據(jù)分析步驟,其中一些涉及Python pacakges,如imageio,matplotlib等。
- 導(dǎo)入圖像并觀察其屬性
- 拆分圖層
- Greyscale
- 對像素值使用邏輯運算符
- 使用邏輯運算符進行運算
- 衛(wèi)星圖像數(shù)據(jù)分析
- 導(dǎo)入圖像
現(xiàn)在讓我們加載圖像并觀察各種屬性:
- if __name__ == '__main__':
- import imageio
- import matplotlib.pyplot as plt
- %matplotlib inline
- pic = imageio.imread('F:/demo_2.jpg')
- plt.figure(figsize = (15,15))
- plt.imshow(pic)觀察圖像的基本屬性
- print('Type of the image : ' , type(pic))
- print('Shape of the image : {}'.format(pic.shape))
- print('Image Hight {}'.format(pic.shape[0]))
- print('Image Width {}'.format(pic.shape[1]))
- print('Dimension of Image {}'.format(pic.ndim))
- Type of the image :
- Shape of the image : (562, 960, 3)
- Image Hight 562
- Image Width 960
- Dimension of Image 3
ndarray的形狀表明它是一個三層矩陣,這里的前兩個數(shù)字是長度和寬度,第三個數(shù)字(即3)是三層:Red, Green, Blue。 因此,如果我們計算RGB圖像的大小,則總大小將計為height x width x 3
- print('Image size {}'.format(pic.size))
- print('Maximum RGB value in this image {}'.format(pic.max()))
- print('Minimum RGB value in this image {}'.format(pic.min()))
- Image size 1618560
- Maximum RGB value in this image 255
- Minimum RGB value in this image 0
這些值對于驗證很重要,因為8比特顏色強度不能超出0到255范圍。
現(xiàn)在,使用圖片分配變量,我們還可以訪問圖片的任何特定像素值,并進一步訪問每個RGB通道。
- '''
- Let's pick a specific pixel located at 100 th Rows and 50 th Column.
- And view the RGB value gradually.
- '''
- pic[ 100, 50 ]
- Image([109, 143, 46], dtype=uint8)
在這種情況下:R = 109; G = 143; B = 46,我們可以意識到這個特殊像素中有很多綠色?,F(xiàn)在,我們可以通過給出三個通道的索引值來特別選擇其中一個數(shù)字:
- 0紅色通道的索引值
- 1綠色通道的索引值
- 2藍色通道的索引值
但是,在OpenCV中,圖像不是RGB而是BGR,imageio.imread將圖像加載為RGB(或RGBA),但OpenCV假定圖像為BGR或BGRA(BGR是默認的OpenCV顏色格式)。
- # A specific pixel located at Row : 100 ; Column : 50
- # Each channel's value of it, gradually R , G , B
- print('Value of only R channel {}'.format(pic[ 100, 50, 0]))
- print('Value of only G channel {}'.format(pic[ 100, 50, 1]))
- print('Value of only B channel {}'.format(pic[ 100, 50, 2]))
- Value of only R channel 109
- Value of only G channel 143
- Value of only B channel 46
好的,現(xiàn)在讓我們快速查看整個圖像中的每個頻道。
- plt.title('R channel')
- plt.ylabel('Height {}'.format(pic.shape[0]))
- plt.xlabel('Width {}'.format(pic.shape[1]))
- plt.imshow(pic[ : , : , 0])
- plt.show()
- plt.title('G channel')
- plt.ylabel('Height {}'.format(pic.shape[0]))
- plt.xlabel('Width {}'.format(pic.shape[1]))
- plt.imshow(pic[ : , : , 1])
- plt.show()
- plt.title('B channel')
- plt.ylabel('Height {}'.format(pic.shape[0]))
- plt.xlabel('Width {}'.format(pic.shape[1]))
- plt.imshow(pic[ : , : , 2])
- plt.show()
現(xiàn)在,我們可以更改RGB值的數(shù)量。例如,讓我們對紅色、綠色、藍色圖層設(shè)置跟隨行值的強度。
- R頻道:行 - 100到110
- G頻道:行 - 200到210
- B頻道:行 - 300到310
我們將加載一次圖像,以便可以同時顯示每個層的變化。
- pic = imageio.imread('F:/demo_2.jpg')
- pic[50:150 , : , 0] = 255 # full intensity to those pixel's R channel
- plt.figure( figsize = (10,10))
- plt.imshow(pic)
- plt.show()
- pic[200:300 , : , 1] = 255 # full intensity to those pixel's G channel
- plt.figure( figsize = (10,10))
- plt.imshow(pic)
- plt.show()
- pic[350:450 , : , 2] = 255 # full intensity to those pixel's B channel
- plt.figure( figsize = (10,10))
- plt.imshow(pic)
- plt.show()
為了更清楚,讓我們也改變列部分,這次我們將同時更改RGB通道。
- # set value 200 of all channels to those pixels which turns them to white
- pic[ 50:450 , 400:600 , [0,1,2] ] = 200
- plt.figure( figsize = (10,10))
- plt.imshow(pic)
- plt.show()
拆分圖層
現(xiàn)在,我們知道圖像的每個像素都由三個整數(shù)表示,將圖像分割成單獨的顏色分片只需拉出圖像陣列的正確切片。
- import numpy as np
- pic = imageio.imread('F:/demo_2.jpg')
- fig, ax = plt.subplots(nrows = 1, ncols=3, figsize=(15,5))
- for c, ax in zip(range(3), ax):
- # create zero matrix
- split_img = np.zeros(pic.shape, dtype="uint8") # 'dtype' by default: 'numpy.float64'
- # assing each channel
- split_img[ :, :, c] = pic[ :, :, c]
- # display each channel
- ax.imshow(split_img)
灰度
黑白圖像存儲在二維陣列中,有兩種類型的黑白圖像:
- Greyscale:灰色陰影范圍:0~255
- Binary:像素為黑色或白色:0或255
現(xiàn)在,Greyscaling是一個將圖像從全色轉(zhuǎn)換為灰色陰影的過程。在圖像處理工具中,例如:在OpenCV中,許多功能在處理之前使用灰度圖像,這樣做是因為它簡化了圖像,幾乎可以降噪并增加處理時間,因為圖像中的信息較少。
在python中有兩種方法可以將圖像轉(zhuǎn)換為灰度,但使用matplotlib的簡單方法是使用此公式獲取原始圖像的RGB值的加權(quán)平均值。
- Y' = 0.299 R + 0.587 G + 0.114 B
- pic = imageio.imread('F:/demo_2.jpg')
- gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114])
- gray = gray(pic)
- plt.figure( figsize = (10,10))
- plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))
- plt.show()
然而,GIMP將顏色轉(zhuǎn)換為灰度圖像軟件有三種算法來完成任務(wù)。
灰度的Lightness 等級計算為
- Lightness = ½ × (max(R,G,B) + min(R,G,B))
灰度的Luminosity 等級計算為
- Luminosity = 0.21 × R + 0.72 × G + 0.07 × B
灰度的Average 計算為
- Average Brightness = (R + G + B) ÷ 3
讓我們嘗試一下算法,Luminosity效果如何?
- pic = imageio.imread('F:/demo_2.jpg')
- gray = lambda rgb : np.dot(rgb[... , :3] , [0.21 , 0.72, 0.07])
- gray = gray(pic)
- plt.figure( figsize = (10,10))
- plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))
- plt.show()
- '''
- Let's take a quick overview some the changed properties now the color image.
- Like we observe some properties of color image, same statements are applying
- now for gray scaled image.
- '''
- print('Type of the image : ' , type(gray))
- print()
- print('Shape of the image : {}'.format(gray.shape))
- print('Image Hight {}'.format(gray.shape[0]))
- print('Image Width {}'.format(gray.shape[1]))
- print('Dimension of Image {}'.format(gray.ndim))
- print()
- print('Image size {}'.format(gray.size))
- print('Maximum RGB value in this image {}'.format(gray.max()))
- print('Minimum RGB value in this image {}'.format(gray.min()))
- print('Random indexes [X,Y] : {}'.format(gray[100, 50]))
- Type of the image :
- Shape of the image : (562,960)
- Image Height 562
- Image Widht 960
- Dimension of Image 2
- Image size 539520
- Maximum RGB value in this image 254.9999999997
- Minimum RGB value in this image 0.0
- Random indexes [X,Y] : 129.07
使用邏輯運算符處理像素值
我們可以使用邏輯運算符創(chuàng)建相同大小的bullion ndarray。但是,這不會創(chuàng)建任何新數(shù)組,它只是將值返回到其主變量。例如,如果考慮在RGB圖像中濾除一些低值像素或高值或(任何條件),可以先將RGB轉(zhuǎn)換為灰度。
首先加載圖像并在屏幕上顯示:
- pic = imageio.imread('F:/demo_1.jpg')
- plt.figure(figsize = (10,10))
- plt.imshow(pic)
- plt.show()
接下來,我們考慮轉(zhuǎn)儲該圖像,比如我們想要過濾所有低于20 的像素值。為此,我們將使用邏輯運算符執(zhí)行此任務(wù),返回所有索引的True值。
- low_pixel = pic < 20
- # to ensure of it let's check if all values in low_pixel are True or not
- if low_pixel.any() == True:
- print(low_pixel.shape)
- (1079, 1293, 3)
正如上文所說,傳統(tǒng)上不使用宿主變量,但我之所以提到是因為它只保留True值。 所以,如果我們看到low_pixel和pic的 shape,我們會發(fā)現(xiàn)它們都具有相同的 shape。
- print(pic.shape)
- print(low_pixel.shape)
- (1079, 1293, 3)
- (1079, 1293, 3)
我們使用全局比較運算符為所有小于200的值生成低值濾波器。但是,我們可以使用此low_pixel數(shù)組作為索引將這些低值設(shè)置為某些特定值,這些值可能高于或低于先前的像素值。
- # randomly choose a value
- import random
- # load the orginal image
- pic = imageio.imread('F:/demo_1.jpg')
- # set value randomly range from 25 to 225 - these value also randomly choosen
- pic[low_pixel] = random.randint(25,225)
- # display the image
- plt.figure( figsize = (10,10))
- plt.imshow(pic)
- plt.show()
圖層蒙版
圖像蒙版是一種圖像處理技術(shù),用于去除具有模糊邊緣,透明或頭發(fā)部分的照片背景。
現(xiàn)在,我們將創(chuàng)建一個圓盤形狀的蒙版。首先,我們將測量從圖像中心到每個邊界像素值的距離。我們設(shè)置一個比較方便的半徑值,然后使用邏輯運算符創(chuàng)建一個圓盤,以下為代碼:
- if __name__ == '__main__':
- # load the image
- pic = imageio.imread('F:/demo_1.jpg')
- # seperate the row and column values
- total_row , total_col , layers = pic.shape
- '''
- Create vector.
- Ogrid is a compact method of creating a multidimensional-
- ndarray operations in single lines.
- for ex:
- >>> ogrid[0:5,0:5]
- output: [array([[0],
- [1],
- [2],
- [3],
- [4]]),
- array([[0, 1, 2, 3, 4]])]
- '''
- x , y = np.ogrid[:total_row , :total_col]
- # get the center values of the image
- cen_x , cen_y = total_row/2 , total_col/2
- '''
- Measure distance value from center to each border pixel.
- To make it easy, we can think it's like, we draw a line from center-
- to each edge pixel value --> s**2 = (Y-y)**2 + (X-x)**2
- '''
- distance_from_the_center = np.sqrt((x-cen_x)**2 + (y-cen_y)**2)
- # Select convenient radius value
- radius = (total_row/2)
- # Using logical operator '>'
- '''
- logical operator to do this task which will return as a value
- of True for all the index according to the given condition
- '''
- circular_pic = distance_from_the_center > radius
- '''
- let assign value zero for all pixel value that outside the cirular disc.
- All the pixel value outside the circular disc, will be black now.
- '''
- pic[circular_pic] = 0
- plt.figure(figsize = (10,10))
- plt.imshow(pic)
- plt.show()
衛(wèi)星圖像處理
衛(wèi)星圖像及其處理系統(tǒng)非常有用,我們可以用于做一些分析任務(wù)。
- # load the image
- pic = imageio.imread('F:\satimg.jpg')
- plt.figure(figsize = (10,10))
- plt.imshow(pic)
- plt.show()
我們來看一些基本信息:
- print(f'Shape of the image {pic.shape}')
- print(f'hieght {pic.shape[0]} pixels')
- print(f'width {pic.shape[1]} pixels')
- Shape of the image (3725, 4797, 3)
- hieght 3725 pixels
- width 4797 pixels
這張圖片上有一些有趣的東西,像許多其他的圖像可視化一樣,每個RGB層中的顏色都有自己的意思。例如,紅色的強度將表示像素中的地理數(shù)據(jù)點的高度,藍色的強度表示方位的度量,綠色表示斜率。這些顏色將有助于以更快,更有效的方式傳達此信息,而不是顯示數(shù)字。
- 紅色像素表示:Altitude·
- 藍色像素表示:Aspect
- 綠色像素表示: Slope
通過觀察彩色圖像,我們可以分辨出海拔是多少,斜率是多少,以及Slope是什么,這就是為顏色加載更多含義以表示更科學(xué)的分析的想法。
檢測每個通道的像素
- # Only Red Pixel value , higher than 180
- pic = imageio.imread('F:\satimg.jpg')
- red_mask = pic[:, :, 0] < 180
- pic[red_mask] = 0
- plt.figure(figsize=(15,15))
- plt.imshow(pic)
- # Only Green Pixel value , higher than 180
- pic = imageio.imread('F:\satimg.jpg')
- green_mask = pic[:, :, 1] < 180
- pic[green_mask] = 0
- plt.figure(figsize=(15,15))
- plt.imshow(pic)
- # Only Blue Pixel value , higher than 180
- pic = imageio.imread('F:\satimg.jpg')
- blue_mask = pic[:, :, 2] < 180
- pic[blue_mask] = 0
- plt.figure(figsize=(15,15))
- plt.imshow(pic)
- # Composite mask using logical_and
- pic = imageio.imread('F:\satimg.jpg')
- final_mask = np.logical_and(red_mask, green_mask, blue_mask)
- pic[final_mask] = 40
- plt.figure(figsize=(15,15))
- plt.imshow(pic)
未完待續(xù)......這只是該教程的第一章節(jié),其他內(nèi)容將會在后續(xù)章節(jié)中呈現(xiàn)。