数字图像处理

发布时间 2023-05-28 20:34:00作者: 吴记玛卡

数字图像处理与python实现

1.数字图像处理基础知识

1.1数字图像简介

目的

提升图像的视觉感知质量

提取图像中感兴趣区域或特征

方便图像的存储和运输

特点

可再现能力强

处理精度高

适用范围广

灵活性高

方法

图像变换

图像压缩编码

图像增强和复原

图像分割

图像描述

图像分类(识别)

1.2图像的采样和量化

是将模拟图像转化为数字图像的重要步骤

采样

图像空间坐标的离散化,决定了图像空间分辨率

 

求均值/最大值采样

from skimage import data
from matplotlib import pyplot as plt
import numpy as np
img=data.coffee()
print(img.shape)#原始大小
print(type(img))#类型
ratio = 20#采样比率
imagel = np.zeros((int(img.shape[0]/ratio),
                  int(img.shape[1]/ratio),
                  img.shape[2]),
                  dtype='int32')#采样后的大小
for i in range (imagel.shape[0]):
  for j in range(imagel.shape[1]):
      for k in range(imagel.shape[2]):#遍历
          delta = img[i*ratio:(i+1)*ratio,j*ratio:(j+1)*ratio,k]#获取采样图像块
          # imagel[i,j,k]=np.mean(delta)#计算均值
          imagel[i, j, k] = np.max(delta)#最大值采样
plt.imshow(imagel)
plt.show()

可以改变采样比率

一般来说

采样间隔越大,所得图像像素越少,空间分辨率越差,图像质量越差,马赛克效应 采样间隔越小,所得图像像素越多,空间分辨率越高,图像质量越好,数据量大

 

量化

图像响应幅值的离散化,决定了图像的灰度分辨率

from skimage import data
from matplotlib import pyplot as plt
img = data.coffee()
ratio = 128
for i in range (img.shape[0]):
  for j in range(img.shape[1]):
      for k in range(img.shape[2]):
          img[i][j][k] = int(img[i][j][k]/ratio)*ratio#对图像中每个像素进行量化
plt.imshow(img)
plt.show()

量化等级越多,图像层次越丰富,灰度分辨率高,图像质量好,数据量大 量化等级越少,图像层次越欠丰富,灰度分辨率低, 轮廓效应,质量变差,数据量小

1.3图像的表示和可视化

经过采样和量化后,图像已经成为空间位置和响应值均离散的数字图像

原本连续的图像I=f(x,y)转为一个二维阵列f(x,y),m行n列、

与图像表示相关的重要指标是图像分辨率:组成一幅图像的像素密度

图像的基本属性

1.图像像素数量

2.图像分辨率

3.图像大小

4.图像颜色

5.图像深度

6.图像色调

7.图像饱和度

8.图像亮度

9.图像对比度

10.图像层次

图像可视化模块skimage

io                            读取、保存和显示图片或视频
data                       提供一些测试图片和样本数据
color                           颜色空间变换
filters             图像增强、边缘检测、排序滤波器、自动阈值等
draw               操作于numpy数组上的基本图形绘制,包括线条、矩形、圆和文本等
transform         几何变换或其它变换,如旋转、拉伸和拉东变换等
morphology         形态学操作,如开闭运算、骨架提取等
exposure             图片强度调整,如亮度调整、直方图均衡等
feature                       特征检测与提取等
measure                 图像属性的测量,如相似性或等高线等
segmentation                         图像分割
restoration                           图像恢复
util                                 通用函数
# 图像读取
"""
通过io对图像文件进行读取,存在numpy格式的数组
"""

# from skimage import io
# from matplotlib import pyplot as plt
# file_name = 'coffee.png'
# image = io.imread(fname =file_name)
# print(image.shape)#查看数组形状
# plt.imshow(image)
# plt.show()
#索引操作
"""
通过索引可以选择数组内指定位置的元素
单个元素索引和多个元素索引
  单个元素索引 指定要选择元素的确定行,列,通道位置,取出单个元素
      一维数组单个元素索引操作可以通过数组名[索引位置],取出对应位置元素
      二维矩阵单个元素索引操作通过数组名[行索引x,列索引y],取出第x行y列元素
      三维数组元素索引方式数组名[行索引x,列索引y,通道索引z]
  多个元素索引
      一维数组多个元素索引通过数组名[索引起始位置:索引终止位置]取出起始位置到结束位置的元素
      二维数组多个元素索引通过数组名[起始行:结束行,起始列:结束列]
      三维数组[起始行:结束行,起始列:结束列,起始通道:结束通道]
"""
# 可以选择数组内指定位置的元素
# import numpy as np
# array = np.array([2,3,4,5,6])#定义一维数组
# # print(array[0])
# # print(array[1])
# print(array[0:3])
# #定二维数组
# array2 = np.array([[1,2,3],[2,3,4],[4,5,6]])
# # print(array2[1,0])#第一行第0列
# # print(array2[1,2])#第一行第二列
# print(array2[1:2,1:2])
# #对coffee进行多元素索引裁剪
# from skimage import data
# from matplotlib import pyplot as plt
# image = data.coffee()
# imagel = image[20:200,30:200,:]
# plt.imshow(imagel)
# plt.show()

1.4像素间的关系

邻域关系

4邻域,8邻域,D邻域P18

连通性

两个像素的位置满足相邻关系且两个像素的灰度值满足特定的相似性准则

距离

欧式距离,D4距离,D8距离,明可夫斯基距离

1.5简单图像处理

1.5.1图像基本属性的操作

1.亮度操作

2.对比度操作

import numpy as np
from skimage import data
from matplotlib import pyplot as plt
img = data.coffee()
def change_alpha(img,a):
  img_changed = np.zeros(shape=img.shape,dtype='uint8')
  for i in range(img.shape[0]):
      for j in range(img.shape[1]):
          for k in range(img.shape[2]):
              if img[i,j,k]*a>255:
                  img_changed[i,j,k] =255
              elif img[i,j,k]*a<0:
                  img_changed[i,j,k]=0
              else:
                  img_changed[i,j,k]=img[i,j,k]*a
  return img_changed
