图像处理与计算机视觉

一、图像处理基本操作

1、图片的打开与显示

from PIL import Image
import matplotlib.pyplot as plt
img=Image.open('tupian\\mao.png')
plt.figure("mao")
plt.imshow(img)
plt.show()

打开图片后,可以使用一些属性来查看图片信息,如

print (img. size) #图片的尺寸
print (img. mode) #图片的模式
print (img. format) #图片的格式


2、图片的保存

from PIL import Image
import matplotlib.pyplot as plt
plt.ion()
img=Image.open('tupian\\mao.png')
plt.figure("mao")
plt.imshow(img)
plt.show()
img.save('tupian\\mao1.bmp')
plt.pause(1)
plt.close()

3、图像通道

(1)彩色图像转灰度图
from PIL import Image
import matplotlib.pyplot as plt
img=Image.open('tupian\\mao.png')
gray=img.convert('L')
plt.figure("mao")
plt.imshow(gray,cmap='gray')
plt.axis('off')
plt.show()


(2)通道分离与合并
from PIL import Image
import matplotlib.pyplot as plt
img=Image.open('tupian\\mao.png')
gray=img.convert('L')#转换成灰度
r,g,b=img.split()#分离三通道
pic=Image.merge('RGB',(r,g,b))#合并三通道
plt.figure("mao")
plt.subplot(2,3,1)
plt.title('origin')
plt.imshow(img),plt.axis('off')
plt.subplot(2,3,2),plt.title('gray')
plt.imshow(gray,cmap='gray'),plt.axis('off')
plt.subplot(2,3,3),plt.title('merge')
plt.imshow(pic),plt.axis('off')
plt.subplot(2,3,4),plt.title('r')
plt.imshow(r,cmap='gray'),plt.axis('off')
plt.subplot(2,3,5),plt.title('g')
plt.imshow(g,cmap='gray'),plt.axis('off')
plt.subplot(2,3,6),plt.title('g')
plt.imshow(b,cmap='gray'),plt.axis('off')
plt.show()


4、裁剪图片

from PIL import Image
import matplotlib.pyplot as plt
img=Image.open('tupian\\mao.png')
plt.figure("mao")
plt.subplot(1,2,1),plt.title('orign')
plt.imshow(img),plt.axis('off')
box=(290,50,540,260)
roi=img.crop(box)
plt.subplot(1,2,2),plt.title('roi')
plt.imshow(roi),plt.axis('off')
plt.show()


5、几何变换

(1)图像的缩放
from PIL import Image
import matplotlib.pyplot as plt
img=Image.open('tupian\\mao.png')
plt.figure("mao")
dst=img.resize((128, 128))
plt.imshow(dst)
plt.show()


(2)图像的旋转
from PIL import Image
import matplotlib.pyplot as plt
img=Image.open('tupian\\mao.png')
plt.figure("mao")
dst=img.rotate(45)
plt.imshow(dst)
plt.show()


(3)转换图像
from PIL import Image
import matplotlib.pyplot as plt
img=Image.open('tupian\\mao.png')
plt.figure("mao")
dst=img.transpose(Image.FLIP_LEFT_RIGHT)#左右互换
#dst=img.transpose(Image.FLIP_TOP_BOTTOM)#上下互换
#dst=img.transpose(Image.ROTATE_90)#顺时针旋转
plt.imshow(dst)
plt.show()


二、图像算术/逻辑增强与直方图分析

1、画灰度图直方图

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img=np.array(Image.open('tupian\\mao1.jpg').convert('L'))
plt.figure("mao1")
arr=img.flatten()
n,bins,patches=plt.hist(arr,bins=256,facecolor='green',alpha=0.75)
plt.show()


2、彩色图片直方图

from PIL import Image
import  numpy as np
import matplotlib.pyplot as plt
src=Image.open('tupian\\mao1.jpg')
r,g,b=src.split()
plt.figure("mao1")
ar=np.array(r).flatten()
plt.hist(ar,bins=256,facecolor='r',edgecolor='r')
ag=np.array(g).flatten()
plt.hist(ag,bins=256,facecolor='g',edgecolor='g')
ab=np.array(b).flatten()
plt.hist(ab,bins=256,facecolor='b',edgecolor='b')
plt.show()


