python编程:实现对数据库中图片文件的查看及比对

当谈到图像查看和管理时,我们往往会使用一些工具软件,比如Windows自带的照片查看器或者第三方工具。那如果你想要一个更加强大和定制化的图像查看器呢?这时候就需要自己动手写一个程序了。
C:\pythoncode\new\ShowSqliteImage.py

这里我们将介绍一个使用Python和wxPython编写的图像查看器应用程序。它不仅可以查看图像,还支持缩放、旋转等基本操作,最酷的是它可以连接SQLite数据库,从中读取图像并计算图像的MD5哈希值,用于查找重复图像。

程序的界面非常简洁,顶部有一个文本框用于选择SQLite数据库文件,中间是一个列表框列出数据库中的所有图像名称。选择一个图像名称后,就会在右侧区域显示该图像。下方有几个按钮,可以对图像进行旋转、放大、缩小和重置等操作。还有一个独特的"Compare MD5"按钮,点击它就会计算当前图像的MD5哈希值,并在数据库中搜索是否有重复的图像。

代码的编写利用了wxPython这个跨平台的GUI库,使用Python的PIL库来处理图像。SQLite则用于存储图像数据和元数据。代码结构清晰,功能实现也很巧妙,是一个不错的wxPython编程实例。

完整代码:

import wx
import sqlite3
import os
import hashlib
from datetime import datetime
import io
from PIL import Image, ImageOpsclass ImageViewerApp(wx.Frame):def __init__(self, parent, title):super(ImageViewerApp, self).__init__(parent, title=title, size=(1000, 700))self.panel = wx.Panel(self)self.db_path = ""self.original_image = Noneself.init_ui()self.Centre()self.Show()def init_ui(self):vbox = wx.BoxSizer(wx.VERTICAL)# Database selectionhbox1 = wx.BoxSizer(wx.HORIZONTAL)self.db_path_text = wx.TextCtrl(self.panel)db_path_btn = wx.Button(self.panel, label='Select Database')db_path_btn.Bind(wx.EVT_BUTTON, self.on_select_database)hbox1.Add(self.db_path_text, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)hbox1.Add(db_path_btn, flag=wx.ALL, border=5)vbox.Add(hbox1, flag=wx.EXPAND)hbox2 = wx.BoxSizer(wx.HORIZONTAL)# List of image namesself.image_list = wx.ListBox(self.panel)self.image_list.Bind(wx.EVT_LISTBOX, self.on_select_image)hbox2.Add(self.image_list, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)# Image display area and controlsright_panel = wx.Panel(self.panel)right_sizer = wx.BoxSizer(wx.VERTICAL)self.image_display = wx.StaticBitmap(right_panel)right_sizer.Add(self.image_display, proportion=1, flag=wx.EXPAND|wx.ALL, border=5)btn_sizer = wx.BoxSizer(wx.HORIZONTAL)rotate_btn = wx.Button(right_panel, label='Rotate')rotate_btn.Bind(wx.EVT_BUTTON, self.on_rotate_image)btn_sizer.Add(rotate_btn, flag=wx.ALL, border=5)zoom_in_btn = wx.Button(right_panel, label='Zoom In')zoom_in_btn.Bind(wx.EVT_BUTTON, self.on_zoom_in_image)btn_sizer.Add(zoom_in_btn, flag=wx.ALL, border=5)zoom_out_btn = wx.Button(right_panel, label='Zoom Out')zoom_out_btn.Bind(wx.EVT_BUTTON, self.on_zoom_out_image)btn_sizer.Add(zoom_out_btn, flag=wx.ALL, border=5)reset_btn = wx.Button(right_panel, label='Reset')reset_btn.Bind(wx.EVT_BUTTON, self.on_reset_image)btn_sizer.Add(reset_btn, flag=wx.ALL, border=5)compare_btn = wx.Button(right_panel, label='Compare MD5')compare_btn.Bind(wx.EVT_BUTTON, self.on_compare_md5)btn_sizer.Add(compare_btn, flag=wx.ALL, border=5)right_sizer.Add(btn_sizer, flag=wx.ALL|wx.CENTER, border=10)right_panel.SetSizer(right_sizer)hbox2.Add(right_panel, proportion=2, flag=wx.EXPAND|wx.ALL, border=5)vbox.Add(hbox2, proportion=1, flag=wx.EXPAND)self.panel.SetSizer(vbox)def on_select_database(self, event):with wx.FileDialog(self, "Choose SQLite database file", wildcard="SQLite files (*.db)|*.db|All files (*.*)|*.*", style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:if fileDialog.ShowModal() == wx.ID_CANCEL:returnself.db_path = fileDialog.GetPath()self.db_path_text.SetValue(self.db_path)self.load_image_names()def load_image_names(self):if not self.db_path:wx.MessageBox('Database path is required', 'Error', wx.OK | wx.ICON_ERROR)returnconn = sqlite3.connect(self.db_path)cursor = conn.cursor()cursor.execute("SELECT picname FROM pics")rows = cursor.fetchall()self.image_list.Clear()for row in rows:self.image_list.Append(row[0])conn.close()def on_select_image(self, event):selected_image = self.image_list.GetString(self.image_list.GetSelection())conn = sqlite3.connect(self.db_path)cursor = conn.cursor()cursor.execute("SELECT pic, picmd5, picdate FROM pics WHERE picname = ?", (selected_image,))row = cursor.fetchone()if row:pic_data, picmd5, picdate = rowself.original_image = Image.open(io.BytesIO(pic_data))self.display_image(self.original_image)self.SetTitle(f"MD5: {picmd5} | Date: {picdate}")conn.close()def display_image(self, image):wx_image = wx.Image(image.size[0], image.size[1])wx_image.SetData(image.convert("RGB").tobytes())bitmap = wx.Bitmap(wx_image)self.image_display.SetBitmap(bitmap)self.panel.Layout()def on_rotate_image(self, event):if self.original_image:self.original_image = self.original_image.rotate(90, expand=True)self.display_image(self.original_image)def on_zoom_in_image(self, event):if self.original_image:width, height = self.original_image.sizeself.original_image = self.original_image.resize((width + int(width * 0.1), height + int(height * 0.1)), Image.ANTIALIAS)self.display_image(self.original_image)def on_zoom_out_image(self, event):if self.original_image:width, height = self.original_image.sizeself.original_image = self.original_image.resize((width - int(width * 0.1), height - int(height * 0.1)), Image.ANTIALIAS)self.display_image(self.original_image)def on_reset_image(self, event):if self.original_image:self.load_image_names()self.original_image = Noneself.image_display.SetBitmap(wx.NullBitmap)self.SetTitle("Image Viewer")def on_compare_md5(self, event):if self.original_image:img_byte_arr = io.BytesIO()self.original_image.save(img_byte_arr, format='PNG')md5_hash = hashlib.md5(img_byte_arr.getvalue()).hexdigest()conn = sqlite3.connect(self.db_path)cursor = conn.cursor()cursor.execute("SELECT picname FROM pics WHERE picmd5 = ?", (md5_hash,))row = cursor.fetchone()if row:wx.MessageBox(f"Image with MD5 {md5_hash} found: {row[0]}", 'MD5 Match', wx.OK | wx.ICON_INFORMATION)else:wx.MessageBox(f"No image with MD5 {md5_hash} found.", 'MD5 Match', wx.OK | wx.ICON_INFORMATION)conn.close()if __name__ == '__main__':app = wx.App(False)frame = ImageViewerApp(None, "Image Viewer")app.MainLoop()

好的,我们来看一下这个图像查看器的主要代码部分:

def on_select_image(self, event):# 获取选中的图像名称selected_image = self.image_list.GetString(self.image_list.GetSelection())conn = sqlite3.connect(self.db_path)cursor = conn.cursor()# 从数据库中查询该图像的数据和元数据cursor.execute("SELECT pic, picmd5, picdate FROM pics WHERE picname = ?", (selected_image,))row = cursor.fetchone()if row:pic_data, picmd5, picdate = row# 从字节数据创建PIL Image对象self.original_image = Image.open(io.BytesIO(pic_data))self.display_image(self.original_image)self.SetTitle(f"MD5: {picmd5} | Date: {picdate}")conn.close()def display_image(self, image):# 将PIL Image对象转换为wxPython可显示的位图wx_image = wx.Image(image.size[0], image.size[1])wx_image.SetData(image.convert("RGB").tobytes())bitmap = wx.Bitmap(wx_image)self.image_display.SetBitmap(bitmap)self.panel.Layout()