if __name__ == '__main__' :
  plt.imshow(change_alpha(img,2))
  plt.show()

a>1对比度增强,a<1减弱,a=1原图

3.颜色通道操作

from skimage import data,io

from matplotlib import pyplot as plt
img = data.coffee()
#取红绿蓝三颜色通道
img_r = img[:,:,0]
img_g = img[:,:,1]
img_b = img[:,:,2]
#分别展示三通道

plt.subplot(2,2,1)
io.imshow(img)

plt.subplot(2,2,2)
io.imshow(img_r)

plt.subplot(2,2,3)
io.imshow(img_g)

plt.subplot(2,2,4)
io.imshow(img_b)

plt.show()


#红色蓝色通道互换
from skimage import data,io
from matplotlib import pyplot as plt
img = data.coffee()
#取红绿蓝三颜色通道
img_r = img[:,:,0]
img_g = img[:,:,1]
img_b = img[:,:,2]
#red和blue互换
temp = img_r
img_r = img_b
img_b = temp
#将互换后的通道颜色重新赋值给图像
img[:,:,0] = img_r
img[:,:,2] = img_b
plt.imshow(img)
plt.show()

1.5.2图像的简单运算

#加减
from matplotlib.font_manager import FontProperties
font_set = FontProperties(fname=r"c:\windows\fonts\simsun.ttc",size=12)
from skimage import data
from matplotlib import pyplot as plt
moon = data.moon()
camera = data.camera()
img_minus = moon - camera
img_plus = moon+camera

plt.subplot(221)
plt.title('月亮图像',fontproperties=font_set)
plt.imshow(moon,cmap='gray')
plt.subplot(222)
plt.title('摄像师图像',fontproperties=font_set)
plt.imshow(camera,cmap='gray')
plt.subplot(223)
plt.title('月亮加摄像师图像',fontproperties=font_set)
plt.imshow(img_plus,cmap='gray')
plt.subplot(224)
plt.title('月亮减摄像师图像',fontproperties=font_set)
plt.imshow(img_minus,cmap='gray')
plt.show()
"""
点运算
  运算对象是输入图像的像素值,即输出图像每个像素的灰度值仅取决于输入图像中对应像素的灰度值
两个特点
  1.根据某种预先设置的规则,将输入图像各个像素本身的灰度逐一转化成输出图像的对应像素的灰度值
  2,点运算不会改变像素的空间位置
分为线性运算与非线性运算
线性运算的原值和目标值通过线性方程完成转换,例如对比度灰度调整,图像反色
非线性运算对应非线性映射函数,例如平方函数,对数函数,截取,阈值函数,多值量化函数。
  灰度幂次变换,灰度对数变换,阈值化处理,直方图均衡化是常见的非线性点运算方法
"""

#幂次变换
from skimage import data,io,exposure
from matplotlib import pyplot as plt
img = data.coffee()
#分别计算gamma=0.2,0.67,25时的图像
img_1=exposure.adjust_gamma(img,0.2)
img_2=exposure.adjust_gamma(img,0.67)
img_3=exposure.adjust_gamma(img,25)
#分别展示原图及结果图像
plt.subplot(221)
plt.title('gamma=1')
io.imshow(img)
plt.subplot(222)
plt.title('gamma=0.2')
io.imshow(img_1)
plt.subplot(223)
plt.title('gamma=0.67')
io.imshow(img_2)
plt.subplot(224)
plt.title('gamma=25')
io.imshow(img_3)
# plt.show()
io.show()
#图像直方图
# 直方图和图像是一对多的关系
#直方图均衡化
"""
通过累计函数对灰度值进行“调整”,实现对比度增强
中心思想把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布
"""
from skimage import data,exposure
from matplotlib import pyplot as plt
img = data.moon()
plt.figure("hist",figsize=(8,8))
arr = img.flatten()
plt.subplot(221)
plt.imshow(img,plt.cm.gray)

plt.subplot(222)
plt.hist(arr,bins=256)
#原始图像直方图
img1=exposure.equalize_hist(img)
arr1=img1.flatten()
plt.subplot(223)
plt.imshow(img1,plt.cm.gray)#均衡化图像
plt.subplot(224)
plt.hist(arr1,bins=256)
#均衡化直方图
plt.show()
"""
图像卷积操作
  循环将图像和卷积逐个元素相乘在求和,结果得到卷积后图像的过程
"""
from skimage import data
import numpy as np
from matplotlib import pyplot as plt
img=data.camera()
arr=np.array(img)
kernel=np.array([[1,0,0],[0,0,0],[0,0,2]])
def matrix_conv(arr,kernel):
  n=len(kernel)
  ans=0
  for i in range(n):
      for j in range(n):
          ans += arr[i,j]*float(kernel[i,j])
  return ans
def conv2d(img,kernel):
  n=len(kernel)
  img1=np.zeros((img.shape[0]+2*(n-1),img.shape[1]+2*(n-1)))
  img1[(n-1):(n+img.shape[0]-1),(n-1):(n+img.shape[1]-1)]=img
  img2 = np.zeros((img1.shape[0]-n+1,img1.shape[1]-n+1))
  for i in range(img1.shape[0]-n+1):
      for j in range(img1.shape[1]-n+1):
          temp = img1[i:i+n,j:j+n]
          img2[i,j]=matrix_conv(temp,kernel)
  new_img=img2[(n-1):(n+img.shape[0]-1),(n-1):(n+img.shape[1]-1)]
  return new_img

img_conv=conv2d(img,kernel)
plt.subplot(1,2,1)
plt.imshow(img,cmap='gray')
plt.subplot(1,2,2)
plt.imshow(img_conv,cmap='gray')
plt.show()