三、图像的卷积与空间域滤波

1、2D滤波器

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('tupian\\mao.png',0)#直接读为灰度图像
img1=np.float32(img)#转化数值类型
kernel=np.ones((5,5),np.float32)/25
dst=cv2.filter2D(img1,-1,kernel)
plt.subplot(1,2,1),plt.imshow(img1,'gray')
plt.subplot(1,2,2),plt.imshow(dst,'gray')
plt.show()


2、均值滤波

import cv2
import matplotlib.pyplot as plt
img=cv2.imread('tupian\\mao.png',0)#直接读为灰度图像
blur=cv2.blur(img,(3,5))#模板大小3*5
plt.subplot(1,2,1),plt.imshow(img,'gray')
plt.subplot(1,2,2),plt.imshow(blur,'gray')
plt.show()


3、高斯模糊

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('tupian\\mao.png',0)#直接读为灰度图像
for i in range(2000):#添加噪声
    temp_x=np.random.randint(0,img.shape[0])
    temp_y = np.random.randint(0, img.shape[1])
img[temp_x][temp_y]=255
blur=cv2.GaussianBlur(img,(5,5),0)
plt.subplot(1,2,1),plt.imshow(img,'gray')
plt.subplot(1,2,2),plt.imshow(blur,'gray')
plt.show()


4、中值滤波

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('tupian\\mao.png',0)#直接读为灰度图像
for i in range(2000):#添加噪声
    temp_x=np.random.randint(0,img.shape[0])
    temp_y = np.random.randint(0, img.shape[1])
img[temp_x][temp_y]=255
blur=cv2.medianBlur(img,5)
plt.subplot(1,2,1),plt.imshow(img,'gray')
plt.subplot(1,2,2),plt.imshow(blur,'gray')
plt.show()


5、双边滤波

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('tupian\\mao.png',0)#直接读为灰度图像
for i in range(2000):#添加噪声
    temp_x=np.random.randint(0,img.shape[0])
    temp_y = np.random.randint(0, img.shape[1])
    img[temp_x][temp_y]=255
blur=cv2.bilateralFilter(img,9,75,75)
plt.subplot(1,2,1),plt.imshow(img,'gray')
plt.subplot(1,2,2),plt.imshow(blur,'gray')
plt.show()


四、图像的傅里叶变换与频率域增强

1、图像压缩

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('tupian\\mao1.jpg',0)#直接读为灰度图像
f=np.fft.fft2(img)
fshift=np.fft.fftshift(f)
s1=np.log(np.abs(f))
s2=np.log(np.abs(fshift))
plt.subplot(121),plt.imshow(s1,'gray'),plt.title('original')
plt.subplot(122),plt.imshow(s2,'gray'),plt.title('center')
plt.show()


2、相位图像

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('tupian\\mao1.jpg',0)#直接读为灰度图像
f=np.fft.fft2(img)
fshift=np.fft.fftshift(f)
ph_f=np.angle(f)
ph_fshift=np.angle(fshift)
plt.subplot(121),plt.imshow(ph_f,'gray'),plt.title('original')
plt.subplot(122),plt.imshow(ph_fshift,'gray'),plt.title('center')
plt.show()


3、相位图像优化

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('tupian\\mao1.jpg',0)#直接读为灰度图像
f=np.fft.fft2(img)
fshift=np.fft.fftshift(f)
s1=np.log(np.abs(fshift))
plt.subplot(131),plt.imshow(img,'gray'),plt.title('original')
plt.subplot(132),plt.imshow(s1,'gray'),plt.title('center')
flshit=np.fft.ifftshift(fshift)
img_back=np.fft.ifft2(fshift)
img_back=np.abs(img_back)
plt.subplot(133),plt.imshow(img_back,'gray'),plt.title('img_back')
plt.show()


