【Python-利用动态二维码传输文件(六)】动态二维码文件接收端开发,涉及tkinter进度条Progressbar、Pillow图片对象转换为numpy图片对象、cv2图像灰度化、函数引用传递

        上一篇文章完成了动态二维码文件发送端的开发,本篇文章研究动态二维码文件接收端的开发。

一、程序效果展示

        左边是发送端,右边是接收端。

二、程序设计原理

        之前第四篇文章已验证过可行性,现对原代码进行优化改进,接收端设计思路如下:

        (一)通过pyautogui库对电脑屏幕进行高频截图(移动端摄像头拍摄),使用pyzbar库、OpenCV库、numpy库把截图中单张二维码包含的数据识别出来;

        (二)使用base64库、zlib库、对识别出来的全部数据进行拼接、解码、解压缩、最后还原出源文件;

        (三)使用tkinterProgressbar、Label,显示文件接收进度,最后显示还原文件的绝对路径。

        第四篇文章参考↓↓↓:

【Python-利用二维码传输文件(四)】使用pyautogui录屏(连续截图),并利用OpenCV按帧读取二维码,重组被拆分的文件_清远小阮的博客-CSDN博客上一篇文章实现了使用tkinter显示动态二维码。本篇为了模拟摄像头读取动态二维码信息,使用pyautogui库,对电脑屏幕进行录屏(连续截图),最后利用OpenCV按帧读取二维码,重组被拆分的文件。https://blog.csdn.net/qq616491978/article/details/125744317

三、程序制作过程 

(一)程序界面设计

        tkinter界面包括进度条、状态来、开始录屏按钮和暂停录屏按钮,使用.grid(row=,column=,)网格布局。开始录屏按钮调用save_qrs()函数,暂停录屏按钮调用stop_progress()函数。设计效果如下图:

        程序界面主要代码如下:

def open_window():
    # 创建窗口
    root = Tk()
    # 设置窗口的标题
    root.title("动态二维码文件接收端")
    # 设置进度条
    _progressbar = Progressbar(root, orient='horizontal', length=400, mode='determinate')
    _progressbar.grid(row=0, column=0, columnspan=3)
    _label_progress_text = StringVar()
    _label_progress_text.set("[0/0]")
    _label_progress = Label(root, textvariable=_label_progress_text)
    _label_progress.grid(row=2, column=2)
    # 设置接收文件地址文本框
    _label_savepath = Label(root, text='文件存放地址')
    _label_savepath.grid(row=1, column=0)
    _label_filepath_text = StringVar()
    _label_filepath = Label(root, textvariable=_label_filepath_text)
    _label_filepath.grid(row=1, column=1, columnspan=2)
    # 暂停标志,用于停止录制,使用传递引用
    _stop_flag = [False]
    # 设置开始、停止按钮
    _button_start = Button(root, text="开始录屏",
                           command=lambda: save_qrs(root, _progressbar, _label_progress_text, _stop_flag,
                                                    _label_filepath_text))
    _button_start.grid(row=2, column=0)
    _button_stop = Button(root, text="停止录屏", command=lambda: stop_progress(_stop_flag))
    _button_stop.grid(row=2, column=1)

    # 显示窗口
    root.mainloop()

(二)循环截屏(录屏)和逐张识别二维码

        录屏和二维码识别全部在save_qrs()函数实现,这有几个需要注意的点:

        1)pyautogui.screenshot()截图返回的是一个pillow图片对象,为提高识别效率,这里先用_numpy_img=numpy.array(_screentshot_img)把pillow图片对象转换为numpy图片对象,进行cvtColor()灰度处理,再用pyzbar进行图片识别。

        2)对比第四篇文章,这里使用set()类存放识别出来的二维码信息,进行了优化。_qr_set用于存放每帧识别出来的二维码信息,set数据结构用于存放不重复数据,对存入的数据会自动去重。由于截取可能出现掉帧,掉帧后需要重新开始截图获取丢失的帧,如果用其他结构来存放二维码信息,会导致大量重复帧。

        3)使用列表值_stop_flag[0]进行引用传递改变原参数的值,如果不用列表是改变不了原参的值。这样一来,通过设置_stop_flag[0]TrueFalse,便可在while _stop_flag[0] is False循环语句控制接收的启动和暂停,并且无需使用到全局变量。

        4)最后调用regroup()函数完成文件重组

