目录
- 一:模拟计算图像直方图和累计直方图
- 二:计算图像的均值、标准差、相关系数和协方差
- 三:利用模板进行卷积运算
- 四:获取彩色图像的直方图
- 五:图像直方图均衡化
一:模拟计算图像直方图和累计直方图
① 调用的python工具包:
② 利用生成随机数的函数生成一个256*256的二位数组模拟图像的灰度值的排列:
③ 遍历影像中的每一个像元的像元值,将其存为一个一维数组并进行排序:
④ 由于空值通常用-3.4028235e+38表达,避免错误统计需要提前剔除(利用数组切片的方法:
⑤ 绘制灰度直方图:
import numpy as np
import matplotlib.pyplot as plt
im_data = np.random.randint(low=0, high=256, size=256 * 256)
im_data.shape = 256, 256
print(im_data.shape)
# ##########显示灰度直方图########
# 遍历影像中的每一个像元的像元值
data = []
for i in range(im_data.shape[0]):
for j in range(im_data.shape[1]):
# print(j)
data.append(im_data[i][j])
data.sort()
# 统计最大最小值
data = np.array(data)
print(data.min(), data.max())
# 由于空值通常用-3.4028235e+38表达,避免错误统计需要提前剔除
a = sum(data == 0)
print(a)
print(data.shape)
data = data[a:] # 切片,即a[1:]相当于a[1:len(data)]
# 根据影像中最大最小值设定坐标轴
bins = np.linspace(start=0, stop=256, num=256)
# 绘制直方图,设定直方图颜色
plt.hist(data, bins, facecolor="black")
# 横坐标轴名称
plt.xlabel('像元值')
# 纵坐标轴名称
plt.ylabel('频数')
# 图表头名称
plt.title('灰度分布直方图')
# 显示中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
# 展现绘制得到的图片
plt.show()
# 导出绘制得到的图片
# plt.savefig('C:/test2.jpg')
band1_data = im_data
运行结果:
⑥ 绘制累计灰度直方图(只需将hist函数的cumulative参数设置为True):
运行结果:
(因为是随机生成数组,所以灰度值都分布比较均匀)
二:计算图像的均值、标准差、相关系数和协方差
① 在题目一的基础上利用相关函数可直接计算均值与标准差:
运行结果:
② 计算协方差矩阵和相关系数矩阵
a.先定义一个原始列表(模拟将图像灰度值矩阵转为数组后的数据形式),然后再计算其平均值:
b.再定义一个列表与原始列表结合,计算其协方差矩阵:
c. 再定义一个列表与原始列表结合,计算其相关系数矩阵:
origin_list = [[1, 0, 1, 0], [1, 0, 1, 0], [0, 1, 0, 1], [1, 0, 0, 1]]
index_1 = 0
avg = [0, 0, 0, 0]
for li in origin_list:
for num in li:
avg[index_1] += num/len(li)
index_1 += 1
print('各个平均数: ', avg)
xiefangcha = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
i = -1
for li_1 in origin_list:
i += 1
j = -1
for li_2 in origin_list:
j += 1
for num_1, num_2 in zip(li_1, li_2):
xiefangcha[i][j] += (num_1 - avg[i])*(num_2 - avg[j])/3
print('协方差矩阵: ', xiefangcha)
xiangguanjuzheng = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
i = 0
for xie in xiefangcha:
j = 0
for xi in xie:
xiangguanjuzheng[i][j] = xi/((xiefangcha[i][i]**0.5)*(xiefangcha[j][j]**0.5))
j += 1
i += 1
print('相关矩阵: ', xiangguanjuzheng)
结果输出:
各个平均数: [0.5, 0.5, 0.5, 0.5]
协方差矩阵: [[0.3333333333333333, 0.3333333333333333, -0.3333333333333333, 0.0], [0.3333333333333333, 0.3333333333333333, -0.3333333333333333, 0.0], [-0.3333333333333333, -0.3333333333333333, 0.3333333333333333, 0.0], [0.0, 0.0, 0.0, 0.3333333333333333]]
相关矩阵: [[1.0, 1.0, -1.0, 0.0], [1.0, 1.0, -1.0, 0.0], [-1.0, -1.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]
三:利用模板进行卷积运算
① 定义图像与模板
② 进行卷积运算的方法
③ 参数的传入与结果输出
import numpy as np
# 定义图像与模板
input_data = [
[[1, 1, 7, 1, 8, 1, 7, 1, 1],
[1, 1, 1, 1, 5, 1, 1, 1, 1],
[1, 1, 1, 5, 5, 5, 1, 1, 7],
[7, 1, 1, 5, 5, 5, 1, 1, 1],
[1, 1, 1, 5, 5, 5, 1, 8, 1],
[1, 8, 1, 1, 5, 1, 1, 1, 1],
[1, 8, 1, 1, 5, 1, 1, 8, 1],
[1, 1, 1, 1, 5, 1, 1, 1, 1],
[1, 1, 7, 1, 8, 1, 7, 1, 1]],
]
weights_data = [
[[0, -1, 0],
[-1, 4, -1],
[0, -1, 0]],
]
def compute_conv(fm, kernel):
[h, w] = fm.shape
[k, _] = kernel.shape
r = int(k / 2)
# 保存计算结果
rs = np.zeros([h - 2, w - 2], np.float32)
# 将输入在指定该区域赋值,即除了4个边界后,剩下的区域
# 对每个点为中心的区域遍历
for i in range(1, h - 1):
for j in range(1, w - 1):
# 取出当前点为中心的k*k区域
roi = fm[i - 1:i + r + 1, j - 1:j + r + 1]
# 计算当前点的卷积,对k*k个点点乘后求和
rs[i - 1][j - 1] = np.sum(roi * kernel)
return rs
def my_conv2d(input, weights):
[c, h, w] = input.shape
[_, k, _] = weights.shape
outputs = np.zeros([h - 2, w - 2], np.float32)
# 对每个feature map遍历,从而对每个feature map进行卷积
for i in range(c):
# feature map==>[h,w]
f_map = input[i]
# kernel ==>[k,k]
w = weights[i]
rs = compute_conv(f_map, w)
outputs = outputs + rs
return outputs
def main():
# shape=[c,h,w]
input = np.asarray(input_data, np.float32)
# shape=[in_c,k,k]
weights = np.asarray(weights_data, np.float32)
rs = my_conv2d(input, weights)
print(rs)
if __name__ == '__main__':
main()
运行结果(未输出边缘的像素值):
[[ 0. -6. -8. 5. -8. -6. 0.]
[ 0. -4. 8. 0. 8. -4. -6.]
[ -6. -4. 4. 0. 4. -4. -7.]
[ -7. -4. 8. 0. 8. -11. 28.]
[ 21. -7. -8. 8. -8. 0. -14.]
[ 21. -7. -4. 8. -4. -7. 28.]
[ -7. -6. -4. 5. -4. -6. -7.]]
四:获取彩色图像的直方图
这里用到的是PIL(Python Imaging Library)库,Python平台的图像处理标准库。
① 导入用到的相关的包:
②读入一张彩色tif图像,并分割RGB三种色彩:
③要对图像求直方图,就需要先把图像矩阵进行flatten操作,使之变为一维数组,然后再进行统计,分别提取R\G\B统计值,进行分区绘图:
④相关显示设置,显示原图像:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img = Image.open(r"D:\数据\影像test.tif")
r, g, b = img.split() # 分离R\G\B
# 要对图像求直方图,就需要先把图像矩阵进行flatten操作,使之变为一维数组,然后再进行统计
# 分别提取R\G\B统计值,叠加绘图
fig = plt.figure("ImageHist")
fig.add_subplot(2, 2, 1)
ar = np.array(r).flatten()
plt.hist(ar, facecolor='red', bins=256, edgecolor='red', )
# 横坐标轴名称
plt.xlabel('像元值')
# 纵坐标轴名称
plt.ylabel('频数')
# 图表头名称
plt.title('R 灰度分布直方图')
fig.add_subplot(2, 2, 2)
ag = np.array(g).flatten()
plt.hist(ag, bins=256, facecolor='green', edgecolor='green', )
# 横坐标轴名称
plt.xlabel('像元值')
# 纵坐标轴名称
plt.ylabel('频数')
# 图表头名称
plt.title('G 灰度分布直方图')
fig.add_subplot(2, 2, 3)
ab = np.array(b).flatten()
plt.hist(ab, bins=256, facecolor='blue', edgecolor='blue', )
# 横坐标轴名称
plt.xlabel('像元值')
# 纵坐标轴名称
plt.ylabel('频数')
# 图表头名称
plt.title('B 灰度分布直方图')
ax = fig.add_subplot(2, 2, 4)
plt.imshow(img)
# 显示中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
# 调整子图组合及子图之间的位置与间距
plt.subplots_adjust(left=0.1, right=0.9, hspace=0.5, wspace=0.3)
plt.show()
运行显示结果如下图:
五:图像直方图均衡化
直方图均衡化的基本原理是:对在图像中像素个数多的灰度值(即对画面起主要作用的灰度值)进行展宽,而对像素个数少的灰度值(即对画面不起主要作用的灰度值)进行归并,从而增大对比度,使图像清晰,达到增强的目的。
这里用到了openCV图像处理库,核心代码主要思路为:遍历图像每个像素的灰度,算出每个灰度的概率(n/MN-n是每个灰度的个数,MN是像素总数),用L-1乘以所得概率得到新的灰度:
import cv2
import numpy as np
img = cv2.imread("img.tif")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 直方图统计
def pix_gray(img_gray):
h = img_gray.shape[0]
w = img_gray.shape[1]
gray_level = np.zeros(256)
gray_level2 = np.zeros(256)
for i in range(1, h - 1):
for j in range(1, w - 1):
gray_level[img_gray[i, j]] += 1 # 统计灰度级为img_gray[i,j的个数
for i in range(1, 256):
gray_level2[i] = gray_level2[i - 1] + gray_level[i] # 统计灰度级小于img_gray[i,j]的个数
return gray_level2
# 直方图均衡化
def hist_gray(img_gary):
h, w = img_gary.shape
gray_level2 = pix_gray(img_gray)
lut = np.zeros(256)
for i in range(256):
lut[i] = 255.0 / (h * w) * gray_level2[i] # 得到新的灰度级
lut = np.uint8(lut + 0.5)
out = cv2.LUT(img_gray, lut)
return out
cv2.imshow('input', img_gray)
out_img = hist_gray(img_gray)
cv2.imshow('output', out_img)
cv2.waitKey(0)
# cv2.destroyWindow()
再利用前面同样的方法绘制原图与均衡化后的直方图,进行对比,如下图,可以看出均衡化后的图像的对比度得到了增强:
…
学习遥感数字图像处理中做的一些的编程练习。
借鉴参考:
【Python图像处理】图片读取/提取直方图
。。。。