4、振幅相位及结合

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('tupian\\mao1.jpg',0)#直接读为灰度图像
f = np.fft.fft2(img)
fshift=np.fft.fftshift(f)
s1=np.log(np.abs(fshift))
plt.subplot(221),plt.imshow(img,'gray'),plt.title('original')
plt.xticks([]),plt.yticks([])
#---------------------------------------------------
f1shift=np.fft.ifftshift(np.abs(fshift))
img_back=np.fft.ifft2(f1shift)
img_back=np.abs(img_back)
img_back(img_back-np.amin(img_back))/(np.amax(img_back)-np.amin(img_back))
plt.subplot(222),plt.imshow(img_back,'gray'),plt.title('only Amplitude')
plt.xticks([]),plt.yticks([])
#---------------------------------------------------
f2shift=np.fft.ifftshift(np.angle(fshift))
img_back=np.fft.ifft2(f2shift)
img_back=np.abs(img_back)
img_back(img_back-np.amin(img_back))/(np.amax(img_back)-np.amin(img_back))
plt.subplot(223),plt.imshow(img_back,'gray'),plt.title('only phase')
plt.xticks([]),plt.yticks([])
#---------------------------------------------------
s1=np.abs(fshift)
s1_angle=np.angle(fshift)
s1_real=s1*np.cos(s1_angle)
s1_img=s1*np.sin(s1_angle)
s2=np.zeros(img.shape,dtype=complex)
s2.real=np.array(s1_real)
s2.imag=np.array(s1_img)
f2shift=np.fft.ifftshift(s2)
img_back=np.fft.ifft2(f2shift)
imd_back=np.fft.abs(img_back)
img_back(img_back-np.amin(img_back))/(np.amax(img_back)-np.amin(img_back))
plt.subplot(224),plt.imshow(img_back,'gray'),plt.title('another way')
plt.xticks([]),plt.yticks([])


五、形态学图像处理

1、膨胀与侵蚀

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('tupian\\mao1.bmp',0)
#opencv定义结构元素
kernel=cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
eroded=cv2.erode(img,kernel)
cv2.imshow("Eroded Image",eroded)
dilated=cv2.dilate(img,kernel)
cv2.imshow("Dilated Image",dilated)
cv2.imshow("Origin",img)
#Numpy定义的结构元素
NpKernel=np.uint8(np.ones((3,3)))
Nperoded=cv2.erode(img,NpKernel)
cv2.imshow("Eroded by NumPy kernel",Nperoded)
cv2.waitKey(0)
cv2.destroyAllWindows()


2、开运算与闭运算

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('tupian\\mao1.bmp', 0)
# opencv定义结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
closed = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imshow("CLOSE", closed)
opened = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imshow("Open", opened)
cv2.waitKey(0)
cv2.destroyAllWindows()


3、形态学运算检测边缘

import cv2
import numpy as np
import matplotlib.pyplot as plt

image = cv2.imread('tupian\\mao1.jpg', 0)
element = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
dilate = cv2.dilate(image, element)
erode = cv2.erode(image, element)
result = cv2.absdiff(dilate, erode)
retval, result = cv2.threshold(result, 40, 255, cv2.THRESH_BINARY)
result = cv2.bitwise_not(result)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()


4、形态学运算检测拐角

import cv2

image = cv2.imread('tupian\\mao1.jpg', 0)
origin = cv2.imread('tupian\\mao1.jpg')
cross = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
diamond = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
diamond[0, 0] = 0
diamond[0, 1] = 0
diamond[1, 0] = 0
diamond[4, 4] = 0
diamond[4, 3] = 0
diamond[3, 4] = 0
diamond[4, 0] = 0
diamond[4, 1] = 0
diamond[3, 0] = 0
diamond[0, 3] = 0
diamond[0, 4] = 0
diamond[1, 4] = 0
square = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
x = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
result1 = cv2.dilate(image, cross)
result1 = cv2.erode(result1, diamond)
result2 = cv2.dilate(image, x)
result2 = cv2.erode(result2, square)
result = cv2.absdiff(result2, result1)
retval, result = cv2.threshold(result, 40, 255, cv2.THRESH_BINARY)
for j in range(result.size):
	y = int(j / result.shape[0])
	x = int(j % result.shape[0])
	if result[x, y] == 255:
		cv2.circle(image, (y, x), 5, (255, 0, 0))
cv2.imshow("Result", image)
cv2.waitKey(0)
cv2.destroyAllWindows()


六、图像边缘检测

1、Sobel边缘检测算子

import cv2