# 使用OpenCV库连续截图,并逐张识别出二维码信息
def save_qrs(_tk, _progressbar, _label_progress_text, _stop_flag,_label_filepath_text):
    # _qr_set用于存放每帧识别出来的二维码信息,set数据结构用于存放不重复数据,对存入的数据会自动去重
    _qr_set = set()
    # 设置进度条默认长度为100
    _pb_len = 100
    # 当_stop_flag为False,一直循环截图
    i = 0
    _stop_flag[0] = False
    while _stop_flag[0] is False:
        # 使用pyautogui.screenshot()对屏幕截图
        _screenshot_img = pyautogui.screenshot()
        # 把Pillow图片对象转换为numpy图片对象
        _numpy_img = numpy.array(_screenshot_img)
        # 将图像灰度化提高识别效率
        _cvt_image = cv2.cvtColor(_numpy_img, cv2.COLOR_BGR2GRAY)
        # 解析二维码中的数据
        _qr_data = pyzbar.decode(_cvt_image)
        # 统计接收进度,_qr_set_len为目前接收的不重复的二维码信息数
        # _data_len为单张二维码图片识别后数据的长度用于判断二维码是否识别成功
        _qr_set_len = len(_qr_set)
        _data_len = len(_qr_data)
        # 更新界面状态栏状态,如:正在接收,[11/51]
        _label_progress_text.set("正在接收,[%d/%d]" % (_qr_set_len, _pb_len))
        # 判断二维码是否识别成功,若识别成功,识别数据的长度_data_len应大于0
        if _data_len > 0:
            _str = _qr_data[0].data.decode('utf-8')
            # 把识别出来的单张二维码图片信息存入_qr_set中
            _qr_set.add(_str)
            if _qr_set_len == 0:
                # 用于更新进度条长度_pb_len,只在接收第一次数据时更新长度提高效率
                # 接收数据的格式如:[1/51]xsdgsiakghalshg,获取51存入_pd_len
                _str1 = _str.split(']')
                _str2 = _str1[0].split('/')
                _pb_len = int(_str2[1])
                _progressbar["maximum"] = _pb_len
            # 更新进度条进度
            _progressbar["value"] = _qr_set_len
        if _qr_set_len == _pb_len:
            # 全部数据接收完毕跳出循环
            break
        _tk.update()
    i = i + 1

    if _stop_flag[0] is False:
        # 调用合并函数
        regroup(_qr_set,_label_filepath_text)
        _label_progress_text.set("已完成接收")
    else:
        _label_progress_text.set("已暂停")

(三)重组文件和文件另存至默认路径

        当上述while循环正常结束,证明文件已经全部接收完毕,然后把_qr_set_label_filepath_text传入regroup(_qr_set,_label_filepath_text)函数进行文件重组。这里有几点需要注意的:

        1)对set进行排序。set虽然是不重复的但是乱序的,需要对里面的数据进行重新排序。排序用到了.sort(key=lambda x:comp(x))函数,利用comp(x)的结果进行排序,而comp(x)函数则是提取二维码信息中的序号进行排序,例如[16/51]xxxxx,[5/51]xxxx,提取16和15。

        2)提取文件名及文件后缀。排序后提取第一帧,第一帧存放了待发送文件的文件名和文件后缀,可用于还原文件。如下图:        

        3)解码、解压缩。第二帧开始到结束就是传输的文件数据了,同时由于发送的时候对数据进行了base64编码和zlib压缩,所以还原后需要解码、解压缩才能得到正确的结果,如下图:

         4)保存文件。最后使用open()以二进制形式写入文件,并使用os.path.abspath(_file_path)获取文件存放的绝对路径显示在程序界面上,如下图:

         5)编写暂停函数。编写stop_progress(_stop_flag)函数,使用引用传递改变_stop_flag的值为True,实现暂停录屏。

主要代码如下:

# 暂停录屏
def stop_progress(_stop_flag):
    _stop_flag[0] = True


# 列表排序函数
def comp(_str):
    # 从[1/28]分离出1,用于重组排序
    _str1 = _str.split(']')
    _str2 = _str1[0].split('/')
    _str3 = _str2[0].split('[')
    # 返回整型序号用于list.sort(key=)排序
    return int(_str3[1])


# 还原并另存为对应格式文件
def regroup(_qr_set,_label_filepath_text):
    _list = list(_qr_set)
    # 根据lambda公式对列表进行排序
    _list.sort(key=lambda x: comp(x))
    _regroup_str = ""
    # 提取第一帧,第一帧存放的是发送文件的文件名和文件后缀,如:[1/51]temp.xlsx
    _file_path = _list[0].split(']')[1]
    # 提取从第二帧以后的内容
    for i in range(1, len(_list)):
        _regroup_str = _regroup_str + _list[i].split(']')[1]
        print(_list[i])
    # 使用base64格式对_uini_str进行解码
    print("解码前动态二维码信息 %s" % _regroup_str)
    _regroup_str_b64decode = base64.b64decode(_regroup_str)
    print("解码后动态二维码信息 %s" % _regroup_str_b64decode)
    _regroup_str_b64decode_unzip = zlib.decompress(_regroup_str_b64decode)
    print("解压后动态二维码信息 %s" % _regroup_str_b64decode_unzip)
    # 使用二进制方式把重组的信息写入文件,并另存为_regroup_pic001.png
    with open(_file_path, 'wb') as f:
        f.write(_regroup_str_b64decode_unzip)
        _label_filepath_text.set(os.path.abspath(_file_path))
        f.close()

四、程序源代码

        源代码下载地址↓↓↓:

Python-动态二维码文件接收端开发,涉及tkinter进度条Progressbar、Pillow对象转换为numpy对象等-Python文档类资源-CSDN下载之前第四篇文章已经验证过可行性,现在对之前的代码进行优化改进,接收端的设计原理如下:(一)通过pya更多下载资源、学习资料请访问CSDN下载频道.https://download.csdn.net/download/qq616491978/86339453

猜你喜欢

转载自blog.csdn.net/qq616491978/article/details/126191026