2.彩色图像处理初步

2.1彩色图像的颜色空间

2.1.1RGB颜色空间

#RGB图像显示,R、G、B三通道的图像

from skimage import data,color
from matplotlib import pyplot as plt


def show_rgb():
  img = data.coffee()
  # 显示rgb图像
  plt.subplot(221)

  plt.axis('off') # 不显示坐标轴
  plt.imshow(img) # 显示rgb彩色图像
  # r通道
  plt.subplot(222)
  imgR = img[:, :, 0]

  plt.axis('off')
  plt.setp("gray")
  plt.imshow(imgR,camp='gray')
  # 显示g通道
  plt.subplot(223)
  imgG = img[:, :, 1]

  plt.axis('off')

  plt.imshow(imgG,camp='gray')
  # 显示b通道
  plt.subplot(224)
  imgB = img[:, :, 2]

  plt.axis('off')
 
  plt.imshow(imgB,camp='gray')
  plt.show()

2.1.2HSI颜色空间

色度H 角度表示,反应该颜色接近那个光谱波长 0度红色光谱 120度绿色光谱 240度蓝色光谱

饱和度S由色环的圆心到颜色点半径的表示,距离越长表示饱和度越高,颜色越鲜明

亮度I颜色点到圆柱底部的距离

#rgb->hsi

from skimage import data,color
from matplotlib import pyplot as plt
import math
import numpy as np
import sys


def rgb2hsi(r,g,b):
  r=r/255
  g=g/355
  b=b/255
  num = 0.5*((r-g)+(r-b))
  den=((r-g)*(r-g)+(r-b)*(r-b))**0.5
  if b<=g:
      if den == 0:
          den=sys.float_info.min
      h=math.acos(num/den)

  elif b>g:
      if den == 0:
          den=sys.float_info.min
      h = (2 * math.pi) - math.acos(num / den)
  s=1-(3*min(r,g,b)/(r+g+b))
  i=(r+g+b)/3
  return int(h),int(s*100),int(i*255)
image = data.coffee()
hsi_image=np.zeros(image.shape,dtype='uint8')
for ii in range(image.shape[0]):
  for jj in range(image.shape[1]):
      r,g,b=image[ii,jj,:]
      h,s,i=rgb2hsi(r,g,b)
      hsi_image[ii,jj,:]=(h,s,i)
plt.subplot(331)
plt.axis('off')
plt.imshow(image)

plt.subplot(334)
plt.axis('off')
plt.imshow(image[:,:,0])
plt.subplot(335)
plt.axis('off')
plt.imshow(image[:,:,1])
plt.subplot(336)
plt.axis('off')
plt.imshow(image[:,:,2])

plt.subplot(337)
plt.axis('off')
plt.imshow(hsi_image[:,:,0])#h分量
plt.subplot(338)
plt.axis('off')
plt.imshow(hsi_image[:,:,1])#s分量
plt.subplot(339)
plt.axis('off')
plt.imshow(hsi_image[:,:,2])#i分量
plt.show()

2.2伪彩色图像处理

#根据一定的准则对灰度值赋以彩色,将灰度图像转换为给定彩色分布的图像

#强度分层(灰度分层,灰度分割)

#简单的强度分层技术
from skimage import data,color
from matplotlib import pyplot as plt

import numpy as np

"""
将灰度图像按照灰度值范围划分不同的层级,然后给每个层级赋予不同的颜色
"""
img = data.coffee()
grayimg = color.rgb2gray(img)#将彩色图像转化为灰度图像
plt.axis('off')

plt.imshow(grayimg,cmap='gray')#显示灰度图像
# plt.show()
# print(grayimg.shape)
rows,cols=grayimg.shape
labels = np.zeros([rows,cols])
for i in range(rows):
  for j in range(cols):
      if(grayimg[i,j]<0.4):
          labels[i,j]=0
      elif(grayimg[i,j]<0.8):
          labels[i,j]=1
      else:
          labels[i,j]=2
psdimg=color.label2rgb(labels)#不同的灰度区间采用不同的颜色
plt.axis('off')
plt.imshow(psdimg)#显示强度分层图像
plt.show()
from matplotlib import pyplot as plt
#绘制灰度值到彩色变换关系
L=255
def GetR(gray):
  if gray<L/2:
      return 0
  elif gray>L/4*3:
      return L
  else:
      return 4*gray-2*L
def GetG(gray):
  if gray<L/4:
      return 4*gray
  elif gray>L/4*3:
      return 4*L-4*gray
  else:
      return L
def GetB(gray):
  if gray<L/4:
      return L
  elif gray>L/2:
      return 0
  else:
      return 2*L-4*gray
#设置字体格式
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['font.size']=15
plt.rcParams['axes.unicode_minus']=False

x=[0,64,127,191,255]

#绘制灰度图像到R通道的映射关系
plt.subplot(221)
R = []
for i in x:
  R.append(GetR(i))
plt.plot(x,R,'r--',label = '红色变换')
plt.legend(loc='best')
#绘制灰度图像到G通道的映射关系
plt.subplot(222)
G = []
for i in x:
  G.append(GetG(i))
plt.plot(x,G,'g',label = '绿色变换')
plt.legend(loc='best')
#绘制灰度图像到B通道的映射关系
plt.subplot(223)
B = []
for i in x:
  B.append(GetB(i))
plt.plot(x,B,'b',marker='o',markersize=5,label = '蓝色变换')
plt.legend(loc='best')
#绘制灰度图像到RGB的映射关系
plt.subplot(224)
plt.plot(x,R,'r--')
plt.plot(x,G,'g')
plt.plot(x,B,'b',marker='o',markersize=5)
plt.show()
#灰度图像映射伪彩色图像
from skimage import data,color
from matplotlib import pyplot as plt