img = cv2.imread("tupian\\mao1.jpg", 0)
x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
y = cv2.Sobel(img, cv2.CV_16S, 0, 1)
# cv2.convertScaleAbs(src[,dst[,alpan[,bata]]])
Scale_absX = cv2.convertScaleAbs(x)
Scale_absY = cv2.convertScaleAbs(y)
result = cv2.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)
# result=cv2.addWeighted(src1,alpha,src2,beta,gamma[,dst[,dtype]])
cv2.imshow('img', img)
cv2.imshow('Scale_absX', Scale_absX)
cv2.imshow('Scale_absY', Scale_absY)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()


2、Scharr算子

import cv2

img = cv2.imread("tupian\\mao1.jpg", 0)
x = cv2.Sobel(img, cv2.CV_16S, 1, 0, ksize=-1)
y = cv2.Sobel(img, cv2.CV_16S, 0, 1, ksize=-1)
# ksize=-1 Scharr算子
# cv2.convertScaleAbs(src[,dst[,alpan[,bata]]])
Scale_absX = cv2.convertScaleAbs(x)
Scale_absY = cv2.convertScaleAbs(y)
result = cv2.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)
# result=cv2.addWeighted(src1,alpha,src2,beta,gamma[,dst[,dtype]])
cv2.imshow('img', img)
cv2.imshow('Scale_absX', Scale_absX)
cv2.imshow('Scale_absY', Scale_absY)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()


3、拉普拉斯(Laplacian)算子

import cv2

img = cv2.imread("tupian\\mao1.jpg", 0)
laplacian = cv2.Laplacian(img, cv2.CV_16S, ksize=3)
dst = cv2.convertScaleAbs(laplacian)
cv2.imshow('laplacian', dst)
cv2.waitKey(0)
cv2.destroyALLWindows()

当ksize=1

当ksize=5

当ksize=7


4、Canny算子

import cv2
import numpy as np

def CannyThreshold(lowThreshold):
	detected_edges = cv2.GaussianBlur(gray, (3, 3), 0)
	detected_edges = cv2.Canny(detected_edges, lowThreshold, lowThreshold * ratio, apertureSize=kernel_size)
	dst = cv2.bitwise_and(img, img, mask=detected_edges)
	cv2.imshow('canny demo', dst)

