霍夫曼编码(Huffman Coding)是一种广泛使用的无损数据压缩算法。它通过为数据中的每个符号分配一个变长的编码,使得频率高的符号使用较短的编码,而频率低的符号使用较长的编码,从而达到压缩数据的目的。霍夫曼编码的一般要求包括:
- 符号集合:首先需要确定数据流中的所有不同符号(例如,对于文本数据,符号可以是字符集)。
- 符号频率:计算每个符号在数据流中出现的次数,这些频率将决定霍夫曼编码树的构建。
- 优先队列:构建一个优先队列(通常是最小堆),以存储符号及其频率。
- 构建霍夫曼树:
- 从优先队列中取出两个最小频率的节点。
- 创建一个新的内部节点,其频率是两个取出节点频率的和。
- 将这两个节点作为新内部节点的子节点,并将其重新加入优先队列。
- 生成编码:从根节点开始,向左子节点走分配“0”,向右子节点走分配“1”,直到达到叶节点(即符号)。此时,路径上的“0”和“1”序列构成了该符号的霍夫曼编码。
- 唯一性:确保所有符号的编码都是唯一的,以避免解码时的歧义。
- 前缀码:霍夫曼编码要求任何符号的编码都不是其他符号编码的前缀,这也称为前缀码(prefix code)性质。
- 编码数据:使用生成的霍夫曼编码替换原始数据中的每个符号。
- 存储编码表:为了能够解码,需要将编码表(即符号和其对应的霍夫曼编码)存储在压缩数据的前面或通过其他方式传达给解码器。
- 解码:解码过程与编码过程相反,它根据霍夫曼树或编码表将变长的编码转换回原始符号。
- 优化:在实际应用中,可能需要对霍夫曼树进行优化,以减少编码和解码的时间复杂度或压缩数据的大小。
- 自适应霍夫曼编码:在某些应用中,数据的统计特性可能随时间变化,因此会使用自适应霍夫曼编码,它在编码过程中动态更新霍夫曼树。
#初始化哈夫曼结点 def main(): |
算术编码是一种无损数据压缩技术,它通过将消息映射到一个0和1之间的分数区间来实现压缩。与霍夫曼编码等其他编码方法相比,算术编码通常能够提供更好的压缩比。以下是实现算术编码和解码的一般要求:
概率模型:需要为数据流中的每个符号建立一个概率模型。这些概率用于确定符号的编码区间。
初始区间:编码过程从0到1的区间开始,这个区间将根据符号的概率被分割成子区间。
区间分割:对于每个符号,根据其概率将当前区间分割成若干个子区间,每个子区间的长度与符号的概率成比例。
累积概率:对于每个符号,计算其累积概率,即该符号之前所有符号概率的和。
更新区间:当一个符号被编码时,当前区间将根据该符号的累积概率更新为对应的子区间。
编码结束:当所有符号都被编码后,将当前区间表示为一个二进制小数。
解码过程:解码过程与编码过程相反,它根据累积概率和当前区间来确定原始符号。
二进制表示:为了便于存储和传输,通常需要将算术编码的输出转换为二进制形式。
同步:在编码和解码过程中,需要确保发送方和接收方同步,以便正确地重建原始数据。
自适应算术编码:在一些应用中,数据的概率分布可能会随时间变化,因此需要使用自适应算术编码,它可以根据数据的实际分布动态调整概率模型。
防止下溢:由于算术编码涉及非常小的数,需要采取措施防止在编码和解码过程中发生下溢。
效率和精度:需要考虑编码和解码算法的效率和精度,以确保压缩和解压缩过程既快速又准确。
实现细节:算术编码的实现可能涉及一些技术细节,如使用特定的数据结构来表示区间,以及优化算法以减少计算量。
错误处理:需要考虑错误处理机制,以应对传输错误或数据损坏的情况。
3、实验结果分析: def get_symbol_probabilities(text): def main(): # 创建按钮,用于触发算数编码和解码操作 |
LZW(Lempel-Ziv-Welch)编码是一种无损数据压缩算法,它通过构建一个可变长度的字典来逐步压缩数据。以下是实现LZW编码和解码的一般要求:
初始化字典:开始编码时,需要一个初始字典,其中包含输入数据集中所有可能的字符作为字典的初始条目。
字符编码:每个字符最初被单独编码,并逐步添加到输出中。
查找匹配串:算法尝试在输入数据中查找当前字符之后更长的匹配串,并检查该串是否已存在于字典中。
字典更新:如果找到匹配串,则将其编码添加到输出中,并从当前位置开始继续查找;如果没有找到,则将当前字符作为一个新条目添加到字典中。
编码输出:编码输出包括字典中条目的索引,这些索引对应于输入数据中的字符或字符串。
处理新词:当输入数据中出现一个新的字符或字符串(不在字典中),该串被分解为单个字符,并逐步添加到字典中。
结束条件:当输入数据完全被读取,编码过程结束。
解码过程:解码过程需要与编码过程相反,它使用相同的字典来将编码索引转换回原始字符或字符串。
字典共享:编码器和解码器必须使用相同的初始字典,并且在编码过程中以相同的方式更新字典。
数据结构:需要有效的数据结构来存储字典条目,以及快速查找和添加新条目。
压缩比:LZW算法的压缩比依赖于输入数据的重复模式。数据中重复模式越多,压缩比越高。
编码效率:LZW算法的效率取决于查找和插入字典条目的速度。
自适应性:LZW算法是自适应的,它可以根据输入数据的统计特性动态调整字典。
最大字典大小:在某些实现中,可能需要设置字典的最大大小,以防止内存使用过多。
清空字典:在一些特定情况下,如压缩非常大的文件时,可能需要清空字典并重新开始以避免性能问题。
3、实验结果分析: # LZW编码实现 def main(): # 创建按钮,用于触发LZW编码和解码操作 |
WAV(Waveform Audio File Format)是一种无损音频文件格式,通常用于保存未压缩的音频数据。WAV文件由两部分组成:一个包含音频流的属性(如采样率、位深、声道数等)的头部信息,以及随后的实际音频数据。读取和显示WAV数据通常需要满足以下要求: 解析头部信息:读取WAV文件的头部信息,这通常包括以下几个关键字段: 音频格式(如PCM、IEEE float等) 采样率(每秒钟的样本数) 声道数(如单声道或立体声) 位深(每个样本的位数,常见的有8位、16位、24位或32位) 数据速率(每秒位数) 数据长度(音频数据的总字节数) 读取音频数据:根据头部信息中提供的参数,读取紧跟在头部之后的音频数据块。 数据格式转换:WAV文件的音频数据通常是以二进制形式存储的,需要根据位深和音频格式转换为适合处理的格式(如整数或浮点数)。 音频解码:对于未压缩的WAV文件,音频数据通常是原始样本值,可以直接用于播放或进一步处理。 音频播放:如果需要播放音频,可以使用音频播放库或API来播放解码后的音频数据。 显示波形:为了在界面上显示音频波形,需要将音频样本值映射到图形界面的坐标系中。通常,这涉及到绘制音频信号的波形图或频谱图。 同步播放与显示:如果同时进行播放和显示,需要确保播放进度和显示的波形同步。 错误处理:在读取和处理WAV文件时,应考虑错误处理机制,以应对文件损坏、格式不支持或读取权限等问题。 用户界面:如果需要用户交互,应设计直观的用户界面,提供播放控制(如播放、暂停、停止)和波形查看功能。 性能考虑:对于大型WAV文件或实时应用,需要考虑读取和处理数据的性能,避免延迟和卡顿。 内存管理:音频数据可能会占用大量内存,特别是在高采样率和多位深的情况下,需要合理管理内存使用。 跨平台兼容性:确保读取和显示WAV数据的程序或脚本在不同操作系统和平台上都能正常工作。 文件格式验证:在读取之前验证文件是否为有效的WAV格式,通常WAV文件以RIFF和WAVE作为文件头标识。 版权和许可:在使用WAV文件时,应确保遵守相关的版权和使用许可。 wav是一种标准数字音频文件。作为最常见的音频文件之一的wav格式,是由微软公司和IBM联合设计。 Python中主流的读取波形音频(.wav)的方法有四种,使用scipy库、soundfile库、ewave库、torchaudio库。 |
def open_wav_file(file_path):
with wave.open(file_path, 'rb') as wav_file:
# 获取音频文件的参数
num_channels = wav_file.getnchannels()
sample_width = wav_file.getsampwidth()
sample_rate = wav_file.getframerate()
num_frames = wav_file.getnframes()
# 读取音频数据
audio_data = wav_file.readframes(num_frames)
return audio_data, num_channels, sample_width, sample_rate
def read_wav_file():
# 读取WAV文件的逻辑
try:
filename = "audio.wav" # WAV文件名
wav = wave.open(filename, 'r')
frames = wav.readframes(-1)
signal = np.frombuffer(frames, dtype='int16')
sample_rate = wav.getframerate()
duration = len(signal) / sample_rate
return signal, sample_rate, duration
except Exception as e:
show_error_message(str(e))
def display_wav_data():
# 显示WAV数据的逻辑
try:
signal, sample_rate, duration = read_wav_file()
time = np.linspace(0, duration, len(signal))
plt.figure(figsize=(200, 54))
plt.plot(time, signal)
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.title('WAV Data')
plt.show()
except Exception as e:
show_error_message(str(e))
def main():
# 创建主窗口
window = tk.Tk()
window.title("Encoding and Decoding Tool")
# 创建标签和输入框,用于输入字符串
input_label = tk.Label(window, text="Input String:")
input_label.pack()
input_entry = tk.Entry(window)
input_entry.pack()
# 创建一个Frame容器,用于放置所有按钮
button_frame = tk.Frame(window)
button_frame.pack(pady=10)
def read_bmp_data():
try:
bmp_file_path = filedialog.askopenfilename()
bf_type, bf_size, bf_offbits, bi_width, bi_height, bi_bitcount, img_data = read_bmp(bmp_file_path)
grayscale_data = convert_to_grayscale(img_data)
show_success_message(
f'bf_type = {bf_type},bf_size = {bf_size},bf_offbits = {bf_offbits},bi_width = {bi_width},bi_height = {bi_height},bi_bitcount = {bi_bitcount}')
# 写入灰度图像到BMP文件
output_filepath = r"C:\Users\sunao\Desktop\outbmp.bmp"
write_bmp(output_filepath, bf_type, bf_size, bf_offbits, bi_width, bi_height, bi_bitcount, grayscale_data)
except Exception as e:
show_error_message(str(e))
read_bmp_button = tk.Button(button_frame, text="Read BMP File", command=read_bmp_data)
read_bmp_button.pack(side=tk.LEFT, padx=5)
BMP(Bitmap Image File Format)文件是一种位图图像文件格式,用于存储数字图像数据。BMP文件可以是压缩的,也可以是未压缩的,并且可以包含彩色图像或单色位图。进行BMP文件读写时,通常需要满足以下要求:
文件格式理解:理解BMP文件格式的组成,包括文件头、位图信息头、颜色数据和像素数据。
文件头解析:读取并解析BMP文件的文件头(BITMAPFILEHEADER),这通常包括文件类型、文件大小、位图数据的偏移量等信息。
位图信息头:读取位图信息头(BITMAPINFOHEADER),它包含图像的宽度、高度、位深(颜色位数)、压缩类型和图像大小等信息。
颜色数据:对于某些BMP文件,可能需要读取颜色数据(如调色板),特别是当位图使用索引颜色时。
像素数据读取:根据位图信息头中的信息,读取并解析像素数据。像素数据通常按行存储,每行可能需要字节对齐。
数据解析:根据位深解析像素数据,位深可以是1、4、8、16、24或32位。不同的位深意味着不同的颜色信息存储方式。
图像渲染:将解析后的像素数据渲染成图像,这可能涉及到颜色转换、位翻转等操作。
写入文件:在创建BMP文件时,需要构建正确的文件头、位图信息头和颜色数据,然后写入像素数据。
数据对齐:BMP文件要求每行像素数据的字节数必须是4的倍数,因此可能需要对数据进行填充。
压缩和解压:对于压缩的BMP文件,需要实现相应的压缩和解压算法。
错误处理:在读写过程中,需要考虑错误处理机制,以应对文件损坏、格式不正确或读写错误等问题。
性能考虑:对于大型图像文件,读写操作可能会消耗较多时间和资源,需要考虑性能优化。
用户界面:如果需要用户交互,设计直观的用户界面,允许用户选择文件、查看图像和保存结果。
跨平台兼容性:确保程序在不同的操作系统和平台上都能正确读写BMP文件。
版权和许可:在使用BMP文件时,需要确保遵守相关的版权和使用许可。
第三方库的使用:可以使用第三方图像处理库(如Python的Pillow库)来简化BMP文件的读写操作。
3、实验结果分析: def read_bmp(filename): def main(): def read_bmp_data(): |
安装OpenCV库:确保你的开发环境中安装了OpenCV库,它是进行视频读取和处理的基础。
创建视频捕获对象:使用cv2.VideoCapture()函数创建一个视频捕获对象,该对象可以是视频文件的路径或摄像头的索引号。
检查视频是否成功打开:通过调用捕获对象的isOpened()方法,检查视频是否成功打开。
读取视频帧:在循环中使用read()方法从视频捕获对象中读取每一帧。该方法返回两个值:一个布尔值表示是否成功读取帧,以及读取的帧本身。
处理视频帧:对读取的每一帧进行所需的图像处理操作。
显示视频帧:使用cv2.imshow()函数显示视频帧。可以通过设置窗口名称和帧的标题来显示。
等待用户输入:使用cv2.waitKey()函数等待用户输入,以便在需要时退出视频读取循环。
释放视频捕获对象:完成视频读取后,使用release()方法释放视频捕获对象,释放与之关联的资源。
关闭所有OpenCV窗口:使用cv2.destroyAllWindows()关闭所有由OpenCV创建的窗口。
错误处理:在读取视频时,需要考虑错误处理,例如处理文件路径错误、文件格式不支持或文件损坏等问题。
视频属性获取:如果需要,可以使用get()方法获取视频的其他属性,如帧高度、宽度、帧率等。
支持的文件格式:确保视频文件的格式被OpenCV支持,常见的格式包括MP4、AVI等。
视频编解码器:了解和指定正确的视频编解码器,以确保视频可以被正确读取。
帧率和分辨率:根据需要处理的视频帧率和分辨率,可能需要对视频播放进行适当的调整。
实时视频处理:如果视频读取涉及到实时处理,需要考虑算法的效率和处理时间,以保持视频播放的流畅性。
def read_and_display_video(video_source=0):
"""
读取视频源(视频文件或摄像头)并在窗口中实时显示
:param video_source: 视频源,可以是视频文件路径或者0(表示默认摄像头)
"""
# 打开视频文件或摄像头
cap = cv2.VideoCapture(video_source)
# 检查是否成功打开
if not cap.isOpened():
print("Cannot open video source")
return
while True:
# 读取一帧视频
ret, frame = cap.read()
# 如果没有更多帧,退出循环
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
# 显示帧
cv2.imshow('Video', frame)
# 按下q键退出循环
if cv2.waitKey(1) == ord('q'):
break
# 释放视频捕获对象和关闭窗口
cap.release()
cv2.destroyAllWindows()
def main():
# 创建主窗口
window = tk.Tk()
window.title("Encoding and Decoding Tool")
# 创建标签和输入框,用于输入字符串
input_label = tk.Label(window, text="Input String:")
input_label.pack()
input_entry = tk.Entry(window)
input_entry.pack()
# 创建一个Frame容器,用于放置所有按钮
button_frame = tk.Frame(window)
button_frame.pack(pady=10)
def read_mp4_data():
try:
mp4_file_path = filedialog.askopenfilename() # 打开文件对话框选择 MP4 文件
if mp4_file_path:
read_and_display_video(mp4_file_path)
except Exception as e:
show_error_message(str(e))
read_mp4_button = tk.Button(button_frame, text="Read MP4 File", command=read_mp4_data)
read_mp4_button.pack(side=tk.LEFT, padx=5)
window.mainloop()
推流和拉流之间的主要区别如下: 推流模式(RTSP推流分发): 客户端将视频/音频数据主动推送到服务器。 服务器接收并转发这些数据流。 适用于客户端具有稳定上行带宽的情况。 拉流模式(RTSP拉流分发): 服务器主动向客户端拉取视频/音频数据流。 客户端被动接收服务器发来的数据流。 适用于客户端上行带宽较弱的情况。 直播软件OBS: |
3、实验结果分析: 进入easydarwin页面localhost:10086 此页面可以上传媒体视频,也可以设置点播地址 打开obs直播软件,进行推流设置和音媒体配置设置。上传视频或者录像。 设置服务器地址和推流码 设置音视频码率 Easydarwin打开直播,点击播放 |
附件:
import tkinter as tk from tkinter import messagebox import numpy as np import matplotlib.pyplot as plt import matplotlib matplotlib.use('TkAgg') # 在导入 pyplot 之前指定后端 import wave from math import inf from decimal import Decimal, getcontext from tkinter import filedialog import struct import cv2 #初始化哈夫曼结点 class Huffmannode(object): def __init__(self): self.parent=0 self.left=0 self.right=0 self.weight=0 #选择最小的结点下标 def select_node(huffman): #俩个结点直接返回不需要找最小俩个结点 if len(huffman)==2: return 0,1 min=semin=inf#初始化成无穷大 f=s=-1 for i in range(len(huffman)): if huffman[i].parent==0: if min>huffman[i].weight: semin=min s=f min=huffman[i].weight f=i elif semin>huffman[i].weight: semin=huffman[i].weight s=i return f,s #编码 def Huffman_code(origin_dict): #给结点赋权重 n=len(origin_dict) m=2*n-1 huffman=[] for i in origin_dict: temp_huffmannode=Huffmannode() temp_huffmannode.weight=origin_dict[i] huffman.append(temp_huffmannode) # 构建Huffman树,选择俩个最小的结点合并 for i in range(n,m): f , s=select_node(huffman) temp_huffmannode=Huffmannode() temp_huffmannode.weight = huffman[f].weight+huffman[s].weight temp_huffmannode.right = f #小的放在右边 temp_huffmannode.left = s huffman[f].parent = huffman[s].parent=i huffman.append(temp_huffmannode) #0,1编码,右1,左0 codeing_dict = dict.fromkeys(origin_dict, None) for i in range(0,n): s='' k=i parent=huffman[i].parent while parent!=0: if huffman[parent].left==k: s+='0' k=parent parent=huffman[parent].parent else: s+='1' k=parent parent=huffman[parent].parent codeing_dict[list(origin_dict.keys())[i]]=list(reversed(s)) for k in codeing_dict.items(): codeing_dict[k[0]] = ''.join(k[1]) return codeing_dict def get_symbol_probabilities(text): # 统计输入文本中每个符号的概率分布 symbol_probabilities = {} total_symbols = len(text) for symbol in text: symbol_probabilities[symbol] = symbol_probabilities.get(symbol, 0) + 1 for symbol, count in symbol_probabilities.items(): symbol_probabilities[symbol] = Decimal(count) / Decimal(total_symbols) return symbol_probabilities def build_cumulative_probabilities(symbol_probabilities): # 构建累计概率表 cumulative_probabilities = {} cumulative_prob = Decimal(0) for symbol, probability in symbol_probabilities.items(): cumulative_probabilities[symbol] = (cumulative_prob, cumulative_prob + probability) cumulative_prob += probability return cumulative_probabilities def encode(text, cumulative_probabilities): # 执行算术编码 lower_limit = Decimal(0) upper_limit = Decimal(1) range_size = upper_limit - lower_limit for symbol in text: range_start, range_end = cumulative_probabilities[symbol] range_size *= range_end - range_start lower_limit += range_start * range_size upper_limit = lower_limit + range_size # 返回编码后的小数和编码范围大小 return lower_limit, range_size def decode(encoded_number, cumulative_probabilities, text_length): # 执行算术解码 message = '' getcontext().prec = text_length # 设置小数精度以确保准确解码 while len(message) < text_length: for symbol, (range_start, range_end) in cumulative_probabilities.items(): if range_start <= encoded_number < range_end: message += symbol range_size = range_end - range_start encoded_number = (encoded_number - range_start) / range_size break return message # LZW编码实现 def lzw_encode(text): dictionary = {} next_code = 256 encoded_text = [] prefix = "" for c in text: if prefix + c in dictionary: prefix += c else: encoded_text.append(dictionary.get(prefix, 0)) dictionary[prefix + c] = next_code next_code += 1 prefix = c encoded_text.append(dictionary.get(prefix, 0)) return encoded_text def open_wav_file(file_path): with wave.open(file_path, 'rb') as wav_file: # 获取音频文件的参数 num_channels = wav_file.getnchannels() sample_width = wav_file.getsampwidth() sample_rate = wav_file.getframerate() num_frames = wav_file.getnframes() # 读取音频数据 audio_data = wav_file.readframes(num_frames) return audio_data, num_channels, sample_width, sample_rate def read_wav_file(): # 读取WAV文件的逻辑 try: filename = "audio.wav" # WAV文件名 wav = wave.open(filename, 'r') frames = wav.readframes(-1) signal = np.frombuffer(frames, dtype='int16') sample_rate = wav.getframerate() duration = len(signal) / sample_rate return signal, sample_rate, duration except Exception as e: show_error_message(str(e)) def display_wav_data(): # 显示WAV数据的逻辑 try: signal, sample_rate, duration = read_wav_file() time = np.linspace(0, duration, len(signal)) plt.figure(figsize=(200, 54)) plt.plot(time, signal) plt.xlabel('Time (s)') plt.ylabel('Amplitude') plt.title('WAV Data') plt.show() except Exception as e: show_error_message(str(e)) def show_error_message(message): messagebox.showerror("Error", message) def show_success_message(message): messagebox.showinfo("Success", message) def read_bmp(filename): with open(filename, "rb") as fp: # 读取文件头 file_header = fp.read(14) # 解析文件头数据 bf_type = file_header[:2] bf_size = struct.unpack("<I", file_header[2:6])[0] bf_offbits = struct.unpack("<I", file_header[10:14])[0] # 读取图像信息头 info_header = fp.read(40) # 解析图像信息头数据 bi_width, bi_height = struct.unpack("<ii", info_header[4:12]) bi_bitcount = struct.unpack("<H", info_header[14:16])[0] # 读取图像数据 img_data = fp.read() return bf_type, bf_size, bf_offbits, bi_width, bi_height, bi_bitcount, img_data def write_bmp(filename, bf_type, bf_size, bf_offbits, bi_width, bi_height, bi_bitcount, img_data): with open(filename, "wb") as fp: # 写入文件头 fp.write(bf_type) fp.write(struct.pack("<I", bf_size)) fp.write(struct.pack("<H", 0)) # bfReserved1 fp.write(struct.pack("<H", 0)) # bfReserved2 fp.write(struct.pack("<I", bf_offbits)) # 写入图像信息头 fp.write(struct.pack("<I", 40)) # biSize fp.write(struct.pack("<i", bi_width)) fp.write(struct.pack("<i", bi_height)) fp.write(struct.pack("<H", 1)) # biPlanes fp.write(struct.pack("<H", bi_bitcount)) fp.write(struct.pack("<I", 0)) # biCompression fp.write(struct.pack("<I", 0)) # biSizeImage fp.write(struct.pack("<i", 0)) # biXPelsPerMeter fp.write(struct.pack("<i", 0)) # biYPelsPerMeter fp.write(struct.pack("<I", 0)) # biClrUsed fp.write(struct.pack("<I", 0)) # biClrImportant # 写入图像数据 fp.write(img_data) def convert_to_grayscale(img_data): grayscale_data = bytearray() i = 0 while i < len(img_data): try: b, g, r = img_data[i:i+3] grayscale_value = int(0.299 * r + 0.587 * g + 0.114 * b) grayscale_data.extend([grayscale_value] * 3) i += 3 except ValueError: # 如果当前像素数据不符合RGB格式,跳过该像素 i += 1 return bytes(grayscale_data) def read_and_display_video(video_source=0): """ 读取视频源(视频文件或摄像头)并在窗口中实时显示 :param video_source: 视频源,可以是视频文件路径或者0(表示默认摄像头) """ # 打开视频文件或摄像头 cap = cv2.VideoCapture(video_source) # 检查是否成功打开 if not cap.isOpened(): print("Cannot open video source") return while True: # 读取一帧视频 ret, frame = cap.read() # 如果没有更多帧,退出循环 if not ret: print("Can't receive frame (stream end?). Exiting ...") break # 显示帧 cv2.imshow('Video', frame) # 按下q键退出循环 if cv2.waitKey(1) == ord('q'): break # 释放视频捕获对象和关闭窗口 cap.release() cv2.destroyAllWindows() # 示例用法 # 读取默认摄像头 # read_and_display_video() def main(): # 创建主窗口 window = tk.Tk() window.title("Encoding and Decoding Tool") # 创建标签和输入框,用于输入字符串 input_label = tk.Label(window, text="Input String:") input_label.pack() input_entry = tk.Entry(window) input_entry.pack() # 创建一个Frame容器,用于放置所有按钮 button_frame = tk.Frame(window) button_frame.pack(pady=10) # 创建按钮,用于触发哈夫曼编码和解码操作 def huffman_encode_decode(): s = input_entry.get() if s: try: dic = {} for i in range(len(s)): dic[s[i]] = dic.get(s[i], 0) + 1 code_dict = Huffman_code(dic) show_success_message(f"Huffman Encoding: {code_dict}") except Exception as e: show_error_message(str(e)) else: show_error_message("Please enter a valid input string.") huffman_button = tk.Button(button_frame, text="Huffman Encoding/Decoding", command=huffman_encode_decode) huffman_button.pack(side=tk.LEFT, padx=5) # 创建按钮,用于触发算数编码和解码操作 def arithmetic_encode_decode(): text = input_entry.get() if text: try: symbol_probabilities = get_symbol_probabilities(text) cumulative_probabilities = build_cumulative_probabilities(symbol_probabilities) encoded_number, range_size = encode(text, cumulative_probabilities) decoded_message = decode(encoded_number, cumulative_probabilities, len(text)) show_success_message(f"arithmetic Encoding: {encoded_number}") except Exception as e: show_error_message(str(e)) else: show_error_message("Please enter a valid input string.") arithmetic_button = tk.Button(button_frame, text="Arithmetic Encoding/Decoding", command=arithmetic_encode_decode) arithmetic_button.pack(side=tk.LEFT, padx=5) # 创建按钮,用于触发LZW编码和解码操作 def lzw_encode_decode(): text = input_entry.get() if text: try: code = lzw_encode(text) show_success_message(f"LZW Encoding: {code}") except Exception as e: show_error_message(str(e)) else: show_error_message("Please enter a valid input string.") lzw_button = tk.Button(button_frame, text="LZW Encoding/Decoding", command=lzw_encode_decode) lzw_button.pack(side=tk.LEFT, padx=5) # 创建按钮,用于读取和显示WAV数据 def read_and_display_wav_data(): try: wav_file_path = filedialog.askopenfilename() # 打开文件对话框选择 WAV 文件 audio_data, num_channels, sample_width, sample_rate = open_wav_file(wav_file_path) # 将二进制音频数据转换为 NumPy 数组 audio_array = np.frombuffer(audio_data, dtype=np.uint8) # 如果音频数据是16位采样宽度,将其转换为有符号整数 if sample_width == 2: audio_array = audio_array.astype(np.int16) # 计算音频数据的时间轴 duration = len(audio_array) / sample_rate time = np.linspace(0, duration, len(audio_array)) # 绘制波形图 plt.plot(time, audio_array) plt.xlabel('Time (s)') plt.ylabel('Amplitude') plt.title('Waveform') plt.show() except Exception as e: show_error_message(str(e)) read_wav_button = tk.Button(button_frame, text="Read WAV File", command=read_and_display_wav_data) read_wav_button.pack(side=tk.LEFT, padx=5) def read_bmp_data(): try: bmp_file_path = filedialog.askopenfilename() bf_type, bf_size, bf_offbits, bi_width, bi_height, bi_bitcount, img_data = read_bmp(bmp_file_path) grayscale_data = convert_to_grayscale(img_data) show_success_message( f'bf_type = {bf_type},bf_size = {bf_size},bf_offbits = {bf_offbits},bi_width = {bi_width},bi_height = {bi_height},bi_bitcount = {bi_bitcount}') # 写入灰度图像到BMP文件 output_filepath = r"C:\Users\sunao\Desktop\outbmp.bmp" write_bmp(output_filepath, bf_type, bf_size, bf_offbits, bi_width, bi_height, bi_bitcount, grayscale_data) except Exception as e: show_error_message(str(e)) read_bmp_button = tk.Button(button_frame, text="Read BMP File", command=read_bmp_data) read_bmp_button.pack(side=tk.LEFT, padx=5) def read_mp4_data(): try: mp4_file_path = filedialog.askopenfilename() # 打开文件对话框选择 MP4 文件 if mp4_file_path: read_and_display_video(mp4_file_path) except Exception as e: show_error_message(str(e)) read_mp4_button = tk.Button(button_frame, text="Read MP4 File", command=read_mp4_data) read_mp4_button.pack(side=tk.LEFT, padx=5) window.mainloop() # 调用主函数 main()