import numpy as np
img=data.coffee()
grayimg = color.rgb2gray(img)*255#将彩色图像转化为灰度图像
colorimg = np.zeros(img.shape,dtype='uint8')
for ii in range(img.shape[0]):
  for jj in range(img.shape[1]):
      r,g,b = GetR(grayimg[ii,jj]),GetR(grayimg[ii,jj]),GetB(grayimg[ii,jj])
      colorimg[ii,jj,:]=(r,g,b)
plt.subplot(121)
plt.axis('off')
plt.imshow(grayimg,cmap='gray')#显示灰度图像
plt.subplot(122)
plt.axis('off')
plt.imshow(colorimg)
plt.show()

2.3基于彩色图像的分割

2.3.1 HSI颜色空间的分割

面向颜色处理,用色调H和饱和度S描述色彩,用亮度I描述光的强度

特点:

I分量与图像彩色信息无关

H分量和S分量与人感受颜色的方式是紧密相连的

 

#hsi颜色分割
from skimage import data
from matplotlib import pyplot as plt
import math
import numpy as np
import sys
#定义RGB转HSI
def rgb2hsi(r,g,b):
  r=r/255
  g=g/355
  b=b/255
  num = 0.5*((r-g)+(r-b))
  den=((r-g)*(r-g)+(r-b)*(r-b))**0.5
  if b<=g:
      if den == 0:
          den=sys.float_info.min
      h=math.acos(num/den)

  elif b>g:
      if den == 0:
          den=sys.float_info.min
      h = (2 * math.pi) - math.acos(num / den)
  s=1-(3*min(r,g,b)/(r+g+b))
  i=(r+g+b)/3
  return int(h),int(s*100),int(i*255)
img = data.coffee()
hsi_img = np.zeros(img.shape,dtype='uint8')
for ii in range(img.shape[0]):
  for jj in range(img.shape[1]):
      r,g,b = img[ii,jj,:]
      h,s,i = rgb2hsi(r,g,b)
      hsi_img[ii,jj,:]=(h,s,i)
H=hsi_img[:,:,0]
S=hsi_img[:,:,1]
I=hsi_img[:,:,2]
#生成二值饱和度模板
S_template=np.zeros(S.shape,dtype='uint8')
for i in range(S.shape[0]):
  for j in range(S.shape[1]):
      if S[i,j]>0.3*S.max():
          S_template[i,j]=1
#色调图像与二值饱和度模板相乘可以分割结果C
C=np.zeros(H.shape,dtype='uint8')
for i in range(C.shape[0]):
  for j in range(C.shape[1]):
      C[i,j]=H[i,j]*S_template[i,j]
#显示结果
plt.subplot(231)
plt.axis('off')
plt.imshow(img)
plt.subplot(232)
plt.axis('off')
plt.imshow(H,cmap='gray')
plt.subplot(233)
plt.axis('off')
plt.imshow(S,cmap='gray')
plt.subplot(234)
plt.axis('off')
plt.imshow(I,cmap='gray')
plt.subplot(235)
plt.axis('off')
plt.imshow(S_template,cmap='gray')
plt.subplot(236)
plt.axis('off')
plt.imshow(C,cmap='gray')
plt.show()

2.3.2RGB颜色分割

from skimage import data
from matplotlib import pyplot as plt
import math
import numpy as np
import sys
img = data.coffee()
r = img[:,:,0]
g = img[:,:,1]
b = img[:,:,2]
#rgb颜色空间的分割
#选择样本区域
r1=r[128:255,85:169]
print(r1)
#计算该区域中彩色点的平均向量a的红色部分
r1_u=np.mean(r1)
# #计算样本点红色分量的样本差
r1_d=0.0
for i in range(r1.shape[0]):
  for j in range(r1.shape[1]):
      r1_d = r1_d +(r1[i,j]-r1_u)*(r1[i,j]-r1_u)
r1_d=math.sqrt(r1_d/r1.shape[0]/r1.shape[1])
#寻找符合条件的点,r2为红色分割图像
r2 = np.zeros(r.shape,dtype='uint8')
for i in range(r1.shape[0]):
  for j in range(r1.shape[1]):
      if r[i,j]>=(r1_u-1.25*r1_d) and r[i,j]<=(r1_u+1.25*r1_d):
          r2[i,j]=1
#img2为根据红色分割后的rgb图像
img2 = np.zeros(img.shape,dtype='uint8')
for i in range(r1.shape[0]):
  for j in range(r1.shape[1]):
      if r2[i,j] == 1:
          img2[i,j,:]=img[i,j,:]
#结果
plt.subplot(231)
plt.axis('off')
plt.imshow(img)#原始
plt.subplot(232)
plt.axis('off')
plt.imshow(r,cmap='gray')#r分量
plt.subplot(233)
plt.axis('off')
plt.imshow(g,cmap='gray')#g分量
plt.subplot(234)
plt.axis('off')
plt.imshow(b,cmap='gray')#b分量
plt.subplot(235)
plt.axis('off')
plt.imshow(r2,cmap='gray')#红色分割
plt.subplot(236)
plt.axis('off')
plt.imshow(img2)#分割后的rgb
plt.show()

2.4彩色图像灰度化

灰度图像能以较少的数据表征图像的大部分特征

最大值灰度方法,平均灰度方法,加权平均灰度方法p48

from skimage import data
from matplotlib import pyplot as plt
import numpy as np
img = data.coffee()
#初始化灰度图像
max_gray = np.zeros(img.shape[0:2],dtype='uint8')
ave_gray = np.zeros(img.shape[0:2],dtype='uint8')
weight_gray = np.zeros(img.shape[0:2],dtype='uint8')
for ii in range(img.shape[0]):
  for jj in range(img.shape[1]):
      r,g,b = img[ii,jj,:]
      #最大值灰度化方法
      max_gray[ii,jj]=max(r,g,b)
      #平均值灰度化方法
      ave_gray[ii,jj]=(r+g+b)/3
      #加权平均灰度化方法
      weight_gray[ii,jj]=0.30*r+0.59*g+0.11*b