lowThreshold = 0
max_lowThreshold = 100
ratio = 3
kernel_size = 3
img = cv2.imread("tupian\\mao1.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.namedWindow('canny demo')
cv2.createTrackbar('Min threshold', 'canny demo', lowThreshold, max_lowThreshold,
	CannyThreshold)
CannyThreshold(0)
if cv2.waitKey(0) == 27:
	cv2.destroyAllWindows()


七、图像的压缩编码

import os
import cv2
from queue import PriorityQueue
import numpy as np
import math
import struct
import matplotlib.pyplot as plt

class HuffmanNode(object):
	def __init__(self, value, key=None, symbol='', left_child=None, right_child=None):
		self.left_child = left_child
		self.right_child = right_child
		self.value = value
		self.key = key
		assert symbol == ''
		self.symbol = symbol

	def __eq__(self, other):
		return self.value == other.value

	def __gt__(self, other):
		return self.value > other.value

	def __lt__(self, other):
		return self.value < other.value

def createTree(hist_dict: dict) -> HuffmanNode:
	# 借助优先级队列实现直方图频率的排序,取出和插入元素很方便
	q = PriorityQueue()
	# 根据传入的像素值和频率字典构造哈夫曼节点并放入队列中
	for k, v in hist_dict.items():
		# 这里放入的都是之后哈夫曼树的叶子节点,key都是各自的元素
		q.put(HuffmanNode(value=v, key=k))
	# 判断条件,直到队列中只剩下一个根节点
	while q.qsize() > 1:
		# 取出两个最小的哈夫曼节点,队列中这两个节点就不在了
		l_freq, r_freq = q.get(), q.get()
		# 增加他们的父节点,父节点值为这两个哈夫曼节点的和,但是没有key值;左子节点是较小的,右子节点是较大的
		node = HuffmanNode(value=l_freq.value + r_freq.value, left_child=l_freq, right_child=r_freq)
		# 把构造的父节点放在队列中,继续排序和取放、构造其他的节点
		q.put(node)
	# 队列中只剩下根节点了,返回根节点
	return q.get()

def walkTree_VLR(root_node: HuffmanNode, symbol=''):
	# 为了不增加变量复制的成本,直接使用一个dict类型的全局变量保存每个元素对应的哈夫曼编码
	global Huffman_encode_dict
	# 判断节点是不是HuffmanNode,因为叶子节点的子节点是None
	if isinstance(root_node, HuffmanNode):
		# 编码操作,改变每个子树的根节点的哈夫曼编码,根据遍历过程是逐渐增加编码长度到完整的
		root_node.symbol += symbol
		# 判断是否走到了叶子节点,叶子节点的key!=None
		if root_node.key != None:
			# 记录叶子节点的编码到全局的dict中
			Huffman_encode_dict[root_node.key] = root_node.symbol
		# 访问左子树,左子树在此根节点基础上赋值'0'
		walkTree_VLR(root_node.left_child, symbol=root_node.symbol + '0')
		# 访问右子树,右子树在此根节点基础上赋值'1'
		walkTree_VLR(root_node.right_child, symbol=root_node.symbol + '1')
	return

def encodeImage(src_img: np.ndarray, encode_dict: dict):
	img_encode = ""
	assert len(src_img.shape) == 1, '`src_img` must be a vector'
	for pixel in src_img:
		img_encode += encode_dict[pixel]
	return img_encode

def writeBinImage(img_encode: str, huffman_file: str):
	# 文件要以二进制打开
	with open(huffman_file, 'wb') as f:
		# 每8个bit组成一个byte
		for i in range(0, len(img_encode), 8):
			# 把这一个字节的数据根据二进制翻译为十进制的数字
			img_encode_dec = int(img_encode[i:i + 8], 2)
			# 把这一个字节的十进制数据打包为一个unsigned char,大端(可省略)
			img_encode_bin = struct.pack('>B', img_encode_dec)
			# 写入这一个字节数据
			f.write(img_encode_bin)

def readBinImage(huffman_file: str, img_encode_len: int):
	code_bin_str = ""
	with open(huffman_file, 'rb') as f:
		# 从文件读取二进制数据
		content = f.read()
		# 从二进制数据解包到十进制数据,所有数据组成的是tuple
		code_dec_tuple = struct.unpack('>' + 'B' * len(content), content)
		for code_dec in code_dec_tuple:
			# 通过bin把解压的十进制数据翻译为二进制的字符串,并填充为8位,否则会丢失高位的0
			# 0 -> bin() -> '0b0' -> [2:] -> '0' -> zfill(8) -> '00000000'
			code_bin_str += bin(code_dec)[2:].zfill(8)
		# 由于原始的编码最后可能不足8位,保存到一个字节的时候会在高位自动填充0,读取的时候需要去掉填充的0,否则读取出的编码会比原来的编码长
		# 计算读取的编码字符串与原始编码字符串长度的差,差出现在读取的编码字符串的最后一个字节,去掉高位的相应数量的0就可以
		len_diff = len(code_bin_str) - img_encode_len
		# 在读取的编码字符串最后8位去掉高位的多余的0
		code_bin_str = code_bin_str[:-8] + code_bin_str[-(8 - len_diff):]
	return code_bin_str

def decodeHuffman(img_encode: str, huffman_tree_root: HuffmanNode):
	img_src_val_list = []
	# 从根节点开始访问
	root_node = huffman_tree_root
	# 每次访问都要使用一位编码
	for code in img_encode:
		# 如果编码是'0',说明应该走到左子树
		if code == '0':
			root_node = root_node.left_child
		# 如果编码是'1',说明应该走到右子树
		elif code == '1':
			root_node = root_node.right_child
		# 只有叶子节点的key才不是None,判断当前走到的节点是不是叶子节点
		if root_node.key != None:
			# 如果是叶子节点,则记录这个节点的key,也就是哪个原始数据的元素
			img_src_val_list.append(root_node.key)
			# 访问到叶子节点之后,下一次应该从整个数的根节点开始访问了
			root_node = huffman_tree_root
	return np.asarray(img_src_val_list)

def decodeHuffmanByDict(img_encode: str, encode_dict: dict):
	img_src_val_list = []
	decode_dict = {}
	# 构造一个key-value互换的字典,i.e. dict={code:element},后边方便使用
	for k, v in encode_dict.items():
		decode_dict[v] = k
	# s用来记录当前字符串的访问位置,相当于一个指针
	s = 0
	# 只要没有访问到最后
	while len(img_encode) > s + 1:
		# 遍历字典中每一个键code
		for k in decode_dict.keys():
			# 如果当前的code字符串与编码字符串前k个字符相同,k表示code字符串的长度,那么就可以确定这k个编码对应的元素是什么
			if k == img_encode[s:s + len(k)]:
				img_src_val_list.append(decode_dict[k])
				# 指针移动k个单位
				s += len(k)
				# 如果已经找到了相应的编码了,就可以找下一个了
				break
	return np.asarray(img_src_val_list)

def put(path):
	# 即使原图像是灰度图,也需要加入GRAYSCALE标志
	src_img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
	# 记录原始图像的尺寸,后续还原图像要用到
	src_img_w, src_img_h = src_img.shape[:2]
	# 把图像展开成一个行向量
	src_img_ravel = src_img.ravel()
	# {pixel_value:count},保存原始图像每个像素对应出现的次数,也就是直方图
	hist_dict = {}
	# 得到原始图像的直方图,出现次数为0的元素(像素值)没有加入
	for p in src_img_ravel:
		if p not in hist_dict:
			hist_dict[p] = 1
		else:
			hist_dict[p] += 1
	# 构造哈夫曼树
	huffman_root_node = createTree(hist_dict)
	# 遍历哈夫曼树,并得到每个元素的编码,保存到Huffman_encode_dict,这是全局变量
	walkTree_VLR(huffman_root_node)
	global Huffman_encode_dict
	print('哈夫曼编码字典:', Huffman_encode_dict)
	# 根据编码字典编码原始图像得到二进制编码数据字符串
	img_encode = encodeImage(src_img_ravel, Huffman_encode_dict)
	# 把二进制编码数据字符串写入到文件中,后缀为bin
	writeBinImage(img_encode, 'huffman_bin_img_file.bin')
	# 读取编码的文件,得到二进制编码数据字符串
	img_read_code = readBinImage('huffman_bin_img_file.bin', len(img_encode))
	# 解码二进制编码数据字符串,得到原始图像展开的向量
	# 这是根据哈夫曼树进行解码的方式
	img_src_val_array = decodeHuffman(img_read_code, huffman_root_node)
	# 这是根据编码字典进行解码的方式,更慢一些
	# img_src_val_array = decodeHuffmanByDict(img_read_code, Huffman_encode_dict)
	# 确保解码的数据与原始数据大小一致
	assert len(img_src_val_array) == src_img_w * src_img_h
	# 恢复原始二维图像
	img_decode = np.reshape(img_src_val_array, [src_img_w, src_img_h])
	# 计算平均编码长度和编码效率
	total_code_len = 0
	total_code_num = sum(hist_dict.values())
	avg_code_len = 0
	I_entropy = 0
	for key in hist_dict.keys():
		count = hist_dict[key]
		code_len = len(Huffman_encode_dict[key])
		prob = count / total_code_num
		avg_code_len += prob * code_len
		I_entropy += -(prob * math.log2(prob))
	S_eff = I_entropy / avg_code_len
	print("平均编码长度为:{:.3f}".format(avg_code_len))
	print("编码效率为:{:.6f}".format(S_eff))
	# 压缩率
	ori_size = src_img_w * src_img_h * 8 / (1024 * 8)
	comp_size = len(img_encode) / (1024 * 8)
	comp_rate = 1 - comp_size / ori_size
	print('原图灰度图大小', ori_size, 'KB  压缩后大小', comp_size, 'KB  压缩率', comp_rate, '%')
	plt.rcParams['font.sans-serif'] = ['SimHei']
	plt.subplot(121), plt.imshow(src_img, plt.cm.gray), plt.title('原图灰度图像'), plt.axis('off')
	plt.subplot(122), plt.imshow(img_decode, plt.cm.gray), plt.title('解压后'), plt.axis('off')
	# plt.savefig('1.1new.jpg')
	plt.show()

if __name__ == '__main__':
	# 哈夫曼编码字典{pixel_value:code},在函数中作为全局变量用到了
	Huffman_encode_dict = {}
	# 图像处理函数,要传入路径
	put(r'tupian\\mao1.jpg')
哈夫曼编码字典: {192: '0000000', 181: '0000001', 211: '00000100', 65: '00000101', 59: '00000110', 38: '00000111', 110: '0000100', 180: '0000101', 63: '00001100', 70: '00001101', 60: '00001110', 64: '00001111', 111: '0001000', 108: '0001001', 66: '00010100', 30: '00010101000', 29: '00010101001', 233: '00010101010000', 234: '00010101010001', 235: '00010101010010', 241: '000101010100110', 242: '00010101010011100', 6: '000101010100111010', 253: '000101010100111011', 14: '000101010100111100', 248: '000101010100111101', 247: '00010101010011111', 27: '000101010101', 220: '00010101011', 36: '000101011', 67: '00010110', 58: '00010111', 72: '00011000', 69: '00011001', 112: '0001101', 61: '00011100', 206: '00011101', 68: '00011110', 57: '00011111', 174: '0010000', 62: '00100010', 56: '00100011', 114: '0010010', 73: '00100110', 40: '00100111', 161: '0010100', 113: '0010101', 173: '0010110', 74: '00101110', 71: '00101111', 115: '0011000', 172: '0011001', 179: '0011010', 203: '00110110', 44: '00110111', 176: '0011100', 177: '0011101', 204: '00111100', 205: '00111101', 178: '0011111', 163: '0100000', 171: '0100001', 75: '01000100', 210: '01000101', 175: '0100011', 55: '01001000', 41: '01001001', 160: '0100101', 156: '0100110', 157: '0100111', 39: '01010000', 214: '01010001', 159: '0101001', 31: '01010100000', 228: '0101010000100', 238: '0101010000101000', 15: '01010100001010010', 3: '010101000010100110', 13: '010101000010100111', 244: '0101010000101010', 250: '01010100001010110', 9: '010101000010101110', 11: '010101000010101111', 239: '0101010000101100', 10: '010101000010110100', 8: '010101000010110101', 245: '01010100001011011', 0: '010101000010111000', 251: '010101000010111001', 246: '01010100001011101', 16: '01010100001011110', 17: '01010100001011111', 28: '010101000011', 34: '0101010001', 215: '010101001', 209: '01010101', 151: '0101011', 162: '0101100', 53: '01011010', 208: '01011011', 164: '0101110', 42: '01011110', 202: '01011111', 45: '01100000', 207: '01100001', 43: '01100010', 79: '01100011', 170: '0110010', 153: '0110011', 149: '0110100', 77: '01101010', 54: '01101011', 158: '0110110', 169: '0110111', 116: '0111000', 117: '0111001', 200: '01110100', 51: '01110101', 155: '0111011', 154: '0111100', 152: '0111101', 150: '0111110', 76: '01111110', 46: '01111111', 148: '1000000', 165: '1000001', 47: '10000100', 78: '10000101', 118: '1000011', 168: '1000100', 201: '10001010', 50: '10001011', 37: '1000110', 120: '1000111', 119: '1001000', 48: '10010010', 52: '10010011', 167: '1001010', 147: '1001011', 219: '10011000000', 32: '10011000001', 217: '1001100001', 216: '100110001', 198: '10011001', 199: '10011010', 49: '10011011', 122: '1001110', 166: '1001111', 142: '1010000', 80: '10100010', 82: '10100011', 145: '1010010', 121: '1010011', 143: '1010100', 146: '1010101', 124: '1010110', 140: '1010111', 123: '1011000', 141: '1011001', 81: '10110100', 222: '101101010000', 25: '1011010100010', 227: '1011010100011', 221: '101101010010', 223: '101101010011', 35: '1011010101', 21: '1011010110000000', 18: '1011010110000001', 12: '1011010110000010', 20: '1011010110000011', 231: '10110101100001', 26: '1011010110001', 237: '101101011001000', 22: '101101011001001', 230: '10110101100101', 225: '1011010110011', 218: '10110101101', 33: '10110101110', 229: '10110101111000', 19: '1011010111100100', 255: '101101011110010100', 243: '101101011110010101', 240: '10110101111001011', 236: '101101011110011', 224: '1011010111101', 226: '1011010111110', 232: '101101011111100', 23: '101101011111101', 24: '10110101111111', 125: '1011011', 144: '1011100', 126: '1011101', 127: '1011110', 84: '10111110', 197: '10111111', 196: '11000000', 90: '11000001', 83: '11000010', 96: '11000011', 139: '1100010', 87: '11000110', 86: '11000111', 137: '1100100', 138: '1100101', 93: '11001100', 98: '11001101', 135: '1100111', 85: '11010000', 89: '11010001', 92: '11010010', 94: '11010011', 136: '1101010', 95: '11010110', 88: '11010111', 134: '1101100', 102: '11011010', 97: '11011011', 99: '11011100', 91: '11011101', 187: '11011110', 189: '11011111', 128: '1110000', 193: '11100010', 100: '11100011', 101: '11100100', 194: '11100101', 132: '1110011', 195: '11101000', 186: '11101001', 191: '11101010', 213: '111010110', 212: '111010111', 133: '1110110', 103: '11101110', 104: '11101111', 188: '11110000', 183: '11110001', 185: '11110010', 184: '11110011', 105: '11110100', 190: '11110101', 129: '1111011', 106: '11111000', 107: '11111001', 131: '1111101', 182: '11111100', 109: '11111101', 130: '1111111'}
平均编码长度为:7.468
编码效率为:0.996944
原图灰度图大小 280.56640625 KB  压缩后大小 261.891845703125 KB  压缩率 0.0665602158022972 %


八、基于神经网络模型的手写数字识别

import numpy
import matplotlib.pyplot
import scipy.special


class neuralNetwork:
	def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
		self.inodes = inputnodes
		self.hnodes = hiddennodes
		self.onddes = outputnodes
		self.wih = numpy.random.normal(0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))
		self.who = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.onddes, self.hnodes))
		self.lr = learningrate
		self.activation_function = lambda x: scipy.special.expit(x)
		pass

	def train(self, inputs_list, targets_list):
		inputs = numpy.array(inputs_list, ndmin=2).T
		targets = numpy.array(targets_list, ndmin=2).T
		hidden_inputs = numpy.dot(self.wih, inputs)
		hidden_outputs = self.activation_function(hidden_inputs)
		final_intputs = numpy.dot(self.who, hidden_outputs)
		final_outputs = self.activation_function(final_intputs)
		output_errors = targets - final_outputs
		hidden_errors = numpy.dot(self.who.T, output_errors)
		self.who += self.lr * numpy.dot((
					output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))
		self.wih += self.lr * numpy.dot((
					hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))
		pass

	def query(self, inputs_list):
		inputs = numpy.array(inputs_list, ndmin=2).T
		hidden_inputs = numpy.dot(self.wih, inputs)
		hidden_outputs = self.activation_function(hidden_inputs)
		final_inputs = numpy.dot(self.who, hidden_outputs)
		final_outputs = self.activation_function(final_inputs)
		return final_outputs


