吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4315|回复: 25
收起左侧

[Python 原创] 纯python实现大漠ocr功能

  [复制链接]
18834161486 发表于 2025-1-9 14:06
分享一套自用的ocr识别及合并算法,字库借用大漠的字库数据,然后使用opencv的模板匹配来实现,代码里面有详细的例子。
[Python] 纯文本查看 复制代码
import time
from ctypes import windll
import numpy as np
import cv2
from mss import mss


class Mxbx:
    def __init__(self):
        print('欢迎使用')
        windll.user32.SetProcessDPIAware()
        self.sct = mss()

    def GetCapture(self, x1, y1, x2, y2):
        '''
        截图
        :param x1:
        :param y1:
        :param x2:
        :param y2:
        :return: rgb图像
        '''
        monitor = {'top': y1, 'left': x1, 'width': x2 - x1, 'height': y2 - y1}
        pic = self.sct.grab(monitor)
        pic = cv2.cvtColor(np.array(pic), cv2.COLOR_RGBA2RGB)
        return pic

    def parse_custom_color(self, color_string):
        r, g, b = int(color_string[4:6], 16), int(color_string[2:4], 16), int(color_string[0:2], 16)
        if len(color_string) > 6:
            dr, dg, db = int(color_string[7:9], 16), int(color_string[9:11], 16), int(color_string[11:13], 16)
        else:
            dr, dg, db = 0, 0, 0
        lower_rgb = np.array([max(0, r - dr), max(0, g - dg), max(0, b - db)], dtype=np.uint8)
        upper_rgb = np.array([min(255, r + dr), min(255, g + dg), min(255, b + db)], dtype=np.uint8)
        return lower_rgb, upper_rgb

    def Stressshow(self, x1, y1, x2, y2, colors, types=0):
        '''
        隐藏其他颜色为黑色,只保留选中颜色
        :param x1: 起点x
        :param y1: 起点Y
        :param x2: 终点x
        :param y2: 终点Y
        :param colors: 十六进制颜色,可以从大漠的色彩描述直接获取
        :param types: 0:原来颜色,非零:白色
        :return:
        '''
        image = self.GetCapture(x1, y1, x2, y2)
        colors = colors.split("|")
        masks = np.zeros_like(image[:, :, 0], dtype=np.uint8)
        for color in colors:
            lower_rgb, upper_rgb = self.parse_custom_color(color)
            mask = cv2.inRange(image, lower_rgb, upper_rgb)
            masks += mask
        result = cv2.bitwise_and(image, image, mask=masks)
        if types:
            result[np.where(masks != 0)] = [255, 255, 255]
        return result

    def SetDict(self, lines):
        '''
        初始化字库文件
        :param lines: 字库数组
        :return: 点阵数据
        '''
        des = {}
        for line in lines[1:]:
            parts = line.split("$")
            hex_str = parts[0]
            hex_values = np.array([int(c, 16) for c in hex_str], dtype=np.uint8)
            bin_values = np.unpackbits(hex_values[:, None], axis=1).reshape(-1, 8)[:, 4:]  # 只需要后4位
            num_elements = bin_values.shape[0]
            remainder = num_elements % 11
            if remainder != 0:
                padding = 11 - remainder
                bin_values = np.pad(bin_values, ((0, padding), (0, 0)), mode='constant', constant_values=0)
            bin_values = bin_values.reshape(-1, 11).T
            des.setdefault(parts[1], bin_values)
        return lines[0], des

    def Ocr(self, x1, y1, x2, y2, thd, DIict):
        '''
        点阵文字识别
        :param x1:
        :param y1:
        :param x2:
        :param y2:
        :param thd: 相似度
        :param DIict: 字库
        :return:
        '''

        def filter_points(points, max_distance):
            if points.shape[0] <= 1:
                return points

            diff = points[:, None, :] - points[None, :, :]
            distances = np.linalg.norm(diff, axis=2)
            mask = distances < max_distance
            to_remove = np.zeros(len(points), dtype=bool)
            for i in range(len(points)):
                if to_remove[i]:
                    continue
                for j in range(i + 1, len(points)):
                    if mask[i, j]:
                        to_remove[j] = True
            cleaned_data = points[~to_remove]
            return cleaned_data

        img = self.Stressshow(x1, y1, x2, y2, DIict[0], 1)
        img = (img != 0).any(axis=2).astype(int)
        img = np.array(img, dtype=np.uint8)
        res = {}
        for key, value in DIict[1].items():
            _, h = value.shape
            if x2 - x1 > h and y2 - y1 > 11:
                result = cv2.matchTemplate(value, img, cv2.TM_CCOEFF_NORMED)
                loc = np.column_stack(np.where(result >= thd))
                loc = filter_points(loc, min(6, h))
                if loc.size > 1:
                    py, px = 6 + y1, int(h / 2 + x1)
                    loc += (py, px)
                    loc = loc[:, [1, 0]]
                    res.setdefault(key, loc)
        return res if len(res) > 0 else 0

    def Getocr(self, input_data, x_size=15):
        '''
        解析ocr
        :param input_data:ocr返回值
        :param x_size: x间距,距离小合并到一起
        :return:
        '''
        output = [(key, tuple(row)) for key, arr in input_data.items() for row in arr]
        output.sort(key=lambda x: x[1][1])
        groups = []
        current_group = []
        for i, (char, coord) in enumerate(output):
            if current_group:
                last_coord = current_group[-1][1]
                if abs(coord[1] - last_coord[1]) <= 5:
                    current_group.append((char, coord))
                else:
                    groups.append(current_group)
                    current_group = [(char, coord)]
            else:
                current_group.append((char, coord))
        if current_group:
            groups.append(current_group)

        def merge_by_x_coordinate(groups, size=x_size):
            merged_groups = []
            for group in groups:
                group.sort(key=lambda x: x[1][0])
                merged_group = []
                current_subgroup = []
                for i, (char, coord) in enumerate(group):
                    if not current_subgroup:
                        current_subgroup.append((char, coord))
                    else:
                        last_char, last_coord = current_subgroup[-1]
                        if abs(coord[0] - last_coord[0]) <= size:
                            current_subgroup.append((char, coord))
                        else:
                            merged_group.append(current_subgroup)
                            current_subgroup = [(char, coord)]
                if current_subgroup:
                    merged_group.append(current_subgroup)
                merged_groups.append(merged_group)
            return merged_groups

        merged_groups = merge_by_x_coordinate(groups, size=x_size)

        def merge_characters(merged_groups):
            merged_dict = {}
            for group in merged_groups:
                for subgroup in group:
                    merged_char = ''.join([char for char, _ in subgroup])
                    first_coord = subgroup[0][1]
                    if merged_char not in merged_dict:
                        merged_dict[merged_char] = []
                    merged_dict[merged_char].append(first_coord)
            return merged_dict

        merged_dict = merge_characters(merged_groups)
        return merged_dict


