036.isEqual 不合理的重写

本文探讨了Objective-C与Swift两种编程语言在iOS开发领域的应用与区别,包括其优势、使用场景及迁移策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

---------------  FKItem.h  ---------------
#import <Foundation/Foundation.h>
@interface FKItem : NSObject
@end
---------------  FKItem.m  ---------------
#import "FKItem.h"
@implementation FKItem
@end
---------------  main.m  ---------------
#import <Foundation/Foundation.h>
#import "FKItem.h"

@interface FKDog : NSObject
@end

@implementation FKDog
- (
BOOL) isEqual:(id)other
{
     return YES// 不加判断,让FKDog对象与任何对象都相等
}
@end

int main()
{
    FKDog* dog = [[FKDog alloc] init];
    NSLog(@"FKDog对象是否isEqual: FKItem对象?%d", [dog isEqual: [FKItem new]]);
    NSLog(@"FKDog对象是否isEqual: NSString对象?%d", [dog isEqual: [NSString stringWithFormat:@"Hello"]]);
}

一、编写本节代码的具体步骤:
1.可仿照第二章001节的代码编写步骤,可以把类的接口文件,类的实现文件写在main.m文件中。

二、本节代码涉及到的知识点:
1.本节代码重写了isEqual方法,不过这种无条件返回YES的评判标准显然不太符合实际中的需求。
function robustFormulaRecognizer() % 创建主窗口 fig = figure(‘Name’, ‘鲁棒公式识别系统’, ‘NumberTitle’, ‘off’, … ‘Position’, [100, 100, 1200, 800], ‘MenuBar’, ‘none’, … ‘Color’, [0.95 0.95 0.95]); % 创建UI控件 uicontrol('Style', 'pushbutton', 'String', '上传图像', ... 'Position', [30, 750, 100, 30], 'Callback', @uploadImage, ... 'FontSize', 11, 'BackgroundColor', [0.3 0.6 0.9], 'ForegroundColor', 'white'); uicontrol('Style', 'pushbutton', 'String', '识别公式', ... 'Position', [150, 750, 100, 30], 'Callback', @recognizeFormula, ... 'FontSize', 11, 'BackgroundColor', [0.1 0.7 0.3], 'ForegroundColor', 'white'); uicontrol('Style', 'pushbutton', 'String', '清除结果', ... 'Position', [270, 750, 100, 30], 'Callback', @clearResults, ... 'FontSize', 11, 'BackgroundColor', [0.9 0.5 0.1], 'ForegroundColor', 'white'); % 创建图像显示区域 ax_original = axes('Parent', fig, 'Position', [0.05, 0.5, 0.4, 0.35]); title(ax_original, '原始图像'); axis(ax_original, 'off'); ax_processed = axes('Parent', fig, 'Position', [0.55, 0.5, 0.4, 0.35]); title(ax_processed, '处理图像'); axis(ax_processed, 'off'); ax_equal = axes('Parent', fig, 'Position', [0.05, 0.1, 0.4, 0.35]); title(ax_equal, '等号检测'); axis(ax_equal, 'off'); % 创建结果展示区域 result_panel = uipanel('Title', '识别结果', 'FontSize', 12, ... 'BackgroundColor', 'white', 'Position', [0.55, 0.1, 0.4, 0.35]); uicontrol('Parent', result_panel, 'Style', 'text', 'String', '识别公式:', ... 'Position', [20, 200, 80, 20], 'FontSize', 11, 'HorizontalAlignment', 'left'); formula_text = uicontrol('Parent', result_panel, 'Style', 'text', 'String', '', ... 'Position', [110, 200, 300, 20], 'FontSize', 11, 'HorizontalAlignment', 'left', ... 'BackgroundColor', 'white'); uicontrol('Parent', result_panel, 'Style', 'text', 'String', '计算结果:', ... 'Position', [20, 170, 80, 20], 'FontSize', 11, 'HorizontalAlignment', 'left'); calc_text = uicontrol('Parent', result_panel, 'Style', 'text', 'String', '', ... 'Position', [110, 170, 300, 20], 'FontSize', 11, 'HorizontalAlignment', 'left', ... 'BackgroundColor', 'white'); uicontrol('Parent', result_panel, 'Style', 'text', 'String', '用户答案:', ... 'Position', [20, 140, 80, 20], 'FontSize', 11, 'HorizontalAlignment', 'left'); answer_text = uicontrol('Parent', result_panel, 'Style', 'text', 'String', '', ... 'Position', [110, 140, 300, 20], 'FontSize', 11, 'HorizontalAlignment', 'left', ... 'BackgroundColor', 'white'); uicontrol('Parent', result_panel, 'Style', 'text', 'String', '验证结果:', ... 'Position', [20, 110, 80, 20], 'FontSize', 11, 'HorizontalAlignment', 'left'); result_text = uicontrol('Parent', result_panel, 'Style', 'text', 'String', '', ... 'Position', [110, 110, 300, 20], 'FontSize', 11, 'HorizontalAlignment', 'left', ... 'BackgroundColor', 'white'); % 等号检测日志 equal_log = uicontrol('Parent', result_panel, 'Style', 'listbox', ... 'String', {}, 'Position', [20, 30, 360, 70], 'FontSize', 10, ... 'BackgroundColor', 'white'); % 存储GUI句柄 handles = struct(); handles.ax_original = ax_original; handles.ax_processed = ax_processed; handles.ax_equal = ax_equal; handles.formula_text = formula_text; handles.calc_text = calc_text; handles.answer_text = answer_text; handles.result_text = result_text; handles.equal_log = equal_log; handles.current_image = []; handles.binary_image = []; handles.region_stats = []; handles.region_bboxes = []; handles.equal_sign_index = []; handles.ocr_results = []; guidata(fig, handles); % ======================== 回调函数 ======================== function uploadImage(~, ~) [filename, pathname] = uigetfile({'*.jpg;*.png;*.bmp', '图像文件 (*.jpg, *.png, *.bmp)'}, ... '选择公式图像'); if isequal(filename, 0) return; end img_path = fullfile(pathname, filename); img = imread(img_path); handles = guidata(fig); handles.current_image = img; % 显示原始图像 axes(handles.ax_original); imshow(img); title('原始图像'); % 预处理图像 gray_img = im2gray(img); % 图像锐化 - 增强边缘 sharpened_img = imsharpen(gray_img, 'Radius', 1.5, 'Amount', 1.2, 'Threshold', 0.1); % 自适应二值化 binary_img = imbinarize(sharpened_img, 'adaptive', 'Sensitivity', 0.7); inverted_img = ~binary_img; handles.binary_image = inverted_img; % 显示处理图像 axes(handles.ax_processed); imshow(inverted_img); title('二值化图像'); % 重置结果 set(handles.formula_text, 'String', ''); set(handles.calc_text, 'String', ''); set(handles.answer_text, 'String', ''); set(handles.result_text, 'String', ''); set(handles.equal_log, 'String', {}); axes(handles.ax_equal); cla; title('等号检测'); guidata(fig, handles); end function recognizeFormula(~, ~) handles = guidata(fig); if isempty(handles.current_image) errordlg('请先上传图像', '错误'); return; end try inverted_img = handles.binary_image; [img_h, img_w] = size(inverted_img); % ================= 第一步:区域分割 ================= axes(handles.ax_processed); imshow(inverted_img); title('区域分割'); drawnow; % 区域分割 cc = bwconncomp(inverted_img); stats = regionprops(cc, 'BoundingBox', 'Area', 'Eccentricity', 'Orientation', 'Solidity'); % 过滤噪点 min_area = max(20, img_h*img_w*0.0005); % 动态最小面积 valid_idx = [stats.Area] > min_area; stats = stats(valid_idx); % 按水平位置排序 bboxes = vertcat(stats.BoundingBox); [~, order] = sort(bboxes(:,1)); bboxes = bboxes(order, :); stats = stats(order); % 存储区域信息 handles.region_stats = stats; handles.region_bboxes = bboxes; % 显示分割结果 imshow(inverted_img); hold on; for i = 1:size(bboxes,1) rectangle('Position', bboxes(i,:), 'EdgeColor', [0.8 0.2 0.2], 'LineWidth', 1); end hold off; title(sprintf('分割出 %d 个区域', length(stats))); drawnow; axes(handles.ax_equal); imshow(inverted_img); title('等号检测过程'); hold on; log_entries = {}; % 从右向左扫描区域(跳过数字区域) eq_candidate_index = []; for i = size(bboxes,1):-1:1 bbox = bboxes(i,:); x = floor(bbox(1)); y = floor(bbox(2)); w = max(floor(bbox(3)), 1); h = max(floor(bbox(4)), 1); % 提取区域图像 region_img = inverted_img(max(1,y):min(img_h,y+h-1), max(1,x):min(img_w,x+w-1)); % 初步识别区域类型 [is_digit, digit_value] = isDigitRegion(region_img); % 显示区域信息 rectangle('Position', bbox, 'EdgeColor', [0.8 0.2 0.2], 'LineWidth', 1); text(bbox(1)+5, bbox(2)-10, sprintf('%d', i), ... 'Color', [0.2 0.2 0.8], 'FontSize', 10, 'FontWeight', 'bold'); if is_digit % 标记数字区域 text(bbox(1)+10, bbox(2)+15, digit_value, ... 'Color', [0 0.5 0], 'FontSize', 12); log_entries{end+1} = sprintf('区域 %d: 数字 %s', i, digit_value); else % 检查是否具有等号特征 [is_equal, confidence] = detectEqualSign(region_img, median(bboxes(:,4))); if is_equal % 标记候选等号区域 rectangle('Position', bbox, 'EdgeColor', [0.2 0.8 0.2], 'LineWidth', 2); text(bbox(1)+10, bbox(2)+15, '等号候选', ... 'Color', [0 0.6 0], 'FontSize', 12, 'FontWeight', 'bold'); log_entries{end+1} = sprintf('区域 %d: 等号候选 (置信度 %.2f)', i, confidence); eq_candidate_index = i; break; % 找到第一个非数字候选区域即停止 else % 标记运算符区域 [is_op, op_type] = detectOperator(region_img); if is_op text(bbox(1)+10, bbox(2)+15, op_type, ... 'Color', [0.8 0 0], 'FontSize', 12, 'FontWeight', 'bold'); log_entries{end+1} = sprintf('区域 %d: 运算符 %s', i, op_type); else text(bbox(1)+10, bbox(2)+15, '?', ... 'Color', [0.5 0.5 0.5], 'FontSize', 12); log_entries{end+1} = sprintf('区域 %d: 未知类型', i); end end end end % 处理等号候选 if isempty(eq_candidate_index) % 如果没有找到候选等号,使用中间位置作为等号 [~, eq_idx] = min(abs(1:size(bboxes,1) - size(bboxes,1)/2)); log_entries{end+1} = sprintf('未找到等号候选,使用区域 %d 作为等号', eq_idx); else eq_idx = eq_candidate_index; log_entries{end+1} = sprintf('确定等号位置: 区域 %d', eq_idx); % 检查是否为双横线结构 bbox = bboxes(eq_idx,:); region_img = inverted_img(max(1,floor(bbox(2))):min(img_h,floor(bbox(2)+bbox(4))-1), ... max(1,floor(bbox(1))):min(img_w,floor(bbox(1)+bbox(3))-1)); [is_double, top_idx, bottom_idx] = checkDoubleLineStructure(region_img); if is_double % 如果是双横线结构,标记为确认等号 rectangle('Position', bbox, 'EdgeColor', [0 0.8 0], 'LineWidth', 3); text(bbox(1)+bbox(3)/2, bbox(2)-15, '=', ... 'Color', [0 0.5 0], 'FontSize', 20, 'FontWeight', 'bold', ... 'HorizontalAlignment', 'center'); log_entries{end+1} = sprintf('区域 %d 确认双横线结构 (上横线:%d, 下横线:%d)', ... eq_idx, top_idx, bottom_idx); else % 如果不是双横线,但位置特征符合,仍标记为等号 rectangle('Position', bbox, 'EdgeColor', [0.9 0.6 0], 'LineWidth', 3); text(bbox(1)+bbox(3)/2, bbox(2)-15, '=', ... 'Color', [0.7 0.4 0], 'FontSize', 20, 'FontWeight', 'bold', ... 'HorizontalAlignment', 'center'); log_entries{end+1} = '单横线结构,但位置特征符合等号'; end end hold off; % 更新日志 set(handles.equal_log, 'String', log_entries); % 存储等号位置 handles.equal_sign_index = eq_idx; % ================= 第三步:字符识别 ================= ocr_results = cell(1, size(bboxes,1)); for i = 1:size(bboxes,1) % 如果是等号区域,直接标记 if ~isempty(equal_sign_index) && i == equal_sign_index ocr_results{i} = '='; continue; end bbox = bboxes(i,:); x = floor(bbox(1)); y = floor(bbox(2)); w = max(floor(bbox(3)), 1); h = max(floor(bbox(4)), 1); % 提取区域图像 region_img = inverted_img(max(1,y):min(img_h,y+h-1), max(1,x):min(img_w,x+w-1)); % 运算符特征检测 [is_operator, operator_type] = detectOperator(region_img); if is_operator ocr_results{i} = operator_type; else % OCR识别数字和字母 char_set = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; ocr_result = ocr(region_img, 'CharacterSet', char_set, 'TextLayout', 'Block'); if ~isempty(ocr_result.Text) char = strtrim(ocr_result.Text); % 数字校正 if strcmp(char, '7') || strcmp(char, '1') char = correctDigit(region_img, char); end ocr_results{i} = char; else ocr_results{i} = '?'; end end end % ================= 第四步:构建表达式 ================= % 分割表达式和答案 expr_str = ''; answer_str = ''; % 如果没有找到等号,使用位置最中间的区域作为等号 if isempty(equal_sign_index) [~, eq_idx] = min(abs(1:size(bboxes,1) - size(bboxes,1)/2)); log_entries{end+1} = sprintf('未找到等号,使用区域 %d 作为等号', eq_idx); set(handles.equal_log, 'String', log_entries); else eq_idx = equal_sign_index; end for i = 1:length(ocr_results) if i < eq_idx expr_str = [expr_str ocr_results{i}]; elseif i > eq_idx answer_str = [answer_str ocr_results{i}]; end end % 特殊字符转换 expr_str = strrep(expr_str, 'x', '*'); expr_str = strrep(expr_str, 'X', '*'); expr_str = strrep(expr_str, '÷', '/'); expr_str = strrep(expr_str, ' ', ''); % 尝试转换为数值 try user_answer = str2double(answer_str); catch user_answer = NaN; end % 安全计算表达式 try correct_result = eval(expr_str); catch % 修正常见OCR错误 expr_str = strrep(expr_str, 'O', '0'); expr_str = strrep(expr_str, 'o', '0'); expr_str = strrep(expr_str, 'l', '1'); expr_str = strrep(expr_str, 'I', '1'); expr_str = strrep(expr_str, 's', '5'); correct_result = eval(expr_str); end % 验证结果 is_correct = abs(user_answer - correct_result) < 1e-6; % 更新结果展示 set(handles.formula_text, 'String', [expr_str '=' answer_str]); set(handles.calc_text, 'String', num2str(correct_result)); set(handles.answer_text, 'String', num2str(user_answer)); if is_correct set(handles.result_text, 'String', '✓ 答案正确', 'ForegroundColor', [0 0.6 0]); else set(handles.result_text, 'String', '✗ 答案错误', 'ForegroundColor', [0.8 0 0]); end % 显示最终识别结果 axes(handles.ax_processed); imshow(inverted_img); hold on; for i = 1:size(bboxes,1) % 等号区域用绿色标注 if ~isempty(equal_sign_index) && i == equal_sign_index rectangle('Position', bboxes(i,:), 'EdgeColor', [0.2 0.8 0.2], 'LineWidth', 2); text(bboxes(i,1)+5, bboxes(i,2)-10, '=', ... 'Color', [0 0.5 0], 'FontSize', 12, 'FontWeight', 'bold'); else % 运算符区域用不同颜色标注 if strcmp(ocr_results{i}, '+') rect_color = [0.8 0.2 0.8]; % 紫色 text_color = [0.6 0 0.6]; % 深紫色 elseif strcmp(ocr_results{i}, '-') rect_color = [0.8 0.5 0.2]; % 橙色 text_color = [0.6 0.3 0]; % 深橙色 else rect_color = [1 0 0]; % 红色 text_color = [0 0 1]; % 蓝色 end rectangle('Position', bboxes(i,:), 'EdgeColor', rect_color, 'LineWidth', 1.5); if ~isempty(ocr_results{i}) text(bboxes(i,1)+5, bboxes(i,2)-10, ocr_results{i}, ... 'Color', text_color, 'FontSize', 10, 'FontWeight', 'bold'); end end end hold off; title('最终识别结果'); % 保存处理后的数据 handles.ocr_results = ocr_results; guidata(fig, handles); catch ME errordlg(sprintf('识别失败: %s', ME.message), '错误'); end end function clearResults(~, ~) handles = guidata(fig); % 清除结果文本 set(handles.formula_text, 'String', ''); set(handles.calc_text, 'String', ''); set(handles.answer_text, 'String', ''); set(handles.result_text, 'String', ''); set(handles.equal_log, 'String', {}); % 清除图像 axes(handles.ax_processed); cla; title('处理图像'); axes(handles.ax_equal); cla; title('等号检测'); % 如果有原始图像,重新显示 if ~isempty(handles.current_image) axes(handles.ax_original); imshow(handles.current_image); title('原始图像'); end end end % ======================== 运算符检测函数 ======================== function [is_operator, operator_type] = detectOperator(region_img) [h, w] = size(region_img); % 计算形状特征 aspect_ratio = w / h; eccentricity = regionprops(region_img, 'Eccentricity').Eccentricity; is_operator = false; operator_type = ''; % 减号检测 if aspect_ratio > 3 && eccentricity > 0.9 is_operator = true; operator_type = '-'; return; end % 加号检测 if aspect_ratio > 1.2 && aspect_ratio < 2.5 % 中心区域分析 center_y = round(h/2); center_x = round(w/2); % 检查水平和垂直线段 horizontal_line = sum(region_img(center_y, :)) > w*0.7; vertical_line = sum(region_img(:, center_x)) > h*0.7; if horizontal_line && vertical_line is_operator = true; operator_type = '+'; return; end end % 乘号检测(斜线) if aspect_ratio > 0.8 && aspect_ratio < 1.2 % 使用Hough变换检测斜线 [H, theta, rho] = hough(region_img, 'Theta', -45:5:45); peaks = houghpeaks(H, 2); if size(peaks,1) >= 2 angles = theta(peaks(:,2)); angle_diff = abs(diff(angles)); % 检查是否接近垂直的斜线对 if abs(angle_diff) > 80 && abs(angle_diff) < 100 is_operator = true; operator_type = '*'; end end end end % ======================== 数字校正函数 ======================== function char = correctDigit(region_img, original_char) [h, w] = size(region_img); % 1的特征:高宽比大,顶部无横线,底部较宽 aspect_ratio = h / w; top_region = region_img(1:round(h*0.3), :); bottom_region = region_img(round(h*0.7):end, :); top_pixels = sum(top_region(:)); bottom_pixels = sum(bottom_region(:)); % 7的特征:顶部有横线,右上角有折角 top_line = sum(region_img(1, :)) > w*0.6; right_top_corner = region_img(1, end) && region_img(2, end); if strcmp(original_char, '7') % 检查是否为1的特征 if aspect_ratio > 3 && top_pixels < numel(top_region)*0.2 && bottom_pixels > numel(bottom_region)*0.5 char = '1'; return; end elseif strcmp(original_char, '1') % 检查是否为7的特征 if aspect_ratio < 2 && top_line && right_top_corner char = '7'; return; end end char = original_char; % 保持原识别结果 end function [is_digit, digit_value] = isDigitRegion(region_img) % 基本特征分析 [h, w] = size(region_img); aspect_ratio = w / h; % 数字通常具有特定的宽高比 is_digit = aspect_ratio >= 0.5 && aspect_ratio <= 1.5; if ~is_digit digit_value = ''; return; end % OCR识别数字 char_set = '0123456789'; ocr_result = ocr(region_img, 'CharacterSet', char_set, 'TextLayout', 'Block'); if ~isempty(ocr_result.Text) digit_value = strtrim(ocr_result.Text); % 常见错误校正 if strcmp(digit_value, '7') % 检查是否为1 if isDigitOne(region_img) digit_value = '1'; end elseif strcmp(digit_value, '1') % 检查是否为7 if isDigitSeven(region_img) digit_value = '7'; end end else % 尝试通过形状判断 if isDigitZero(region_img) digit_value = '0'; elseif isDigitOne(region_img) digit_value = '1'; elseif isDigitTwo(region_img) digit_value = '2'; else digit_value = '?'; is_digit = false; end end end function result = isDigitOne(img) [h, w] = size(img); aspect_ratio = h / w; % 1的特征:高宽比大,顶部像素少 top_region = img(1:round(h*0.3), :); top_pixels = sum(top_region(:)); result = aspect_ratio > 2.5 && top_pixels < numel(top_region)*0.3; end function result = isDigitSeven(img) [h, w] = size(img); % 7的特征:顶部有横线 top_line = sum(img(1, :)) > w*0.6; right_top_corner = img(1, end) && img(2, end); result = top_line && right_top_corner; end function result = isDigitZero(img) [h, w] = size(img); % 0的特征:封闭轮廓 filled_img = imfill(img, 'holes'); hole_area = sum(filled_img(:)) - sum(img(:)); result = hole_area > 0.1 * (w*h); end function result = isDigitTwo(img) [h, w] = size(img); % 2的特征:右上弯曲,左下弯曲 top_right = img(1:round(h*0.3), round(w*0.7):end); bottom_left = img(round(h*0.7):end, 1:round(w*0.3)); result = sum(top_right(:)) > numel(top_right)*0.6 && ... sum(bottom_left(:)) > numel(bottom_left)*0.6; end function [is_double, top_idx, bottom_idx] = checkDoubleLineStructure(region_img) [h, w] = size(region_img); % 水平投影 horizontal_proj = sum(region_img, 2); % 如果没有足够的像素,直接返回 if max(horizontal_proj) == 0 is_double = false; top_idx = 0; bottom_idx = 0; return; end % 归一化投影 horizontal_proj = horizontal_proj / max(horizontal_proj); % 寻找波峰 [peaks, locs] = findpeaks(horizontal_proj, 'MinPeakHeight', 0.3, 'MinPeakDistance', max(1, round(h/4))); % 需要至少两个波峰 if length(peaks) < 2 is_double = false; top_idx = 0; bottom_idx = 0; return; end % 找到两个主要的波峰 [~, sorted_idx] = sort(peaks, 'descend'); top_locs = sort(locs(sorted_idx(1:min(2, length(sorted_idx))))); top_idx = top_locs(1); bottom_idx = top_locs(2); % 检查波峰间距 distance = abs(top_idx - bottom_idx); avg_height = h / 2; % 估计的平均高度 % 合理的间距应该在10%-40%的总高度之间 is_double = distance > 0.1*h && distance < 0.4*h; end function [is_equal, confidence] = detectEqualSign(region_img, median_height) % 输入: % region_img - 二值图像区域 (前景为白色1,背景为黑色0) % median_height - 整个图像中区域高度的中位数 % 输出: % is_equal - 逻辑值,是否为等号 % confidence - 置信度 (0~1) [h, w] = size(region_img); % 1. 初步检查:排除无效区域 if h == 0 || w == 0 || sum(region_img(:)) == 0 is_equal = false; confidence = 0; return; end % 2. 计算基本特征 aspect_ratio = w / h; fill_ratio = sum(region_img(:)) / (h*w); % 填充比例 eccentricity = regionprops(region_img, 'Eccentricity').Eccentricity; % 3. 水平投影分析 horizontal_proj = sum(region_img, 2); % 垂直方向求和 horizontal_proj = horizontal_proj / max(horizontal_proj); % 归一化 % 4. 寻找水平线(波峰) min_peak_height = 0.3; % 最小波峰高度阈值 min_peak_distance = max(1, round(h/4)); % 最小波峰间距 % 查找主要波峰 [peaks, locs] = findpeaks(horizontal_proj, ... 'MinPeakHeight', min_peak_height, ... 'MinPeakDistance', min_peak_distance); num_peaks = length(peaks); % 5. 等号特征分析 is_equal = false; confidence = 0; % 特征1:双横线结构 (等号) if num_peaks >= 2 % 获取两个最强的波峰 [~, sorted_idx] = sort(peaks, 'descend'); top_locs = sort(locs(sorted_idx(1:min(2, num_peaks)))); % 计算波峰间距离 peak_distance = abs(top_locs(1) - top_locs(2)); % 特征1.1:合理的垂直间距 (0.5-2倍中值高度) is_reasonable_distance = peak_distance > 0.5*median_height && ... peak_distance < 2*median_height; % 特征1.2:两条线长度相似 line1_length = sum(region_img(top_locs(1), :) > 0); line2_length = sum(region_img(top_locs(2), :) > 0); length_ratio = min(line1_length, line2_length) / max(line1_length, line2_length); % 特征1.3:水平对齐 line1_pos = find(region_img(top_locs(1), :)); line2_pos = find(region_img(top_locs(2), :)); % 计算水平重叠比例 overlap = numel(intersect(line1_pos, line2_pos)) / min(numel(line1_pos), numel(line2_pos)); % 置信度计算 dist_conf = min(1, max(0, 1 - abs(peak_distance - median_height)/(0.5*median_height))); len_conf = length_ratio; align_conf = overlap; confidence = 0.4*dist_conf + 0.3*len_conf + 0.3*align_conf; % 满足核心条件:至少两条线+合理距离 if num_peaks >= 2 && is_reasonable_distance && confidence > 0.5 is_equal = true; end end % 特征2:单横线结构 (减号) if num_peaks == 1 && ~is_equal % 检查是否为长横线 line_length = sum(region_img(locs(1), :) > 0); is_long_line = line_length > 0.7*w; % 检查高度一致性 (单行) [~, max_idx] = max(horizontal_proj); line_height = sum(region_img(max(1, max_idx-1):min(h, max_idx+1), :) > 0); is_single_line = line_height < 3; % 不超过3行像素 % 减号特征 is_dash = aspect_ratio > 3 && eccentricity > 0.9 && is_long_line && is_single_line; % 置信度计算 if is_dash confidence = 0.8; % 高置信度减号 else confidence = 0.3; % 低置信度未知 end end % 6. 附加验证:高宽比和填充比例 if is_equal % 等号应有较大的高宽比(横向延伸) aspect_conf = min(1, aspect_ratio/5); % 等号填充比例应较低(两条线之间有空隙) fill_conf = max(0, 1 - 2*fill_ratio); confidence = 0.7*confidence + 0.2*aspect_conf + 0.1*fill_conf; end % 7. 最终决策阈值 if confidence < 0.6 is_equal = false; end end 在这个代码下,把等号的识别逻辑更改为,如果相邻的两个识别区域的水平位置相差不大(即认为上下分布),或者几乎一样,则判断为等号,并且改为从左往右识别,等号继承靠前的那一个序号,后面的区域序号依次往前提就可以 给出完整代码
06-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值