plt.subplot(221)
plt.axis('off')
plt.imshow(img)
plt.subplot(222)
plt.axis('off')
plt.imshow(max_gray,cmap='gray')
plt.subplot(223)
plt.axis('off')
plt.imshow(ave_gray,cmap='gray')
plt.subplot(224)
plt.axis('off')
plt.imshow(weight_gray,cmap='gray')
plt.show()

3.空间滤波

3.1空间滤波基础

空间域指的是图像平面本身,相对于变换域而言

空间域的图像处理是图像本身不进行频域变换,以图像中的像素为基础对图像进行处理。

空间域的图像处理是在像素的邻域进行操作,如空间域平滑处理是通过像素的邻域平滑图像,空间域锐化处理通过像素的邻域锐化图像;频域的图像处理首先将图像变换到变换域,然后在频域进行处理,处理之后将其反变换至空间域。

频域处理主要包括低通滤波和高通滤波;低通滤波可以使低频信号通过,而高于所设的的临界值的高频信号则被阻隔或减弱,可用于去除图像的噪声,相当于空间域平滑处理;高通滤波可以使高频信号通过,低于所设的的临界值的低频信号则被阻隔或减弱,可增强图像的轮廓边缘等高频信号,相当于空间域的锐化处理。

3.1.1空间滤波机理

在待处理的图像上逐像素的移动模板,在每个像素点,滤波器的响应通过事先定义的关系计算

线性滤波器:滤波器在图像像素上执行的是线性操作;同理可得非线性滤波器

线性滤波器:均值滤波器

非线性滤波器:统计排序滤波器(最大值,最小值,中值滤波器)

实现空间滤波邻域处理时,需要考虑的一个问题是滤波中心靠近图像边界时如何计算空间滤波器的响应。

考虑一个大小为 m x n 的模板,当模板中心距离图像左边界或右边界为( n -1)/2个像素时,该模板有一条边与图像左边界或右边界重合;当模板中心距离图像上边界或下边界为( m -1)/2个像素时,该模板有一条边与图像上边界或下边界重合。此时如果模板的中心继续向图像边界靠近,模板的行或列就会处于图像平面之外。

有多种方法可以解决上述问题,较简单的方法是将模板中心点的移动范围限制在距离图像左边界或右边界不小于( n -1)/2个像素,且距离图像上边界或下边界不小于( m -1)/2个像素。这种解决方法将使处理后的图像比原始图像稍小,可以将未被处理的像素点的灰度值直接复制到滤波结果处,以保持滤波结果与原始图像尺寸一致。

另一种解决方法是在图像的左边界和右边界以外各补上( n -1)/2列灰度为零的像素点(其灰度值可以为其他常量值,也可以是边界像素的灰度值),在图像的上边界和下边界以外各补上( m -1)/2行灰度为零的像素点,然后再进行滤波处理,处理后的图像与原始图像尺寸一致。