这部分代码是在选择了一个图像后执行的。首先从列表框获取选中的图像名称,然后连接到SQLite数据库,使用SQL查询语句从pics表中获取该图像名称对应的图像数据(pic字段)、MD5哈希值(picmd5)和日期(picdate)。

接着使用PIL库的Image.open()方法从字节数据创建一个Image对象,就可以对该图像进行后续的操作了。display_image()函数则负责将PIL Image对象转换为wxPython可以显示的位图,并设置到GUI的StaticBitmap控件上。

def on_rotate_image(self, event):if self.original_image:self.original_image = self.original_image.rotate(90, expand=True)self.display_image(self.original_image)

这段代码实现了图像旋转功能。利用PIL的Image.rotate()方法可以将图像按指定角度旋转,expand=True表示可以扩展输出尺寸以适应旋转后的图像。

def on_compare_md5(self, event):if self.original_image:img_byte_arr = io.BytesIO()self.original_image.save(img_byte_arr, format='PNG')md5_hash = hashlib.md5(img_byte_arr.getvalue()).hexdigest()conn = sqlite3.connect(self.db_path)cursor = conn.cursor()cursor.execute("SELECT picname FROM pics WHERE picmd5 = ?", (md5_hash,))row = cursor.fetchone()if row:wx.MessageBox(f"Image with MD5 {md5_hash} found: {row[0]}", 'MD5 Match', wx.OK | wx.ICON_INFORMATION)else:wx.MessageBox(f"No image with MD5 {md5_hash} found.", 'MD5 Match', wx.OK | wx.ICON_INFORMATION)conn.close()

这是一个非常巧妙的功能,可以根据计算出的MD5哈希值在数据库中查找是否有重复的图像。首先将当前图像保存到字节IO流中,然后使用hashlib计算该字节流的MD5哈希值。接着连接数据库,执行SQL查询语句查找pics表中是否有相同MD5哈希值的记录。根据查询结果,弹出不同的MessageBox提示信息。

结果如下:

在这里插入图片描述

通过这些代码,我们可以看到作者利用了Python的多个强大库和SQLite数据库,实现了一个既实用又有创意的小程序。代码写得很优雅,值得我们学习和借鉴。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/20332.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FPGA-ARM架构与分类

ARM架构,曾称进阶精简指令集机器(Advanced RISC Machine)更早称作Acorn RISC Machine,是一个32位精简指令集(RISC)处理器架构。 主要是根据FPGA zynq-7000的芯片编写的知识思维导图总结,废话不多说自取吧 …

【Python内功心法】:深挖内置函数,释放语言潜能

文章目录 🚀一、常见内置函数🌈二、高级内置函数⭐1. enumerate函数👊2. eval函数❤️3. exec函数💥4. eval与exec 中 globals与locals如何用☔4-1 globals 参数🎬4-2 locals 参数 ❤️5. filter函数👊6. z…

Python 之SQLAlchemy使用详细说明

目录 1、SQLAlchemy 1.1、ORM概述 1.2、SQLAlchemy概述 1.3、SQLAlchemy的组成部分 1.4、SQLAlchemy的使用 1.4.1、安装 1.4.2、创建数据库连接 1.4.3、执行原生SQL语句 1.4.4、映射已存在的表 1.4.5、创建表 1.4.5.1、创建表的两种方式 1、使用 Table 类直接创建表…

安卓如何书写注册和登录界面

一、如何跳转一个活动 左边的是本活动名称, 右边的是跳转界面活动名称 Intent intent new Intent(LoginActivity.this, RegisterActivity.class); startActivity(intent); finish(); 二、如果在不同的界面传递参数 //发送消息 SharedPreferences sharedPreferen…

【学习Day4】计算机基础

✍🏻记录学习过程中的输出,坚持每天学习一点点~ ❤️希望能给大家提供帮助~欢迎点赞👍🏻收藏⭐评论✍🏻指点🙏 ❤️学习和复习的过程是愉快嘚。 1.7.3 流水线 流水线(pipeline)技术…

单片机按键处理模块

一 介绍 1.key_board用于单片机中的小巧多功能按键支持,软件采用了分层的思想,并且做到了与平台无关,用户只需要提供按键的基本信息和读写io电平的函数即可,非常方便移植,同时支持多个矩阵键盘及多个单io控制键盘。 …

chap5 CNN

