python獲取圖片像素
『壹』 您好,請問怎麼用python寫程序關於計算八張圖片的像素平均值並將其放到
每張圖像是一個二維矩陣(灰度圖像)或者三維張量(彩色圖像)。計算均值的話可以用
importnumpyasnp
np.mean()
這個函數的功能可以查看你的python庫,help(np)即可(或者help(numpy))。
『貳』 python處理圖片數據
目錄
1.機器是如何存儲圖像的?
2.在Python中讀取圖像數據
3.從圖像數據中提取特徵的方法#1:灰度像素值特徵
4.從圖像數據中提取特徵的方法#2:通道的平均像素值
5.從圖像數據中提取特徵的方法#3:提取邊緣
是一張數字8的圖像,仔細觀察就會發現,圖像是由小方格組成的。這些小方格被稱為像素。
但是要注意,人們是以視覺的形式觀察圖像的,可以輕松區分邊緣和顏色,從而識別圖片中的內容。然而機器很難做到這一點,它們以數字的形式存儲圖像。請看下圖:
機器以數字矩陣的形式儲存圖像,矩陣大小取決於任意給定圖像的像素數。
假設圖像的尺寸為180 x 200或n x m,這些尺寸基本上是圖像中的像素數(高x寬)。
這些數字或像素值表示像素的強度或亮度,較小的數字(接近0)表示黑色,較大的數字(接近255)表示白色。通過分析下面的圖像,讀者就會弄懂到目前為止所學到的知識。
下圖的尺寸為22 x 16,讀者可以通過計算像素數來驗證:
圖片源於機器學習應用課程
剛才討論的例子是黑白圖像,如果是生活中更為普遍的彩色呢?你是否認為彩色圖像也以2D矩陣的形式存儲?
彩色圖像通常由多種顏色組成,幾乎所有顏色都可以從三原色(紅色,綠色和藍色)生成。
因此,如果是彩色圖像,則要用到三個矩陣(或通道)——紅、綠、藍。每個矩陣值介於0到255之間,表示該像素的顏色強度。觀察下圖來理解這個概念:
圖片源於機器學習應用課程
左邊有一幅彩色圖像(人類可以看到),而在右邊,紅綠藍三個顏色通道對應三個矩陣,疊加三個通道以形成彩色圖像。
請注意,由於原始矩陣非常大且可視化難度較高,因此這些不是給定圖像的原始像素值。此外,還可以用各種其他的格式來存儲圖像,RGB是最受歡迎的,所以筆者放到這里。讀者可以在此處閱讀更多關於其他流行格式的信息。
用Python讀取圖像數據
下面開始將理論知識付諸實踐。啟動Python並載入圖像以觀察矩陣:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from skimage.io import imread, imshow
image = imread('image_8_original.png', as_gray=True)
imshow(image)
#checking image shape
image.shape, image
(28,28)
矩陣有784個值,而且這只是整個矩陣的一小部分。用一個LIVE編碼窗口,不用離開本文就可以運行上述所有代碼並查看結果。
下面來深入探討本文背後的核心思想,並探索使用像素值作為特徵的各種方法。
方法#1:灰度像素值特徵
從圖像創建特徵最簡單的方法就是將原始的像素用作單獨的特徵。
考慮相同的示例,就是上面那張圖(數字『8』),圖像尺寸為28×28。
能猜出這張圖片的特徵數量嗎?答案是與像素數相同!也就是有784個。
那麼問題來了,如何安排這784個像素作為特徵呢?這樣,可以簡單地依次追加每個像素值從而生成特徵向量。如下圖所示:
下面來用Python繪制圖像,並為該圖像創建這些特徵:
image = imread('puppy.jpeg', as_gray=True)
image.shape, imshow(image)
(650,450)
該圖像尺寸為650×450,因此特徵數量應為297,000。可以使用NumPy中的reshape函數生成,在其中指定圖像尺寸:
#pixel features
features = np.reshape(image, (660*450))
features.shape, features
(297000,)
array([0.96470588, 0.96470588, 0.96470588, ..., 0.96862745, 0.96470588,
0.96470588])
這里就得到了特徵——長度為297,000的一維數組。很簡單吧?在實時編碼窗口中嘗試使用此方法提取特徵。
但結果只有一個通道或灰度圖像,對於彩色圖像是否也可以這樣呢?來看看吧!
方法#2:通道的平均像素值
在讀取上一節中的圖像時,設置了參數『as_gray = True』,因此在圖像中只有一個通道,可以輕松附加像素值。下面刪除參數並再次載入圖像:
image = imread('puppy.jpeg')
image.shape
(660, 450, 3)
這次,圖像尺寸為(660,450,3),其中3為通道數量。可以像之前一樣繼續創建特徵,此時特徵數量將是660*450*3 = 891,000。
或者,可以使用另一種方法:
生成一個新矩陣,這個矩陣具有來自三個通道的像素平均值,而不是分別使用三個通道中的像素值。
下圖可以讓讀者更清楚地了解這一思路:
這樣一來,特徵數量保持不變,並且還能考慮來自圖像全部三個通道的像素值。
image = imread('puppy.jpeg')
feature_matrix = np.zeros((660,450))
feature_matrix.shape
(660, 450)
現有一個尺寸為(660×450×3)的三維矩陣,其中660為高度,450為寬度,3是通道數。為獲取平均像素值,要使用for循環:
for i in range(0,iimage.shape[0]):
for j in range(0,image.shape[1]):
feature_matrix[i][j] = ((int(image[i,j,0]) + int(image[i,j,1]) + int(image[i,j,2]))/3)
新矩陣具有相同的高度和寬度,但只有一個通道。現在,可以按照與上一節相同的步驟進行操作。依次附加像素值以獲得一維數組:
features = np.reshape(feature_matrix, (660*450))
features.shape
(297000,)
方法#3:提取邊緣特徵
請思考,在下圖中,如何識別其中存在的對象:
識別出圖中的對象很容易——狗、汽車、還有貓,那麼在區分的時候要考慮哪些特徵呢?形狀是一個重要因素,其次是顏色,或者大小。如果機器也能像這樣識別形狀會怎麼樣?
類似的想法是提取邊緣作為特徵並將其作為模型的輸入。稍微考慮一下,要如何識別圖像中的邊緣呢?邊緣一般都是顏色急劇變化的地方,請看下圖:
筆者在這里突出了兩個邊緣。這兩處邊緣之所以可以被識別是因為在圖中,可以分別看到顏色從白色變為棕色,或者由棕色變為黑色。如你所知,圖像以數字的形式表示,因此就要尋找哪些像素值發生了劇烈變化。
假設圖像矩陣如下:
圖片源於機器學習應用課程
該像素兩側的像素值差異很大,於是可以得出結論,該像素處存在顯著的轉變,因此其為邊緣。現在問題又來了,是否一定要手動執行此步驟?
當然不!有各種可用於突出顯示圖像邊緣的內核,剛才討論的方法也可以使用Prewitt內核(在x方向上)來實現。以下是Prewitt內核:
獲取所選像素周圍的值,並將其與所選內核(Prewitt內核)相乘,然後可以添加結果值以獲得最終值。由於±1已經分別存在於兩列之中,因此添加這些值就相當於獲取差異。
還有其他各種內核,下面是四種最常用的內核:
圖片源於機器學習應用課程
現在回到筆記本,為同一圖像生成邊緣特徵:
#importing the required libraries
import numpy as np
from skimage.io import imread, imshow
from skimage.filters import prewitt_h,prewitt_v
import matplotlib.pyplot as plt
%matplotlib inline
#reading the image
image = imread('puppy.jpeg',as_gray=True)
#calculating horizontal edges using prewitt kernel
edges_prewitt_horizontal = prewitt_h(image)
#calculating vertical edges using prewitt kernel
edges_prewitt_vertical = prewitt_v(image)
imshow(edges_prewitt_vertical, cmap='gray')
『叄』 為什麼用Python的openCV讀取圖片與PIL讀取的圖片像素值會不一樣
經測試,同一張圖片,使用 PIL和 OpenCv庫讀取的數據是一樣的(經過BGR轉成RGB):
建議:可以嘗試更新 PIL或是 OpenCv庫。
本機測試環境: Python 3.7+Pillow 6.2 +opencv-python 4.1
『肆』 怎樣利用Python進行圖片分析
fromPILimportImage###此處為導出包,注意字母大小寫
importos,os.path
#指明被遍歷的文件夾
rootdir=os.path.abspath(os.curdir)+'/Image/'
rootdir1=os.path.abspath(os.pardir)+"/Image/"
#打包用
ifos.path.isdir(rootdir):
pass
else:
rootdir=rootdir1
size=315,560
i=0
forparent,dirnames,filenamesinos.walk(rootdir):
forfilenameinfilenames:
infile=os.path.join(parent,filename)
im=Image.open(infile)###此處Image.open(dir)為多數對象應用的基礎.
im.thumbnail(size)###此處size為長度為2的tuple類型,改變圖片解析度
im.save(infile)###im.save(dir),圖片處理的最後都用這個,就是保存處理過後的圖片
i+=1
print(i,"Done")
要用pil包 安裝如下:pipinstallpillow
『伍』 Python 的題
from selenium import webdriver # 用來驅動瀏覽器的from selenium.webdriver import ActionChains # 破解滑動驗證碼的時候用的 可以拖動圖片import timefrom PIL import Image # pip3 install pillowimport random# 截圖圖片函數def cut_image(driver): # 獲取整個頁面圖片,圖片名字為'snap.png'
driver.save_screenshot('snap.png') # 獲取滑動小畫圖
image = driver.find_element_by_class_name('geetest_canvas_img') print(image.location) print(image.size) # 獲取小圖片的左上右下的位置
left = image.location['x']
top = image.location['y']
right = left + image.size['width']
buttom = top + image.size['height'] print(left, top, right, buttom) # 調用open方法打開全屏圖片並賦值給image_obj對象
image_obj = Image.open('snap.png') # 通過image_obj對象對小圖片進行截取
# box: The crop rectangle, as a (left, upper, right, lower)-tuple.
img = image_obj.crop((left, top, right, buttom)) # 打開截取後的小圖片
# img.show()
return img# 獲取完整圖片def get_image1(driver):
time.sleep(2) # 修改document文檔樹,把完整圖片的display屬性修改為block
js_code = '''
var x = document.getElementsByClassName("geetest_canvas_fullbg")[0].style.display = "block"; '''
# 執行js代碼 driver.execute_script(js_code) # 截取圖片
image = cut_image(driver) return image# 獲取有缺口圖片def get_image2(driver):
time.sleep(2) # 修改document文檔樹,把完整圖片的display屬性修改為block
js_code = '''
var x = document.getElementsByClassName("geetest_canvas_fullbg")[0].style.display = "none"; '''
# 執行js代碼 driver.execute_script(js_code) # 截取圖片
image = cut_image(driver) return image# 獲取滑塊滑動距離def get_distance(image1, image2): # 小滑塊右側位置
start = 60 # 像素差
num = 60 print(image1.size) for x in range(start, image1.size[0]): for y in range(image1.size[1]): # 獲取image1完整圖片每一個坐標的像素點
rgb1 = image1.load()[x, y] # 獲取image2缺口圖片每一個坐標的像素點
rgb2 = image2.load()[x, y] # (60, 86, 40) (60, 86, 40) rgb
print(rgb1, rgb2) # abs獲取絕對值, 像素點比較的值
r = abs(rgb1[0] - rgb2[0])
g = abs(rgb1[1] - rgb2[1])
b = abs(rgb1[2] - rgb2[2]) # 如果條件成立,則找到缺口位置
if not (r < num and g < num and b < num): # 有誤差 - 7像素
return x - 7# 模擬人的滑動軌跡def get_strck_move(distance):
distance += 20 '''
滑動行為軌跡
加速公式:
v = v0 + a * t
路程公式:
s = v0 * t + 0.5 * a * (t ** 2) '''
# 初速度
v0 = 0 # 時間
t = 0.2 # 位置
s = 0 # 滑動軌跡列表 向前滑動列表
move_list = [] # 中間值,作為加減速度的位置
mid = distance / 5 * 3 # 加減速度列表
v_list = [1, 2, 3, 4] # 循環位移
while s < distance: if s < mid: # 隨機獲取一個加速度
a = v_list[random.randint(0, len(v_list) - 1)] else: # 隨機獲取一個減速度
a = -v_list[random.randint(0, len(v_list) - 1)] '''
勻加速\減速運行
v = v0 + a * t
位移:
s = v * t + 0.5 * a * (t**2) '''
# 獲取初始速度
v = v0 # 路程公式:
s1 = v * t + 0.5 * a * (t ** 2)
s1 = round(s1) # 取整
# 加速公式:
# v = v0 + a * t
m_v = v + a * t # 把當前加/減速度賦值給初始速度,以便下一次計算
v0 = m_v # 把位移添加到滑動列表中 move_list.append(s1) # 修改滑動初始距離
s += s1 # 後退列表, 自定義後退滑動軌跡,必須是負值
back_list = [-1, -1, -2, -3, -2, -1, -1, -2, -3, -2, -1, -1] return {'move_list': move_list, 'back_list': back_list}def main():
driver = webdriver.Chrome(r'F:\python學習\Scripts\chromedriver')
driver.implicitly_wait(10) try:
driver.get('https://account.cnblogs.com/signin?returnUrl=https%3A%2F%2Fwww.cnblogs.com%2F') # 1、輸入用戶名與密碼,並點擊登錄
user_input = driver.find_element_by_id('LoginName')
user_input.send_keys('你的博客園賬號')
time.sleep(0.2)
pwd_input = driver.find_element_by_id('Password')
pwd_input.send_keys('你的博客園密碼')
time.sleep(2)
login_submit = driver.find_element_by_id('submitBtn')
login_submit.click() # 2、獲取完整的圖片
image1 = get_image1(driver) # 3、獲取有缺口圖片
image2 = get_image2(driver) # 4、比對兩張圖片,獲取滑動距離
distance = get_distance(image1, image2) print(distance) # 5、模擬人的滑動軌跡
move_dict = get_strck_move(distance) # 獲取前進滑動軌跡
move_list = move_dict['move_list'] # 獲取後退滑動軌跡
back_list = move_dict['back_list'] # 6、開始滑動
move_tag = driver.find_element_by_class_name('geetest_slider_button') # 點擊摁住滑動按鈕 ActionChains(driver).click_and_hold(move_tag).perform() # 向前滑動
for move in move_list:
ActionChains(driver).move_by_offset(xoffset=move, yoffset=0).perform()
time.sleep(0.1)
time.sleep(0.1) # 向後滑動
for back in back_list:
ActionChains(driver).move_by_offset(xoffset=back, yoffset=0).perform()
time.sleep(0.1) # 製作微妙晃動
ActionChains(driver).move_by_offset(xoffset=3, yoffset=0).perform()
ActionChains(driver).move_by_offset(xoffset=-3, yoffset=0).perform()
time.sleep(0.1) # 釋放滑動按鈕 ActionChains(driver).release().perform()
time.sleep(100) finally:
driver.close()if __name__ == '__main__':
main()