a = Mxbx()
st = time.time()

# 初始化字库数据,第一行为颜色值,后续为字库数据
zk1 = a.SetDict(['b6ffdb-202020|ffffff-202020|ffb666-303030|90dbff-202020|ffffdb-202020',
                 '2080525220500D21A1FD44C0D0560A864008110$梁$0.0.52$13',
                 '04108610C604A4030$3$0.0.16$11',
                 '200001007FF$1$0.0.13$11',
                 '268C1A00C01803001C60$0$0.0.20$11',
                 ])
# 这个字库数据是电脑右下角时间及日期
zk2 = a.SetDict(['d0d4d5-303030',
                 '200401007FFFFE$1$0.0.25$11',
                 '40F8360CC11863F85E08$2$0.0.32$11',
                 '40508610C21CE6F78060$3$0.0.28$11',
                 '0100E0340C8711FFFFF808$4$0.0.37$11',
                 '085F0620C418C70F80E0$5$0.0.28$11',
                 '1F8ED920C4188318E1F0$6$0.0.33$11',
                 '80100201C0F871383C0600$7$0.0.24$11',
                 '33CFCE10C21843FCDCF0$8$0.0.39$11',
                 '7C58C608C11826DF8FC0$9$0.0.35$11',
                 '3F8C1E00C01803C19FE0$0$0.0.31$11'])

b = a.Ocr(1763, 1032, 1855, 1079, 0.9, zk2)
if b:
    b = a.Getocr(b, 15)

print(time.time() - st)
print(b)

免费评分

参与人数 4吾爱币 +9 热心值 +4 收起 理由
ifend + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
a4480681 + 1 谢谢 很厉害 感谢大佬分享
吾蜗牛 + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

linsixi 发表于 2025-1-9 14:18
看不懂,感觉很牛逼的样子
Vampiremss 发表于 2025-1-9 14:46
 楼主| 18834161486 发表于 2025-1-9 14:48

按照格式导入正确的字库数据,选择好范围就好了
moyc 发表于 2025-1-9 15:22
不会用,咋办
 楼主| 18834161486 发表于 2025-1-9 15:27

B站搜索萌新本炘,有视频教程
xbang 发表于 2025-1-9 15:31
python可以做这个啊。。。。认知上 就是爬虫啊,。。。。。
 楼主| 18834161486 发表于 2025-1-9 15:50
xbang 发表于 2025-1-9 15:31
python可以做这个啊。。。。认知上 就是爬虫啊,。。。。。

嘎嘎好用,现在用python写脚本的挺多的。
longhua23 发表于 2025-1-9 15:58
解释有点少,没看明白
 楼主| 18834161486 发表于 2025-1-9 16:04
longhua23 发表于 2025-1-9 15:58
解释有点少,没看明白

源码不理解可以问AI,会调用就行
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-6-15 01:30

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表