#补0 线性滤波
import numpy as np
def corrl2d(img,window):
  m=window.shape[0]
  n=window.shape[1]
  #边界通过0灰度值填补
  img1=np.zeros((img.shape[0]+m-1,img.shape[1]+n-1))
  img1[(m-1)//2:(img.shape[0]+(m-1)//2),(n-1)//2:(img.shape[1]+(n-1)//2)]=img
  img2 = np.zeros(img.shape)
  for i in range(img2.shape[0]):
      for j in range(img2.shape[1]):
          temp = img1[i:i+m,j:j+n]
          img2[i,j]=np.sum(np.multiply(temp,window))
  return (img1,img2)
#window代表滤波模板,img代表原始矩阵
window=np.array([[1,0,0],[0,0,0],[0,0,2]])
img=np.array([[1,2,1,0,2,3],[0,1,1,2,0,1],[3,0,2,1,2,1],[0,1,1,0,0,1],[1,1,3,2,2,0],[0,0,1,0,1,0]])
#img1代表边界填充后矩阵,img2代表空间滤波结果
img1,img2=corrl2d(img,window)
print(img1)
print(img2)

3.1.2空间滤波器模板

若空间滤波器模板的系数从1开始进行索引,从左到右索引值递增,先索引第一行的每个模板系数,再一次索引下一行的每个模板系数

mn的线性滤波器模板有mn个模板系数,这m*n个系数的值决定了线性空间滤波器的功能

假设要实现3*3的平滑空间滤波器,方法是使得滤波器模板的系数均为1/9

具体看书p55

3.2平滑处理

平骨处理常用于模糊处理和降低噪声。平滑滤波器使用给定邻域内像素的平均灰度值或逻辑运算值代替原始图像中像素的灰度值,这种处理降低了图像灰度的“尖锐”变化。然而,图像边缘也是由图像灰度尖锐变化带来的特性,因此平滑空间滤波器有边缘模糊化的负面效应。平滑空间滤波器可分为平滑线性空间滤波器和平滑非线性空间滤波器。具有代表性的平滑非线性空间滤波器为统计排序滤波器。

3.2.1平滑线性空间滤波器(均值滤波器)

平滑滤波器使用给定邻域内像素灰度值的简单平均值或者加权平均值

应用:降低噪声,去除不相关的细节,使得不相关的细节与背景糅合在一起,从而使感兴趣模板更加易于检测,此时模板大小与不相关细节的尺寸有关

滤波器响应

R=(1/(m*n))\sum_{i=1}^{m*n}{z_{i}}^{}

R是由mn大小的模板定义的均值滤波器响应,该模板的所由系数均为1/mn,这种滤波器也称为盒装滤波器,是最简单的均值滤波器

#盒装滤波
import numpy as np
from scipy import signal
from skimage import data
from matplotlib import pyplot as plt
def correl2d(img,window):
  #使用滤波器实现图像的空间相关
  #mode = 'same'#表示输出尺寸等于输入尺寸
  #boundary = 'fill'#表示滤波前,用常量值填充原始图像边缘,默认常量值为0
  s=signal.correlate2d(img,window,mode='same',boundary='fill')
  return s.astype(np.uint8)
img = data.camera()
window1 = np.ones((3,3))/(3**2)#3*3盒装滤波模板
window2=np.ones((5,5))/(5**2)#5*5盒装滤波模板
window3=np.ones((9,9))/(9**2)#9*9盒装滤波模板
#生成滤波结果
new_img1=correl2d(img,window1)
new_img2=correl2d(img,window2)
new_img3=correl2d(img,window3)
#显示图像
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.subplot(221)
plt.imshow(img,cmap='gray')
plt.axis('off')
plt.title('原始图像')
plt.subplot(222)
plt.imshow(new_img1,cmap='gray')
plt.axis('off')
plt.title('3*3盒装滤波结果')
plt.subplot(223)
plt.imshow(new_img2,cmap='gray')
plt.axis('off')
plt.title('5*5盒装滤波结果')
plt.subplot(224)
plt.imshow(new_img3,cmap='gray')
plt.axis('off')
plt.title('9*9盒装滤波结果')
plt.show()

常用的均值滤波是加权平均的,即在计算滤波器响应是邻域中某些像素的权重较大。

img1/16

高斯平滑滤波器对于抑制服从正态分布的噪声有效,具体看p58

#高斯平滑滤波
import numpy as np
from scipy import signal
from skimage import data
from matplotlib import pyplot as plt
import math
#定义二维灰度图像空间滤波函数
def correl2d(img,window):
  #使用滤波器实现图像的空间相关
#     #mode = 'same'#表示输出尺寸等于输入尺寸
#     #boundary = 'fill'#表示滤波前,用常量值填充原始图像边缘,默认常量值为0
    s=signal.correlate2d(img,window,mode='same',boundary='fill')
    return s.astype(np.uint8)
#定义二维高斯函数
def gauss(i,j,sigma):
  return 1/(2*math.pi*sigma**2)*math.exp(-(i**2+j**2)/(2*sigma**2))
# 定义radius*radius的高斯平滑模板
def gauss_window(radius,sigma):
  window = np.zeros((radius*2+1,radius*2+1))
  for i in range(-radius,radius+1):
      for j in range(-radius,radius+1):
          window[i+radius][j+radius]=gauss(i,j,sigma)
  return window/np.sum(window)
img=data.camera()
#3*3高斯平滑滤波器
window1=gauss_window(3,1.0)
#5
window2=gauss_window(5,1.0)
#9
window3 = gauss_window(9,1.0)
#结果
new_img1=correl2d(img,window1)
new_img2=correl2d(img,window2)
new_img3=correl2d(img,window3)
#显示
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.subplot(221)
plt.imshow(img)
plt.axis('off')
plt.title('原始图像')
plt.subplot(222)
plt.imshow(new_img1,cmap='gray')
plt.axis('off')
plt.title('3*3高斯平滑滤波结果')
plt.subplot(223)
plt.imshow(new_img2,cmap='gray')
plt.axis('off')
plt.title('5*5高斯平滑滤波结果')
plt.subplot(224)
plt.imshow(new_img3,cmap='gray')
plt.axis('off')
plt.title('9*9高斯平滑滤波结果')
plt.show()

3.3.2统计排序滤波

典型的非线性平滑滤波器

对模板覆盖的像素的灰度值进行排序,选择有代表性的灰度值作为统计排序滤波器响应

包括(最大值滤波器,中值滤波器,最小值滤波器)

最大值滤波器:用像素邻域内的最大值代替该像素的灰度值,用于寻找最亮点

中值滤波器:用像素邻域内的中间值代替该像素的灰度值,用于降噪

最小值滤波器:用像素邻域内的最小值代替该像素的灰度值,用于寻找最暗点

具体看书p61

#中值滤波
from skimage import data,util
from scipy import ndimage
from matplotlib import pyplot as plt
img=data.astronaut()[:,:,0]
#对图像加入椒盐噪声
noise_img=util.random_noise(img,mode='s&p',seed=None,clip=True)
#中值滤波
n=3
new_img=ndimage.median_filter(noise_img,(n,n))
#显示
plt.subplot(131)
plt.imshow(img,cmap='gray')
plt.subplot(132)
plt.imshow(noise_img,cmap='gray')
plt.subplot(133)
plt.imshow(new_img,cmap='gray')
plt.show()
#彩色图像中值滤波
from skimage import data,util
from scipy import ndimage
from matplotlib import pyplot as plt
import numpy as np
img=data.astronaut()
noise_img=np.zeros(img.shape)
new_img=np.zeros(img.shape)
for i in range(3):
  grayimg=data.astronaut()[:,:,i]
  #对图像加入椒盐噪声
  noise_img[:,:,i]=util.random_noise(grayimg,mode='s&p',seed=None,clip=True)
  #中值滤波
  n=3
  new_img[:,:,i]=ndimage.median_filter(noise_img[:,:,i],(n,n))
#图像
plt.subplot(131)
plt.imshow(img,cmap='gray')
plt.subplot(132)
plt.imshow(noise_img,cmap='gray')
plt.subplot(133)
plt.imshow(new_img,cmap='gray')
plt.show()
#使用3*3的最大值和最小值滤波器
from skimage import data,util
from scipy import ndimage
from matplotlib import pyplot as plt
img=data.astronaut()[:,:,0]
#加入胡椒噪声
pepper_img=util.random_noise(img,mode='pepper',seed=None,clip=True)
#盐粒噪声
salt_img=util.random_noise(img,mode='salt',seed=None,clip=True)
n=3
#最大值滤波
max_img=ndimage.maximum_filter(pepper_img,(n,n))
#最小值滤波
min_img=ndimage.minimum_filter(salt_img,(n,n))
#显示
plt.subplot(231)
plt.imshow(img,cmap='gray')
plt.subplot(232)
plt.imshow(pepper_img,cmap='gray')
plt.subplot(233)
plt.imshow(salt_img,cmap='gray')
plt.subplot(234)
plt.imshow(max_img,cmap='gray')
plt.subplot(235)
plt.imshow(min_img,cmap='gray')
plt.show()

3.3锐化处理

锐化处理的目的是增强图像中目标的细节、边缘、轮廓和其他灰度突变,削弱了灰度变化缓慢的区域。由于微分是对函数的局部变化率的一种描述,因此图像锐化算法的实现可基于空间微分。图像平滑处理有边缘和细节模糊的负面效应。图像平滑和图像锐化在逻辑上是相反的操作,因此也可以使用原始图像减去平滑处理后的图像实现锐化处理,这称为反锐化掩蔽。

3.3.1一阶微分算子

任意一阶微分的定义满足以下两点:在灰度不变的区域微分值为0 ,在灰度变化的区域微分值非0

具体看书p65

3*3邻域

z1z2z3
z4 z5 z6
z7 z8 z9

robert交叉梯度算子

-10
0 1

正对角线梯度算子

0-1
1 0

负对角线梯度算子

"""
求罗伯特边缘图像和梯度图像代码如下
调用了skimage.filters中的roberts_pos_diag(),roberts_neg_diag(),roberts()方法,分别求取罗伯特正对角线边缘图像,罗伯特副对角线边缘图像,罗伯特梯度图像
"""
from skimage import data,filters
from matplotlib import pyplot as plt
img = data.camera()
#罗伯特交叉梯度算子
img_robert_pos=filters.roberts_pos_diag(img)
img_robert_neg=filters.roberts_neg_diag(img)
img_robert=filters.roberts(img)
#显示
plt.subplot(231)
plt.imshow(img,cmap='gray')
plt.subplot(232)
plt.imshow(img_robert_pos,cmap='gray')
plt.subplot(233)
plt.imshow(img_robert_neg,cmap='gray')
plt.subplot(234)
plt.imshow(img_robert,cmap='gray')

plt.show()
$$
g(x,y)=f(x,y)+c*M(x,y)
$$

f是原图像 M是梯度图像 c是锐化强度系数

一般注重奇数模板,具体看书p67~p68

sobel算子

-1-2-1
0 0 0
1 2 1

水平索贝尔算子

-101
-2 0 2
-1 0 1

竖直索贝尔算子

#求sebel边缘图像和梯度图像代码
from skimage import data,filters
from matplotlib import pyplot as plt
img = data.camera()
#sobel算子
img_sobel_h=filters.sobel_h(img)
img_sobel_v=filters.sobel_v(img)
img_sobel=filters.sobel(img)
#显示
plt.subplot(231)
plt.imshow(img,cmap='gray')
plt.subplot(232)
plt.imshow(img_sobel_h,cmap='gray')#水平sobel边缘图像
plt.subplot(233)
plt.imshow(img_sobel_v,cmap='gray')#竖直sobel边缘图像
plt.subplot(234)
plt.imshow(img_sobel,cmap='gray')#sobel梯度图像
# plt.subplot(235)
# plt.imshow(img+200*img_sobel,cmap='gray')
plt.show()

3.3.2二阶微分算子

任意二阶微分的定义满足以下三点:在灰度不变的区域微分值为0 ,在灰度台阶或斜坡的起点处微分值非0;沿着斜坡的微分值为0

具体看书p69~70

拉普拉斯算子

010
1 -4 1
0 1 0

扩展的拉普拉斯算子

111
1 -8 1
1 1 1

(以上不经常使用

以下经常使用)

中心系数为正的拉普拉斯算子

0-10
-1 4 -1
0 -1 0

中心系数为正的扩展的拉普拉斯算子

-1-1-1
-1 8 -1
-1 -1 -1

对原始图像使用拉普拉斯算子进行空间滤波可得到拉普拉斯图像,将拉普拉斯图像以一定比例叠加到原始图像(该比例系数的符号与拉普拉斯模板中心系数的符号一致),可对原始图像进行拉普拉斯锐化增强

#拉普拉斯增强
from skimage import data,filters
from matplotlib import pyplot as plt
img = data.camera()
img_laplace=filters.laplace(img,ksize=3,mask=None)
img_enhance=img+img_laplace
plt.subplot(131)
plt.imshow(img)
plt.subplot(132)
plt.imshow(img_laplace,cmap='gray')
plt.subplot(133)
plt.imshow(img_enhance,cmap='gray')
plt.show()

3.3.3反锐化掩蔽

图像平滑处理有边缘和细节模糊的负面效应。图像平滑和图像锐化在逻辑上是相反的操作,因此也可以使用原始图像减去平滑处理后的图像实现锐化处理,这称为反锐化掩蔽。

三步骤:首先通过平滑滤波得到模糊图像,然后从原始图像减去模糊图像得到差值图像,最后将差值图像叠加到原始图像

$$
d(x,y)=f(x,y)-s(x,y)
$$

f原始图像,s平滑处理所得模糊图像 ,d差值图像

$$
g(x,y)=f(x,y)+c*d(x,y)
$$

权重系数c,c=1称为反锐化掩蔽,c>1称为高提升滤波,c<1时不强调反锐化掩蔽效果

#反锐化掩蔽
import numpy as np
from scipy import signal
from skimage import data
from matplotlib import pyplot as plt
def corrl2d(img,window):
  s=signal.correlate2d(img,window,mode='same',boundary='fill')
  return s
img = data.camera()

window = np.ones((3,3))/(3**2)#3*3盒装滤波
img_blur=corrl2d(img,window)
img_edge=img-img_blur
img_enhance = img+img_edge
plt.subplot(221)
plt.imshow(img,cmap='gray')
plt.subplot(222)
plt.imshow(img_blur,cmap='gray')#模糊图像
plt.subplot(223)
plt.imshow(img_edge,cmap='gray')#差值图像
plt.subplot(224)
plt.imshow(img_enhance,cmap='gray')#锐化增强图像
plt.show()

3.4混合空间增强

综合利用平滑滤波器,锐化滤波器,灰度拉伸等对图像进行处理

"""
人体全身骨骼扫描图像
首先使用拉普拉斯锐化方法突出图像细节,再使用索贝尔梯度处理方法突出图像边缘,
并使用平滑的梯度图像用于掩蔽拉普拉斯锐化增强图像,最后使用灰度幂律变换增强图像的灰度动态范围

第一步对原始图像进行拉普拉斯锐化,得到拉普拉斯锐化图像;
第二步将原始图像与拉普拉斯锐化图像相加,得到拉普拉斯锐化增强图像;
第三步对原始图像进行索贝尔算子梯度处理,得到索贝尔图像;
第四步使用5x5均值滤波器对索贝尔图像进行平滑,得到平滑的索贝尔图像;
第五步将拉普拉斯锐化增强图像与平滑索贝尔图像相乘,得到掩蔽图像;
第六步将原始图像与掩蔽图像相加,得到锐化增强图像;
第七步对锐化增强图像进行灰度幂律变换,得到最终的结果。
"""
# from PIL import Image
#
# im = Image.open('boneScan.png')
#
# im.save(("boneScan_new.tif"),quality=95)
# 人体全身骨骼扫描图像的混合空间增强的代码如下
import numpy as np
from skimage import io,filters
from matplotlib import pyplot as plt
#空间滤波函数
def corrl2d(img,window):
  m=window.shape[0]
  n=window.shape[1]
  #边界通过0灰度值填补
  img1=np.zeros((img.shape[0]+m-1,img.shape[1]+n-1))
  img1[(m-1)//2:(img.shape[0]+(m-1)//2),(n-1)//2:(img.shape[1]+(n-1)//2)]=img
  img2 = np.zeros(img.shape)
  for i in range(img2.shape[0]):
      for j in range(img2.shape[1]):
          temp = img1[i:i+m,j:j+n]
          img2[i,j]=np.sum(np.multiply(temp,window))
  return img2
img=io.imread('boneScan_new.tif',as_gray=True)
# img_laplace为原始图像经过拉普拉斯变换后的结果
window=np.array([[-1,-1,-1],[-1,8,-1],[-1,-1,-1]])
img_laplce=corrl2d(img,window)
img_laplce=255*(img_laplce-img_laplce.min())/(img_laplce.max()-img_laplce.min())
# 将img和img_laplace相加得到锐化增强函数img_laplace
img_laplce_enhance=img+img_laplce
#对原始图像进行sobel后的结果
img_sobel=filters.sobel(img)
#5*5的均值滤波器平滑后的sobel图像
window_mean = np.ones((5, 5)) / (5 ** 2) # 5*5盒装滤波模板
img_sobel_mean=corrl2d(img_sobel,window_mean)
# 将img_laplce_enhance与 img_sobel_mean相乘得到锐化结果
img_sharp = img_laplce_enhance*img_sobel_mean
# 将img,img_sharp相加得到锐化增强图像
img_sharp_enhance=img+img_sharp
# 对img_sharp_enhance灰度幂律变换得到最终结果
img_enhance = img_sharp_enhance**0.5
#显示
imgList = [img,img_laplce,img_laplce_enhance,img_sobel,img_sobel_mean,img_sharp,img_sharp_enhance,img_enhance]

for grayImg in imgList:
  plt.figure()
  plt.axis('off')
  plt.imshow(grayImg,cmap='gray')
plt.show()

4.频域滤波

首先通过正向傅里叶变换将原始图像从空间域转到频域,然后使用频域滤波器将某些频率成分过滤掉,保留某些特定频率,最后使用傅里叶逆变换将滤波后的频域图像重新转换到空间域,得到处理后的图像。

4.1傅里叶变换

4.1.1一维傅里叶变换

F(u)=(1/M)*\sum_{x=0}^{M-1}f(x)*e^{-i2\pi ux/M }

 

具体看书p80

#一组函数及傅里叶变换示例代码
import matplotlib.pyplot as plt
import numpy as np
#中文显示工具
def set_ch():
  from pylab import mpl
  mpl.rcParams['font.sans-serif']=['FangSong']
  mpl.rcParams['axes.unicode_minus']=False
set_ch()
def show(ori_func,ft,sampling_period=5):
  n=len(ori_func)
  interval = sampling_period/n
  #绘制原始函数
  plt.subplot(211)
  plt.plot(np.arange(0,sampling_period,interval),ori_func,'black')
  plt.xlabel('时间'),plt.ylabel('振幅')
  plt.title('原始信号')
  #绘制变换后的函数
  plt.subplot(212)
  frequency=np.arange(n/2)/(n*interval)
  nttf=abs(ft[range(int(n/2))]/n)
  plt.plot(frequency,nttf,'red')
  plt.xlabel('频率(HZ)'),plt.ylabel('频谱')
  plt.title('傅里叶变换结果')
  plt.show()
#生成频率为1(角速度为2*pi)的正弦波
time = np.arange(0,5,.005)
x=np.sin(2*np.pi*1*time)
y=np.fft.fft(x)
show(x,y)
#对3个正弦波进行叠加
x2=np.sin(2*np.pi*20*time)
x3=np.sin(2*np.pi*60*time)
x+=x2+x3
y=np.fft.fft(x)
show(x,y)

#方波傅里叶变换
x=np.zeros(len(time))
x[::20]=1
y=np.fft.fft(x)
show(x,y)

#脉冲傅里叶变换
x=np.zeros(len(time))
x[380:400]=np.arange(0,1,.05)
x[400:420]=np.arange(1,0,-.05)
y=np.fft.fft(x)
show(x,y)

 

5.图像特征提取

6.图像压缩

7.图像小波变换与多分辨率