初めての勉強をしています。授業中の大きな宿題を記録するだけです。自分で書く方法がわからない場合は、このブログを見つけることができると思います
線形回帰モデル
1. 実験内容
画像は非常に一般的な情報媒体ですが、画像の取得、送信、保存の過程でさまざまな理由によりノイズの影響を受ける可能性があります。ノイズの影響をどのように除去し、画像の元の情報を復元するかは、コンピュータ ビジョンにおける重要な研究課題です。
一般的な画像復元アルゴリズムには、空間領域に基づくメディアン フィルター、ウェーブレット領域に基づくウェーブレット ノイズ除去、偏微分に基づく非線形拡散フィルターなどが含まれます。この実験では、画像にガウス ノイズを追加し、線形回帰モデルに基づいてノイズが追加された画像のノイズを除去します。
2. 実験要件
(1) 破損した画像の生成
3. 実験環境
画像相関処理は Python の OpencCV ライブラリに基づいて実行でき、関連する数値演算は Numpy ライブラリを使用して実行できます。
4. プログラムコード
ナンセンスなことを話さず、コードに直接アクセスしてください
from matplotlib import pyplot as plt
import numpy as np
import cv2 # opencv库
from sklearn.linear_model import LinearRegression, Ridge, Lasso # 回归分析
def read_image(img_path):
"""
读取图片,图片是以 np.array 类型存储,返回图片的数组形式
:param img_path: 图片的路径以及名称
:return: img np.array 类型存储
"""
# 读取图片
img = cv2.imread(img_path)
# 如果图片是三通道,采用 matplotlib 展示图像时需要先转换通道
if len(img.shape) == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转换围为二通道的灰度图
return img
def plot_image(image, image_title, is_axis=False):
"""
展示图像
:param image: 展示的图像,一般是 np.array 类型
:param image_title: 展示图像的名称
:param is_axis: 是否需要关闭坐标轴,默认展示坐标轴
:return:
"""
# 展示图片
plt.imshow(image)
# 关闭坐标轴,默认关闭
if not is_axis:
plt.axis('off')
# 展示受损图片的名称
plt.title(image_title)
# 展示图片
plt.show()
def save_image(filename, image):
"""
保存图片,将np.ndarray 图像矩阵保存为一张 png 或 jpg 等格式的图片
:param filename: 图片保存路径及图片名称和格式
:param image: 图像矩阵,一般为np.array
:return:无返回值
"""
# np.copy() 函数创建一个副本,复制到img变量中
img = np.copy(image)
# 从给定数组的形状中删除一维的条目f
img = img.squeeze()
# 将图片数据存储类型改为 np.uint8
if img.dtype == np.double:
# 若img数据存储类型是 np.double ,则转化为 np.uint8 形式
img = img * np.iinfo(np.uint8).max
# 转换图片数组数据类型
img = img.astype(np.uint8) # .astype()将数据类型转换为括号的的类型
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
# 生成图片
cv2.imwrite(filename, img) # cv2.imwrite() 用于将图像保存到指定的文件
def normalization(image):
"""
将数据线性归一化
:param image: 图片矩阵,一般是np.array 类型
:return: 将归一化后的数据,在(0,1)之间
"""
# 获取图片数据类型对象的最大值和最小值,比如int16范围[-32768,32768]
info = np.iinfo(image.dtype)
# 图像数组数据放缩在 0-1 之间,并转换为双精度
return image.astype(np.double) / info.max
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, 图像形状:(h,w,c),顺序为RGB
"""
# 受损图片初始化
noise_img = None
# -------------生成受损图像-----------------
row, col = img.shape[0], img.shape[1] # 图片高宽
rgb = [None, None, None] # rgb初始化
for i in range(3):
# 构造其中一个通道的噪声图
for j in range(row): # 第几行
if rgb[i] is None:
rgb[i] = np.random.choice(2, (1, col), p=[noise_ratio, 1 - noise_ratio])
else:
a = np.random.choice(2, (1, col), p=[noise_ratio, 1 - noise_ratio]) # 从0,1两个数根据概率,重复选择col次,列数,0为施加噪声
rgb[i] = np.concatenate((rgb[i], a), axis=0) # 将产生的噪声加到初始化的rgb上
# 扩展 shape
for i in range(3):
rgb[i] = rgb[i][:, :, np.newaxis] # 变成三维
# 合并
rst = np.concatenate((rgb[0], rgb[1], rgb[2]), axis=2) # 同个维度拼接
noise_img = rst * img # 噪声与原图逐元素相乘
# -----------------------------------------------
return noise_img
def get_noise_mask(noise_img):
"""
获取噪声图像的矩阵形式,一般为 np.array
:param noise_img: 带有噪声的图片
:return: 噪声图像矩阵
"""
# 将图片数据矩阵只包含 0和1,如果不能等于 0 则就是 1。
return np.array(noise_img != 0, dtype='double')
def compute_error(res_img, img):
"""
计算恢复图像 res_img 与原始图像 img 的 2-范数,向量元素绝对值的平方和再开方
:param res_img:恢复图像
:param img:原始图像
:return: 恢复图像 res_img 与原始图像 img 的2-范数
"""
# 初始化
error = 0.0
# 将图像矩阵转换成为np.narray
res_img = np.array(res_img)
img = np.array(img)
# 如果2个图像的形状不一致,则打印出错误结果,返回值为 None
if res_img.shape != img.shape:
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)
def restore_image(noise_img, size=4):
"""
使用区域二元线性回归模型 进行图像恢复。
:param noise_img: 一个受损的图像
:param size: 输入区域半径,长宽是以 size*size 方形区域获取区域, 默认是 4
:return: res_img 恢复后的图片,图像矩阵值 0-1 之间,数据类型为 np.array,
数据类型对象 (dtype): np.double, 图像形状:(height,width,channel), 通道(channel) 顺序为RGB
"""
# 恢复图片初始化,首先 copy 受损图片,然后预测噪声点的坐标后作为返回值。
res_img = np.copy(noise_img)
# 获取噪声图像
noise_mask = get_noise_mask(noise_img)
# -------------恢复图像----------------------------
rows, cols, channel = res_img.shape
region = 10 # 10 * 10的区域
row_cnt = rows // region
col_cnt = cols // region
for chan in range(channel):
for rn in range(row_cnt + 1):
ibase = rn * region
if rn == row_cnt:
ibase = rows - region
for cn in range(col_cnt + 1):
jbase = cn * region
if cn == col_cnt:
jbase = cols - region
x_train = []
y_train = []
x_test = []
for i in range(ibase, ibase + region):
for j in range(jbase, jbase + region):
if noise_mask[i, j, chan] == 0: # 噪音点
x_test.append([i, j])
continue
x_train.append([i, j])
y_train.append([res_img[i, j, chan]])
if x_train == []:
print("x_train is None")
continue
reg = LinearRegression()
reg.fit(x_train, y_train)
pred = reg.predict(x_test)
for i in range(len(x_test)):
res_img[x_test[i][0], x_test[i][1], chan] = pred[i][0]
res_img[res_img > 1.0] = 1.0
res_img[res_img < 0.0] = 0.0
# ---------------------------------------------------------------
return res_img
if __name__ == "__main__":
img_path = '12.jpg' # 图片路径
img = read_image(img_path)
noise_ratio = 0.4 # 噪声比
nor_img = normalization(img)
print(nor_img.shape)
# 生成受损图片
for i in range(3):
noise_img = noise_mask_image(nor_img, noise_ratio)
# 保存受损图片
save_image('result/damaged_' + str(noise_ratio) + '.png', noise_img)
# 恢复图片
res_img = restore_image(noise_img)
# 保存恢复图片
save_image('result/recovery_' + str(noise_ratio) + '.png', res_img)
print("{}噪声比率,噪声图和原图之间的误差: {}".format(noise_ratio,compute_error(noise_img, nor_img)))
print("{}噪声比率,恢复图和原图之前的误差: {}".format(noise_ratio,compute_error(res_img, nor_img)))
noise_ratio = round(noise_ratio+0.2,3)
# 展示恢复图片
# plot_image(image=res_img, image_title="restore image")
最後まで直接プルして main 関数を見てください。
変更する必要がある箇所は 4 つあります。ご自身の環境に応じて、
1 箇所目は画像のパス
、2 箇所目はノイズ率です。これは変更しないでください。コードを実行すると、0.4 が順に生成され、損傷率が 0.6 と 0.8 の画像が生成されます。
3 番目は、損傷した画像を生成するための保存パスです。
4 番目は、復元された画像の保存パスです。
注: ここにあるコードは記述され、修正されています。能力がない場合は、無作為に変更しないでください。パスを変更して実行するだけで十分です。始めるのは簡単です。
5. 実験結果
パスを変更してコードを実行すると、結果フォルダーに 6 つの画像、(0.4、0.6、0.8) の比率を持つ 3 つの破損した画像、および対応する比率を持つ 3 つの復元された画像が生成されます。元の画像は左から破損しています
。
右から (0.4,0.6,0.8) に
画像を復元します。左から右に (0.4,0.6,0.8)
6. 結論
実験はここで終了です。これはまだ非常に単純な実験です。
ここのコードはブログから参照されていますが、コードをより使いやすくするためにいくつかの改良を加えました
https://blog.csdn.net/zhangpeterx/article /詳細/90262269