python写一个截图搜索工具
Linzz

好久没写代码了,不务正业一下。

一直以来我有个奇怪的习惯,是很喜欢在看影视动漫的时候,把一些经典台词截图保存下来,然后当自己社交媒体上打算发表一些内容的时候,在截图库里找一些应景的配图。
随着图片越来越多,已经很难只凭借记忆力和肉眼去找了,于是自然而然催生了一个需求——我需要一个搜索工具,它有如下功能:
1.识别出所有图片中的文字
2.给定一个关键词,匹配所有包含该关键词的图片

因为需求非常定制化,所以只能自己动手写代码,好在思路都非常清晰简单:
1.使用ocr遍历识别所有图片文本,并建立索引;这里我用的是EasyOCR这个库
2.把所有识别结果保存起来,这样后面即使有新图片增加,也只需要跑一遍增量的部分就行
3.搜索功能,简单的字符串匹配
4.创建UI界面,包含文件夹选择部分、搜索功能部分、搜索结果及展示

大致的代码如下,勉强够用,但实际识别效果还挺差的,不过暂时没找到特别好的优化方案,就现这样吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image
import numpy as np
import easyocr
import os
import webbrowser
import threading

class ImageTextRecognizer:
def __init__(self, root):
self.root = root
self.root.title("图片文本识别与搜索")

# 存储识别结果
self.image_text_dict = {}
# 初始化EasyOCR阅读器
self.reader = easyocr.Reader(['ch_sim', 'en']) # 支持简体中文和繁体中文

# 创建界面
self.setup_ui()

def setup_ui(self):
# 文件夹选择部分
self.folder_label = tk.Label(self.root, text="选择图片文件夹:")
self.folder_label.grid(row=0, column=0, padx=10, pady=10)

self.folder_entry = tk.Entry(self.root, width=50)
self.folder_entry.grid(row=0, column=1, padx=10, pady=10)

self.folder_button = tk.Button(self.root, text="浏览", command=self.select_folder)
self.folder_button.grid(row=0, column=2, padx=10, pady=10)

# 识别按钮
self.recognize_button = tk.Button(self.root, text="识别图片文本", command=self.start_recognition)
self.recognize_button.grid(row=1, column=0, columnspan=3, pady=10)

# 搜索功能
self.search_label = tk.Label(self.root, text="搜索文本:")
self.search_label.grid(row=2, column=0, padx=10, pady=10)

self.search_entry = tk.Entry(self.root, width=50)
self.search_entry.grid(row=2, column=1, padx=10, pady=10)

self.search_button = tk.Button(self.root, text="搜索", command=self.search_text)
self.search_button.grid(row=2, column=2, padx=10, pady=10)

# 结果显示区域
self.results_label = tk.Label(self.root, text="识别结果:")
self.results_label.grid(row=3, column=0, padx=10, pady=10)

self.results_text = tk.Text(self.root, width=80, height=15)
self.results_text.grid(row=4, column=0, columnspan=3, padx=10, pady=10)

# 搜索功能结果显示
self.search_results_label = tk.Label(self.root, text="搜索结果:")
self.search_results_label.grid(row=5, column=0, padx=10, pady=10)

self.search_results_listbox = tk.Listbox(self.root, width=80, height=10)
self.search_results_listbox.grid(row=6, column=0, columnspan=3, padx=10, pady=10)
self.search_results_listbox.bind('<Double-1>', self.open_image)

# 状态栏
self.status_bar = tk.Label(self.root, text="就绪", bd=1, relief=tk.SUNKEN, anchor=tk.W)
self.status_bar.grid(row=7, column=0, columnspan=3, sticky=tk.W+tk.E)

def select_folder(self):
"""选择文件夹"""
folder_selected = filedialog.askdirectory()
if folder_selected:
self.folder_entry.delete(0, tk.END)
self.folder_entry.insert(0, folder_selected)

def recognize_text_in_image(self, image_path):
"""使用EasyOCR识别单张图片中的文本"""
try:
# 读取图片
image = np.array(Image.open(image_path))

# 识别文本
results = self.reader.readtext(image, detail=0)
text = '\n'.join(results)
return text.strip()
except Exception as e:
self.status_bar.config(text=f"识别图片 {image_path} 时出错: {str(e)}")
return ""

def process_images_in_folder(self, folder_path):
"""处理文件夹中的所有图片"""
supported_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.gif']

for root, dirs, files in os.walk(folder_path):
for file in files:
if any(file.lower().endswith(ext) for ext in supported_extensions):
file_path = os.path.join(root, file)
text = self.recognize_text_in_image(file_path)
self.image_text_dict[file_path] = text
self.update_results_display(file_path, text)
self.root.update()

def start_recognition(self):
"""开始识别过程"""
folder_path = self.folder_entry.get()
if not folder_path:
messagebox.showwarning("警告", "请选择图片文件夹")
return

self.image_text_dict.clear()
self.results_text.delete(1.0, tk.END)
self.search_results_listbox.delete(0, tk.END)

self.status_bar.config(text="正在识别文本...")

# 使用线程避免界面卡顿
threading.Thread(target=self.process_images_in_folder, args=(folder_path,), daemon=True).start()

def update_results_display(self, file_path, text):
"""更新结果显示"""
self.results_text.insert(tk.END, f"图片: {file_path}\n")
self.results_text.insert(tk.END, "文本:\n")
self.results_text.insert(tk.END, text + "\n\n")
self.results_text.see(tk.END)

def search_text(self):
"""搜索文本"""
search_term = self.search_entry.get().strip().lower()
if not search_term:
messagebox.showwarning("警告", "请输入搜索文本")
return

self.search_results_listbox.delete(0, tk.END)

for file_path, text in self.image_text_dict.items():
if search_term in text.lower():
self.search_results_listbox.insert(tk.END, file_path)

self.status_bar.config(text=f"找到 {self.search_results_listbox.size()} 个匹配项")

def open_image(self, event):
"""双击搜索结果条目打开对应的图片文件"""
try:
selection = self.search_results_listbox.curselection()
if selection:
index = selection[0]
file_path = self.search_results_listbox.get(index)
# 在Windows上使用os.startfile打开图片
if os.name == 'nt':
os.startfile(file_path)
# 在macOS和Linux上使用webbrowser.open打开图片
else:
webbrowser.open('file://' + file_path)
except Exception as e:
self.status_bar.config(text=f"打开图片时出错: {str(e)}")

if __name__ == "__main__":
root = tk.Tk()
app = ImageTextRecognizer(root)
root.mainloop()
Powered by Hexo & Theme Keep
Unique Visitor Page View