卷积神经网络(CNN) 问题描述: 利用卷积神经网络,实现对MNIST数据集的分类问题 数据集: MNIST数据集包括60000张训练图片和10000张测试图片。图片样本的数量已经足够训练一个很复杂的模型(例如 CNN的深层…

商用未来何时来?软银揭示量子计算商业应用现状

内容来源:量子前哨(ID:Qforepost) 文丨沛贤/浪味仙 排版丨沛贤 深度好文:3000字丨10分钟阅读 摘要:软银(SoftBank)先进技术研究所正在积极推进量子计算商业应用,借助与…

SpringCloud Feign用法

1.在目标应用的启动类上添加开启远程fein调用注解: 2.添加一个feign调用的interface FeignClient("gulimall-coupon") public interface CouponFeignService {PostMapping("/coupon/spubounds/save")R save(RequestBody SpuBondTo spuBounds);…

随记-点选验证码(二)

之前写过一篇文章 随记-点选验证码 ,当时借助了 ddddocr 完成了ocr 识别,这篇文章算是对之前的补充。 本次更换了新的方案: 通过 ultralytics(YOLO8)训练自己的模型 吐槽一句:标注真是一件耗时的事情啊&am…

鸿蒙实现汉字转拼音

1.使用三方库 pinyin-pro 地址:OpenHarmony三方库中心仓 亲测可用,一共三个关于 转pinyin的库,一个无法使用,另一个时间太久。 ohpm i pinyin-proimport { pinyin } from pinyin-pro;// 获取带音调拼音 pinyin(汉语拼音); // …

【Java数据结构】详解LinkedList与链表(一)

🔒文章目录: 1.❤️❤️前言~🥳🎉🎉🎉 2.ArrayList的缺陷 3.链表的概念及结构 4.无头单向非循环链表的实现 4.1成员属性 4.2成员方法 createList display——打印链表 addFirst——头插 addLast…

少样本学习与零样本学习:理解与应用

少样本学习与零样本学习:理解与应用 在现代机器学习领域中,少样本学习(Few-Shot Learning)和零样本学习(Zero-Shot Learning)正变得越来越重要。这些技术能够在数据稀缺的情况下有效地进行学习和推理&…

2024就业寒潮下的挑战与机遇:能否守住饭碗,人工智能能否成为新春天?

前言 随着时代的飞速发展,2024年的就业市场迎来了前所未有的挑战。数以百万计的高校毕业生涌入市场,使得就业竞争愈发激烈。然而,在这股就业寒潮中,我们也看到了新的曙光——人工智能的崛起。这一新兴行业以其独特的魅力和巨大的…

深入分析 Android Service (五)

文章目录 深入分析 Android Service (五)1. 深入分析 Service 与 Activity 之间的通信2. Messenger 的内部工作原理2.1 服务端实现2.2 客户端实现 3. AIDL 的内部工作原理3.1 定义 AIDL 接口3.2 服务端实现3.3 客户端实现 4. Service 的优化建议和最佳实践4.1 异步操作4.2 资源…

【Linux】权限的概念

1.Linux权限的概念 Linux下有两种用户:超级用户(root)、普通用户。 超级用户:可以再linux系统下做任何事情,不受权限限制 普通用户:在linux下做有限的事情,受权限设置。 windows下也有超级用户…

Object.entries方法的使用

Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组。 有以下需求&#xff1a; let cpuData reactive([{ label: 总量, content: test },{ label: 已使用, content: test },{ label: 未使用, content: test } ])<el-form label-position"left" l…

环卫车北斗GPS视频监控定位解决方案的应用与优势

一、引言 随着城市化进程的加快&#xff0c;环卫车作为城市环境卫生的重要保障力量&#xff0c;其运行效率与安全性直接关系到城市形象与居民生活品质。然而&#xff0c;传统的环卫车管理模式往往存在信息不对称、调度不合理、行驶不规范等问题&#xff0c;导致城市道路污染和…

微信小程序对接发货功能

注&#xff1a;微信小程序对接发货功能 文档地址&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html php代码 common.php use think\Config; use think\Db; use fast\Http; us…

LabVIEW远程开发与调试

在现代项目开发中&#xff0c;远程开发与调试已经成为一种常见的模式&#xff0c;特别是在使用LabVIEW进行工程项目时。本文将详细分析LabVIEW远程开发与调试的优缺点&#xff0c;并从多个角度说明如何建议客户采用这种方式&#xff0c;以提高项目效率和质量。 优点 灵活性和便…