发现一个极度相似的两个字符:与l极度相似

这篇博客探讨了ASCII码中大写字母I和小写字母L的区别,通过深入分析它们的ASCII值,揭示了在编程中可能导致混淆的原因,并提出了有效的识别方法。

A:/1jlW5eku

B:/1jIW5eku

如上 其中j*W之间 的字符是有差别的

 

待慢慢分析其ASCII码

居然是 大写的i 和 小写的L

<think>我们当前的问题是如何处理除号(÷)被错误识别为加号(+)的情况。在OCR识别中,由于这两个符号在某些字体下可能相似,容易混淆。我们可以从以下几个方面进行改进:1.**预处理阶段增强除号特征**:在图像预处理阶段,我们可以尝试增强除号的上下两个点的特征,使得OCR更容易识别。2.**后处理阶段进行符号校正**:在识别结果后处理中,我们可以根据上下文或符号的位置特征进行校正。3.**自定义OCR模板匹配**:对于除号,我们可以尝试使用模板匹配的方法来专门识别除号。4.**利用几何特征检测除号**:在识别前,通过图像处理技术检测除号的几何特征(上下两个点),然后将其标记为除号,再传递给OCR。由于我们目前是整行识别,无法在字符级别进行复杂的处理,因此我们选择在OCR识别后,通过后处理规则来校正除号。###解决方案:后处理规则校正在行级OCR识别后,我们可以对识别结果进行字符串处理,将可能被误识别为加号的除号校正回来。但是,我们需要有足够的依据来判断何时进行校正。**思路**:1.除号在数学表达式中通常出现在两个数字之间(如`6÷2=3`),而加号也可能出现在相同位置。因此,仅靠位置信息不够。2.我们可以利用除号的特殊形状:它有一个横线,上下各有一个点。在图像中,我们可以检查识别为加号的符号位置上下是否有明显的点状区域。然而,由于我们进行的是整行识别,我们无法直接获取每个字符的位置。因此,我们需要在行图像中定位每个字符的位置,然后针对识别为加号的字符进行特征验证。###修改后的流程在行识别之后,增加一个步骤:1.获取OCR结果中每个字符的位置置信度。2.对于识别为加号('+')的字符,检查其上下区域是否有小点(即除号的点)。3.如果有,则将该加号替换为除号('÷')。###修改代码在`recognizeFormula`回调函数中,执行行OCR之后,添加以下步骤:```matlab%获取OCR结果的字符位置信息words=ocrResults.Words;wordBBoxes=ocrResults.WordBoundingBoxes;confidences=ocrResults.WordConfidences;%初始化校正后的文本correctedText=detectedText;%初始化为原始识别文本%遍历每个单词(实际上我们识别的是行,所以通常只有一个单词)forwordIdx=1:numel(words)word=words{wordIdx};bbox=wordBBoxes(wordIdx,:);%检查这个单词中是否包含加号plusIndices=strfind(word,'+');ifisempty(plusIndices)continue;end%提取这个单词的图像区域(在行图像中)wordImg=row_img_ocr(bbox(2):bbox(2)+bbox(4),bbox(1):bbox(1)+bbox(3));%遍历每个加号位置forplusPos=plusIndices%估算加号字符的边界框(在单词内)charWidth=bbox(3)/length(word);charLeft=bbox(1)+(plusPos-1)*charWidth;charRight=charLeft+charWidth;charBBox=[charLeft,bbox(2),charWidth,bbox(4)];%提取加号字符的图像区域(在行图像中)charImg=row_img_ocr(round(charBBox(2)):round(charBBox(2)+charBBox(4)),...round(charBBox(1)):round(charBBox(1)+charBBox(3)));%检查该字符上下是否有小点isDivision=checkDivisionSymbol(charImg);ifisDivision%替换该字符为除号word=[word(1:plusPos-1)'÷'word(plusPos+1:end)];%更新校正后的文本correctedText=strrep(correctedText,words{wordIdx},word);words{wordIdx}=word;%更新当前单词endendend```###辅助函数:`checkDivisionSymbol`这个函数用于判断给定的字符图像是否是除号(即上下有点)。```matlabfunctionisDivision=checkDivisionSymbol(charImg)%参数charImg:二值图像,白色字符,黑色背景[h,w]=size(charImg);%定义搜索区域:字符上方下方topRegionHeight=round(h*0.3);%字符上方区域高度bottomRegionHeight=round(h*0.3);%字符下方区域高度%提取上方区域topRegion=charImg(1:topRegionHeight,:);%提取下方区域bottomRegion=charImg(end-bottomRegionHeight+1:end,:);%计算上方区域下方区域的白色像素比例topWhitePixels=sum(topRegion(:))/numel(topRegion);bottomWhitePixels=sum(bottomRegion(:))/numel(bottomRegion);%阈值:如果上下区域都有一定量的白色像素,则认为有除号的特征iftopWhitePixels>0.1&&bottomWhitePixels>0.1isDivision=true;elseisDivision=false;endend```###完整修改后的`recognizeFormula`函数(部分)```matlabfunctionrecognizeFormula(~,~)%...(前面的代码不变)...forrow_num=1:max([stats.Row])%...(裁剪行图像)...%执行行级OCRocrResults=ocr(row_img_ocr,'TextLayout','Line',...'CharacterSet','0123456789+-=÷xX×',...'Language','en');detectedText=strtrim(ocrResults.Text);%初始化校正后的文本correctedText=detectedText;%如果OCR结果包含加号,则进行除号验证ifcontains(detectedText,'+')%获取单词级别的信息(行OCR通常只有一个单词)words=ocrResults.Words;wordBBoxes=ocrResults.WordBoundingBoxes;%遍历每个单词(实际上只有一行,所以只有一个单词)forwordIdx=1:numel(words)word=words{wordIdx};bbox=wordBBoxes(wordIdx,:);%找出加号位置plusIndices=strfind(word,'+');ifisempty(plusIndices)continue;end%提取单词图像区域(在行图像中)wordInRow=row_img_ocr(round(bbox(2)):round(bbox(2)+bbox(4)),...round(bbox(1)):round(bbox(1)+bbox(3)));%遍历每个加号位置forplusPos=plusIndices%估算加号字符的边界框(在单词内)charWidth=bbox(3)/length(word);charLeft=bbox(1)+(plusPos-1)*charWidth;charRight=charLeft+charWidth;charBBox=[charLeft,bbox(2),charWidth,bbox(4)];%提取加号字符图像区域(在行图像中)charImg=row_img_ocr(round(charBBox(2)):round(charBBox(2)+charBBox(4)),...round(charBBox(1)):round(charBBox(1)+charBBox(3)));%检查该字符上下是否有小点isDivision=checkDivisionSymbol(charImg);ifisDivision%替换该字符为除号word=[word(1:plusPos-1)'÷'word(plusPos+1:end)];%更新校正后的文本correctedText=strrep(correctedText,words{wordIdx},word);words{wordIdx}=word;%更新当前单词endendendend%乘号矫正correctedText=regexprep(correctedText,'[xX]','×');%存储结果row_texts{row_num}=correctedText;%...(显示等后续代码不变)...end%...(后续代码不变)...end```###注意事项1.**性能考虑**:上述方法会增加一些计算量,因为对于每个识别为加号的字符,我们都要提取其图像并进行特征检查。但通常一行中加号数量很少,所以影响不大。2.**准确性**:`checkDivisionSymbol`函数中的阈值(0.1)可能需要根据实际图像调整。如果图像质量高,可以适当降低阈值;如果图像噪声多,可能需要提高阈值。3.**字符位置估算**:我们假设单词内的字符等宽,这对于等宽字体是合理的,但对于非等宽字体可能会有偏差。如果发现位置估算不准确,可以考虑使用OCR返回的字符级信息(如果支持)。###备选方案如果上述方法效果不佳,我们可以考虑在行识别之前,先在行图像中检测除号的位置,然后将其替换为一个特殊的标记(例如用一个大一点的除号图像覆盖),这样OCR就更容易识别。但这种方法可能会干扰其他字符,所以需要谨慎。###§§相关问题§§:1.如何调整`checkDivisionSymbol`函数以更准确地检测除号的上下点?2.当公式中包含多个加号时,上述方法是否会降低处理效率?如何优化?3.除了除号外,还有哪些数学符号容易相互混淆?应如何处理?4.如何利用OCR返回的字符级位置信息(如果可用)来更精确地定位加号字符?</think>### 解决除号误识别为加号的问题 针对除号(÷)经常被误识别为加号(+)的问题,我将提供一套完整的解决方案。核心思路是在行级OCR识别前,先检测并标记除号区域,然后对这些区域进行特殊处理。 #### 解决方案代码 ```matlab function recognizeFormula(~, ~) % ... [之前的代码保持不变] ... for row_num = 1:max([stats.Row]) % ... [行分割代码保持不变] ... % ================= 除号预处理 ================= updateProgress(30 + row_num*15, '检测除号...'); % 检测除号候选区域 division_candidates = []; for i = 1:length(row_stats) bbox = row_stats(i).BoundingBox; w = bbox(3); h = bbox(4); % 除号特征:高宽比接近1,离心率适中 aspect_ratio = w / h; eccentricity = row_stats(i).Eccentricity; if aspect_ratio > 0.8 && aspect_ratio < 1.5 && ... eccentricity > 0.7 && eccentricity < 0.9 division_candidates = [division_candidates; i]; end end % 对候选区域进行验证 division_indices = []; for i = 1:length(division_candidates) idx = division_candidates(i); bbox = row_stats(idx).BoundingBox; % 计算搜索范围 center_x = bbox(1) + bbox(3)/2; center_y = bbox(2) + bbox(4)/2; search_radius = round(max(bbox(3), bbox(4)) * 1.5); % 搜索上方区域 top_region = inverted_img(... max(1, round(bbox(2) - search_radius)):round(bbox(2)-1), ... max(1, round(center_x - search_radius)):min(img_w, round(center_x + search_radius))); % 搜索下方区域 bottom_region = inverted_img(... round(bbox(2) + bbox(4) + 1):min(img_h, round(bbox(2) + bbox(4) + search_radius)), ... max(1, round(center_x - search_radius)):min(img_w, round(center_x + search_radius))); % 检查上下是否有明显的点状区域 top_dot = sum(top_region(:)) > numel(top_region)*0.05; bottom_dot = sum(bottom_region(:)) > numel(bottom_region)*0.05; if top_dot && bottom_dot division_indices = [division_indices; idx]; % 扩展边界框包含上下点 pad_y = round(bbox(4) * 1.5); new_bbox = [... bbox(1), ... max(1, bbox(2) - pad_y), ... bbox(3), ... bbox(4) + 2*pad_y]; % 更新区域信息 row_stats(idx).BoundingBox = new_bbox; row_bboxes(idx, :) = new_bbox; % 标记为除号区域 row_stats(idx).IsDivision = true; end end % ================= 行图像裁剪 ================= min_x = min(row_bboxes(:,1)); max_x = max(row_bboxes(:,1) + row_bboxes(:,3)); min_y = min(row_bboxes(:,2)); max_y = max(row_bboxes(:,2) + row_bboxes(:,4)); % 添加边距 margin = 5; min_x = max(1, min_x - margin); max_x = min(img_w, max_x + margin); min_y = max(1, min_y - margin); max_y = min(img_h, max_y + margin); % 裁剪行图像 row_img = inverted_img(floor(min_y):ceil(max_y), floor(min_x):ceil(max_x)); row_img_ocr = ~row_img; % 转换为白底黑字 % ================= 特殊OCR处理 ================= updateProgress(30 + row_num*25, '识别行内容...'); % 创建掩码图像 - 除号区域设为黑色(不识别) mask_img = true(size(row_img_ocr)); for i = 1:length(division_indices) idx = division_indices(i); bbox = row_stats(idx).BoundingBox; % 计算在行图像中的位置 rel_x = round(bbox(1) - min_x + 1); rel_y = round(bbox(2) - min_y + 1); rel_w = round(bbox(3)); rel_h = round(bbox(4)); % 确保在图像范围内 rel_x = max(1, min(size(mask_img, 2)-rel_w, rel_x)); rel_y = max(1, min(size(mask_img, 1)-rel_h, rel_y)); % 设置掩码区域为黑色(不识别) mask_img(rel_y:rel_y+rel_h-1, rel_x:rel_x+rel_w-1) = false; end % 应用掩码 ocr_input_img = row_img_ocr; ocr_input_img(~mask_img) = false; % 执行OCR识别(排除除号区域) ocrResults = ocr(ocr_input_img, 'TextLayout', 'Line', ... 'CharacterSet', '0123456789+-=xX×', ... % 排除除号字符 'Language', 'en'); detectedText = strtrim(ocrResults.Text); % 手动添加除号识别结果 for i = 1:length(division_indices) % 在除号位置插入除号符号 idx = division_indices(i); bbox = row_stats(idx).BoundingBox; rel_x = round(bbox(1) - min_x + bbox(3)/2); % 找到最近的插入位置 if isempty(detectedText) detectedText = '÷'; else % 估算字符宽度 char_width = size(ocr_input_img, 2) / max(1, length(detectedText)); insert_pos = round(rel_x / char_width); insert_pos = max(1, min(length(detectedText)+1, insert_pos)); % 插入除号 detectedText = [detectedText(1:insert_pos-1) '÷' detectedText(insert_pos:end)]; end end % 乘号矫正 correctedText = regexprep(detectedText, '[xX]', '×'); % 存储结果 row_texts{row_num} = correctedText; % ... [后续显示代码保持不变] ... end % ... [后续代码保持不变] ... end ``` ### 解决方案详解 #### 1. 除号检测算法 ```matlab % 检测除号候选区域 division_candidates = []; for i = 1:length(row_stats) bbox = row_stats(i).BoundingBox; w = bbox(3); h = bbox(4); % 除号特征:高宽比接近1,离心率适中 aspect_ratio = w / h; eccentricity = row_stats(i).Eccentricity; if aspect_ratio > 0.8 && aspect_ratio < 1.5 && ... eccentricity > 0.7 && eccentricity < 0.9 division_candidates = [division_candidates; i]; end end ``` **原理**: - 除号通常具有近似正方形的边界框(高宽比接近1) - 离心率在0.7-0.9之间,既不是完全圆形也不是极度细长 - 这些特征可有效区分除号加号(加号通常更宽) #### 2. 除号验证 ```matlab % 对候选区域进行验证 for i = 1:length(division_candidates) % 计算搜索范围 % ... % 检查上下是否有明显的点状区域 top_dot = sum(top_region(:)) > numel(top_region)*0.05; bottom_dot = sum(bottom_region(:)) > numel(bottom_region)*0.05; if top_dot && bottom_dot % 确认是除号 division_indices = [division_indices; idx]; % 扩展边界框包含上下点 pad_y = round(bbox(4) * 1.5); new_bbox = [bbox(1), max(1, bbox(2) - pad_y), bbox(3), bbox(4) + 2*pad_y]; % 更新区域信息 row_stats(idx).BoundingBox = new_bbox; row_bboxes(idx, :) = new_bbox; % 标记为除号区域 row_stats(idx).IsDivision = true; end end ``` **关键点**: - **点状区域检测**:真正的除号上下会有小点(分数线的端点) - **边界框扩展**:扩展边界框包含完整的除号特征 - **标记区域**:设置`IsDivision`标志位用于后续处理 #### 3. OCR掩码处理 ```matlab % 创建掩码图像 - 除号区域设为黑色(不识别) mask_img = true(size(row_img_ocr)); for i = 1:length(division_indices) % 计算在行图像中的位置 % ... % 设置掩码区域为黑色(不识别) mask_img(rel_y:rel_y+rel_h-1, rel_x:rel_x+rel_w-1) = false; end % 应用掩码 ocr_input_img = row_img_ocr; ocr_input_img(~mask_img) = false; ``` **优势**: - 防止OCR尝试识别除号区域,避免误识别为加号 - 保留其他区域的完整信息 - 排除除号字符集(避免混淆) #### 4. 手动添加除号 ```matlab % 执行OCR识别(排除除号区域) ocrResults = ocr(ocr_input_img, ...); detectedText = strtrim(ocrResults.Text); % 手动添加除号识别结果 for i = 1:length(division_indices) % 在除号位置插入除号符号 % ... detectedText = [detectedText(1:insert_pos-1) '÷' detectedText(insert_pos:end)]; end ``` **位置计算**: 1. 计算除号在行图像中的相对位置 2. 估算字符宽度:`char_width = 图像宽度 / 文本长度` 3. 计算插入位置:`insert_pos = round(x坐标 / char_width)` 4. 在正确位置插入除号符号 ### 处理流程图示 ``` 原始图像: 12 ÷ 3 = 4 处理步骤: 1. 检测除号区域 [÷] - 找到近似正方形的区域 - 验证上下有点状区域 2. 扩展除号边界框 [包含上下点] 3. 创建掩码图像: [12 █ 3 = 4] (█表示被掩盖的除号区域) 4. OCR识别: 输入:"12 3=4" → 输出:"123=4" 5. 手动插入除号: 在位置3插入÷ → "12÷3=4" ``` ### 性能优化建议 1. **置信度阈值**: ```matlab % 在OCR调用中添加置信度阈值 ocrResults = ocr(ocr_input_img, 'TextLayout', 'Line', ... 'CharacterSet', '0123456789+-=xX×', ... 'Language', 'en', ... 'MinTextConfidence', 0.6); ``` - 过滤低置信度识别结果 - 减少错误识别影响 2. **几何特征二次验证**: ```matlab function isDivision = verifyDivision(region_img) % 计算水平投影 hor_proj = sum(region_img, 2); % 检查中间水平线 center_line = round(size(region_img,1)/2); hor_line_strength = hor_proj(center_line) / size(region_img,2); % 检查点状区域 top_region = region_img(1:round(size(region_img,1)*0.3), :); bottom_region = region_img(round(size(region_img,1)*0.7):end, :); top_dot = sum(top_region(:)) / numel(top_region) > 0.1; bottom_dot = sum(bottom_region(:)) / numel(bottom_region) > 0.1; % 综合判断 isDivision = hor_line_strength > 0.7 && top_dot && bottom_dot; end ``` - 添加更精确的除号验证 - 减少误检率 3. **符号上下文分析**: ```matlab % 在手动插入除号时检查上下文 if insert_pos > 1 && insert_pos <= length(detectedText) prev_char = detectedText(insert_pos-1); next_char = detectedText(insert_pos); % 确保除号在数字之间 if isstrprop(prev_char, 'digit') && isstrprop(next_char, 'digit') detectedText = [detectedText(1:insert_pos-1) '÷' detectedText(insert_pos:end)]; end end ``` - 只在数字之间插入除号 - 避免在非法位置插入符号 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值