人工智能導論實驗導航
實驗一:斑馬問題 https://blog.csdn.net/weixin_46291251/article/details/122246347
實驗二:圖像恢復 https://blog.csdn.net/weixin_46291251/article/details/122561220
實驗三:花卉識別 https://blog.csdn.net/weixin_46291251/article/details/122561505
實驗四:手寫體生成 https://blog.csdn.net/weixin_46291251/article/details/122576478
實驗源碼: xxx
2.1實驗介紹
2.1.1實驗背景
機器學習:
機器學習是一類算法的總稱,這些算法企圖從大量歷史數據中挖掘出其中隱含的規律,並用於預測或者分類,更具體的說,機器學習可以看作是尋找一個函數,輸入是樣本數據,輸出是期望的結果,只是這個函數過於復雜,以至於不太方便形式化表達。需要注意的是,機器學習的目標是使學到的函數很好地適用於“新樣本”,而不僅僅是在訓練樣本上表現很好。學到的函數適用於新樣本的能力,稱為泛化(Generalization)能力。
機器學習作為人工智能核心技術,本章主要圍繞機器學習涉及的決策樹、主成分分析和集成算法而設計的實驗。本章實驗難度分均為初級。
圖像恢復:
圖象是一種非常常見的信息載體,但是在圖像的獲取、傳輸、存儲過程中可能由於各種原因使得圖像受到噪聲的影響。如何去除噪聲的影響,恢復圖像原本的信息是計算機視覺中的重要研究問題。
常見的圖像恢復算法有基於空間域的中值濾波、基於小波域的小波去噪、基於偏微分方程的非線性擴散濾波等。本次實驗對圖像添加噪聲,並對添加噪聲的圖像進行基於線性回歸模型的去噪。
2.1.2實驗目的
本章實驗的主要目的是掌握機器學習相關基礎知識點,了解機器學習相關基礎知識,經典降維方法、決策樹算法和集成算法。熟悉機器學習的一般流程,具備使用python語言和機器學習算法解決實際問題的能力。
學習Python的Opencv庫進行圖像相關處理
學習Python的Numpy庫進行相關數值計算
學習線性回歸模型的應用
2.1.3實驗簡介
A. 生成受損圖像。
受損圖像(X)是由原始圖像(I∈RH∗W∗CI∈RH∗W∗C)添加了不同噪聲遮罩(noise masks)(M∈RH∗W∗CM∈RH∗W∗C)得到的(X=I⨀MX=I⨀M),其中⨀⨀是逐元素相乘。
噪聲遮罩僅包含 {0,1} 值。對原圖的噪聲遮罩的可以每行分別用 0.8/0.4/0.6 的噪聲比率產生的,即噪聲遮罩每個通道每行 80%/40%/60% 的像素值為 0,其他為 1。
B. 使用你最擅長的算法模型,進行圖像恢復。
C. 評估誤差為所有恢復圖像(R)與原始圖像(I)的 2-范數之和,此誤差越小越好。
error=∑3i=1norm(Ri(:)−Ii(😃,2)error=∑i=13norm(Ri(:)−Ii(😃,2),其中(:)是向量化操作,其他評估方式包括 Cosine 相似度以及 SSIM 相似度。
2.2概要設計
程序分為以下幾步:
首先進行圖片的讀取,這里要注意matplotlib和opencv讀取圖片格式的不同,需要進行轉換。然后將數據線性歸一化,然后在原圖上生成噪聲比率為0.6的噪聲,得到含噪的圖片,這里添加的噪聲類型為椒鹽噪聲。然后用中值濾波器對圖像濾波以實現圖像恢復。
實驗的關鍵是加噪和去噪
加噪用的是椒鹽噪聲,椒鹽噪聲(salt-and-pepper noise)即一種是鹽噪聲(salt noise),另一種是胡椒噪聲(pepper noise)。鹽=白色(0),椒=黑色(255)。前者是高灰度噪聲,后者屬於低灰度噪聲。這里兩種噪聲同時出現,呈現在圖像上就是黑白雜點
去噪用的是中值濾波法:使用濾波器窗口包含區域的像素值的中值來得到窗口中心的像素值。是一種非線性平滑濾波器。在去噪同時,較好的保持邊緣輪廓細節,適合處理椒鹽噪聲,但對高斯噪聲效果不好。
2.3詳細設計
2.3.1 導入工具包
matplotlib數據庫下的pyplot模塊是一個常用於圖像展示的模塊;
Numpy數據庫用於相關的數值計算;
cv2,即opencv庫,計算機視覺庫,常用於圖像的處理;
從sklearn.linear_model模塊下導入線性回歸(LinearRegression),嶺回歸(Ridge),Lasso回歸。
嶺回歸(Ridge):在線性回歸的基礎上加了L2正則化項(L2范數),增加線性回歸的泛化性能,它和一般線性回歸的區別是在損失函數上增加了一個L2正則化的項,和一個調節線性回歸項和正則化項權重的系數α。損失函數表達式如下:
J(θ)=(1/2)(Xθ−Y)T(Xθ−Y) + (1/2)α||θ||2
其中α為常數系數,需要進行調優。 ||θ||2 為L2范數。Ridge回歸的解法和一般線性回歸大同小異。
Lasso回歸:有時也叫做線性回歸的L1正則化,和Ridge回歸的主要區別就是在正則化項,Ridge回歸用的是L2正則化,而Lasso回歸用的是L1正則化。Lasso回歸的損失函數表達式如下:
J(θ)=(1/2)(Xθ−Y)T(Xθ−Y)+α||θ||1
其中α為常數系數,需要進行調優。 ||θ||1 為L1范數。
from matplotlib import pyplot as plt # 展示圖片
import numpy as np # 數值處理
import cv2 # opencv庫
from sklearn.linear_model import LinearRegression, Ridge, Lasso # 回歸分析
2.3.2 讀取圖片:
讀取圖片我們采用 cv2.imread(filename[, flags]) 函數:
filename:文件路徑
flags:指定加載圖像顏色類型的標志
cv2.IMREAD_COLOR:讀入一副彩色圖像。圖像的透明度會被忽略,這是默認參數,此時 flags=1。
cv2.IMREAD_GRAYSCALE:以灰度模式讀入圖像,此時 flags=0。
cv2.IMREAD_UNCHANGED:讀入一幅圖像,並且包括圖像的 alpha 通道,此時 flags=-1。
彩色圖像使用 OpenCV 加載時是 BGR 模式,但是 Matplotlib 是 RGB 模式。所以彩色圖像如果已經被 OpenCV 讀取,那它將不會被 Matplotlib 正確顯示。因此我們將 BGR模式轉換為 RGB 模式即可。
def read_image(img_path):
# 讀取圖片
img = cv2.imread(img_path)
# 如果圖片是三通道,采用 matplotlib 展示圖像時需要先轉換通道
if len(img.shape) == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
return img
img_path = 'A.png'# 加載圖片的路徑和名稱
img = read_image(img_path) # 讀取圖片
print(type(img))# 讀取圖片后圖片的類型
plt.imshow(img) # 展示圖片
plt.axis('off') # 關閉坐標
2.3.3 保存圖片
OpenCV 保存一個圖片使用函數 cv2.imwrite(filename, img[, params]):
filename:保存文件路徑及文件名,文件名要加格式
img:需要保存的圖片
def save_image(filename, image):
# np.copy() 函數創建一個副本。
# 對副本數據進行修改,不會影響到原始數據,它們物理內存不在同一位置。
img = np.copy(image)
img = img.squeeze()# 從給定數組的形狀中刪除一維的條目
if img.dtype == np.double: # 將圖片數據存儲類型改為 np.uint8
# 若img數據存儲類型是 np.double ,則轉化為 np.uint8 形式
img = img * np.iinfo(np.uint8).max
img = img.astype(np.uint8) # 轉換圖片數組數據類型
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)# 將 RGB 方式轉換為 BGR 方式
cv2.imwrite(filename, img)# 生成圖片
2.3.4 歸一化
機器學習過程中,數據歸一化非常重要,歸一化的目標主要有:
把數變為(0,1)或者(-1,1)之間的小數
把有量綱表達式變為無量綱表達式
常見的歸一化方法有:
線性比例變換法 xi=xi / max(x)
min-max標准化 xi=[xi−min(x)] /[ max(x)−min(x)]
z-score 標准化 xi=[xi−mean(x) ]/ σ
下面我們來實現線性比例變化法:
def normalization(image):
info = np.iinfo(image.dtype) # 獲取圖片數據類型對象的最大值和最小值
return image.astype(np.double) / info.max # 圖像數組數據放縮在 0-1 之間
img_path = 'A.png'# 圖片的路徑和名稱
img = read_image(img_path)# 讀取圖片
print("沒有歸一化的數據:\n", img[0, 0, :])# 展示部分沒有歸一化的數據:
img = normalization(img)# 圖片數據歸一化
print("歸一化后的數據:\n", img[0, 0, :])# 展示部分 歸一化后的數據
2.3.5 圖片加噪
生成受損圖像的實驗要求:
受損圖像(X)是由原始圖像( I∈RH∗W∗C )添加了不同噪聲遮罩(noise masks)( M∈RH∗W∗C )得到的( X=I⨀M ),其中 ⨀ 是逐元素相乘。
噪聲遮罩僅包含 {0,1} 值。對原圖的噪聲遮罩的可以每行分別用 0.8/0.4/0.6 的噪聲比率產生的,即噪聲遮罩每個通道每行 80%/40%/60% 的像素值為0,其他為1。
椒鹽噪聲(salt-and-pepper noise)是指兩種噪聲,一種是鹽噪聲(salt noise),另一種是胡椒噪聲(pepper noise)。鹽=白色(0),椒=黑色(255)。前者是高灰度噪聲,后者屬於低灰度噪聲。一般兩種噪聲同時出現,呈現在圖像上就是黑白雜點
以下使用的是一個閾值(prob、thres)進行的噪聲分布:
def noise_mask_image(img, noise_ratio):
""" 根據題目要求生成受損圖片 :param img: 圖像矩陣,一般為 np.ndarray :param noise_ratio: 噪聲比率,可能值是0.4/0.6/0.8 :return: noise_img 受損圖片, 圖像矩陣值 0-1 之間,數據類型為 np.array, 數據類型對象 (dtype): np.double, 圖像形狀:(height,width,channel),通道(channel) 順序為RGB """
# 受損圖片初始化
noise_img = np.zeros(img.shape, np.double)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
if random.random() < noise_ratio: # 如果生成的隨機數小於噪聲比例則將該像素點添加黑點
noise_img[i][j] = 0 # 1 / 0
elif random.random() > 1-noise_ratio:
noise_img[i][j] = 1 # 1 / 0
else:
noise_img[i][j] = img[i][j]
return noise_img
2.3.6 誤差評估
評估誤差為所有恢復圖像(R)與原始圖像(I)的2-范數之和,此誤差越小越好。 error=∑3i=1norm(Ri(:)−Ii(😃,2) ,其中(:)是向量化操作
def compute_error(res_img, img):
error = 0.0 # 初始化
res_img = np.array(res_img) # 將圖像矩陣轉換成為np.narray
img = np.array(img)
if res_img.shape != img.shape: # 如果2個圖像的形狀不一致,則打印出錯誤結果,返回值為 None
print("shape error res_img.shape and img.shape %s != %s" % (res_img.shape, img.shape))
return None
error = np.sqrt(np.sum(np.power(res_img - img, 2))) # 計算圖像矩陣之間的評估誤差
return round(error,3)
#計算平面二維向量的 2-范數值
img0 = [1, 0]
img1 = [0, 1]
print("平面向量的評估誤差:", compute_error(img0, img1))
2.3.7 圖像恢復
中值濾波器,使用濾波器窗口包含區域的像素值的中值來得到窗口中心的像素值。是一種非線性平滑濾波器。在去噪同時,較好的保持邊緣輪廓細節,適合處理椒鹽噪聲,但對高斯噪聲效果不好。
中值濾波原理:
選一個含有奇數點的窗口W,將這個窗口在圖像上掃描,把窗口中所含的像素點按灰度級的升或降序排列,取位於中間的灰度值來代替該點的灰度值。 例如選擇濾波的窗口如下圖,是一個一維的窗口,待處理像素的灰度取這個模板中灰度的中值.
換成圖像模板來理解就是將臨近像素按照大小排列,取排序像素中位於中間位置的值作為中值濾波的像素值
中值濾波流程圖:
def restore_image(noise_img, size=4):
img = noise_img
size = 5 # 核尺寸
num = int((size - 1) / 2) # 輸入圖像需要填充的尺寸
img = cv2.copyMakeBorder(img, num, num, num, num, cv2.BORDER_REPLICATE)
h, w = img.shape[0:2] # 獲取輸入圖像的長寬和高
h-=4;w-=4
img1 = np.zeros((h, w, 3), dtype="uint8") # 定義空白圖像,用於輸出中值濾波后的結果
for i in range(num, h - num): # 遍歷出原圖像
for j in range(num, w - num):
sum = []; sum1 = []
for k in range(i - num, i + num + 1): # 求中心像素周圍size*size區域內的像素的平均值
for l in range(j - num, j + num + 1):
sum = sum + [int(img[k, l][0]) + int(img[k, l][1]) + int(img[k, l][2])] # 每個像素的3通道像素值相加,然后求中間數
sum1 = sum1 + [(img[k, l][0], img[k, l][1], img[k, l][2])] # 將對於的三通道像素值存在數組sum1中
id = np.argsort(sum) # 將像素值周圍的點的數組進行排序,然后返回排序之前的像素值對應在數組中的序號
id = id[int((size ** 2) / 2) + 1] # 取返回序號的中間序號
img1[i, j] = sum1[id] # 通過中間序號找到在像素值數組中的3通道信號
return img1
2.4運行測試
原圖:
噪聲
加噪后的圖片:
去噪后的圖片:
總體對比圖:
程序計算出的誤差與相似度:
即:
恢復圖片與原始圖片的評估誤差:5140.961
恢復圖片與原始圖片的SSIM 相似度:0. 12262643111991207
恢復圖片與原始圖片的Cosine 相似度:0.8794560914526841
通過上述誤差的分析和人眼對修復后的圖片的觀察可知程序在一定程度上修復了含有噪聲的圖片,但修復效果仍有一定的提升空間。