input_nodes = 784
hidden_nodes = 200
output_nodes = 10
learning_rate = 0.1
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
training_data_file = open("mnist_train_100.csv", 'r')
training_data_list = training_data_file.readlines()
training_data_file.close()
epochs = 50
for e in range(epochs):
	for record in training_data_list:
		all_values = record.split(',')
		inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
		targets = numpy.zeros(output_nodes) + 0.01
		targets[int(all_values[0])] = 0.99
		n.train(inputs, targets)
		pass
	pass
test_data_file = open("mnist_train_100.csv", 'r')
test_data_list = test_data_file.readlines()
test_data_file.close()
scorecard = []
for record in test_data_list:
	all_values = record.split(',')
	correct_label = int(all_values[0])
	inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
	outputs = n.query(inputs)
	label = numpy.argmax(outputs)
	if (label == correct_label):
		scorecard.append(1)
	else:
		scorecard.append(0)
		pass
	pass
scorecard_array = numpy.asarray(scorecard)
print("performance=", scorecard_array.sum() / scorecard_array.size)
all_values = test_data_list[9].split(',')
print(all_values[0])
n.query((numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01)
D:\Anacondan\environment\environment1\python.exe "E:/文档/2022数字图像处理与机器视觉/3202052051184 庞炅骏/实验项目/实验8.1基于神经网络模型的手写数字识别.py"
performance= 1.0
4

进程已结束,退出代码0

备注

python=3.8

opencv-python=4.8.0.76

numpy=1.20.3

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值