.NET映射设计(Model与UIControl之间的模型关系)

本文探讨了实体在分层架构项目中的重要性,特别是在数据传递和界面交互中的作用。通过实体代替DataTable,可以避免因数据变化引起的维护难题。同时,文章介绍了如何通过实体与界面控件的关联,实现数据的高效赋值和验证,从而提升开发效率。

1:实体的使用范围和重要性

这篇文章讨论的概念其实比较简单的,但是在实际的项目应用中非常的重要和普遍。

我们的项目一般都是采用分层架构,有的三层有的可能五层或者其他的方式组织系统的架构,但是始终要将系统的架构按照模式设计,我们才能重用和接受维护。

随着ORM的流行和大面积的使用,行业内出现各种各样的ORM框架,有自己开发的有大型的软件公司开发的,基本在使用上都遵循了以实体为中心的概念,也就是围绕关系数据库中的表为操作对象。复杂的可能还包括连接查询多表操作等等。[王清培版权所有,转载请给出署名]

按照分层架构设计中的指导约束,我们应该尽可能的在系统模块之间采用Entity进行数据的传递。当然世事无绝对特殊性的项目可能没有这么简单,我们只讨论传统的信息系统项目。

我们看一下分层架构的数据传递。

图1:

这个图可能画的有点简单了,但是能说明大体的概念。

实体在层与层之间传递保证了很多因为Data Table数据传递带来的隐患。典型的就是Rows索引和Columns索引,在变动了DAL层的查询代码后就会将危险传递到BLL层、UI层。这样在给系统后期的维护提高了代价。

如果我们使用Entity传递数据就不会存在这些问题或者说问题变的轻了很多,当然这个需要项目开发过程中的编码约束了。程序员可能会习惯性的使用Data Table。

2:实体与界面的关系

大部分的系统都是需要将数据展现在界面上,然后在从界面上安全的搜集起来放到实体中进行增、删、改、查操作。这样的工作可能都是普通程序员在写或者是实习程序员在写,他们并没有意识到这样是重复的劳动。但是作为我们过来的程序员其实细心点的都会想到这之间是有联系的,可以适当的封装将大大减少开发效率。

我们看一下实体是如何赋值的:

图2:

这是我找的一个简单的代码段,就是将界面上的控件中的值赋到实体中去,然后在进行BLL的业务逻辑操作。

那么我上面的属性还算是少的,有的可能几十个属性都需要从界面上取值,并且是通过验证后的数据值。所以在开发上有两个地方确实很耗时,一个是数据的有效性验证,一个是数据的赋值。当然数据的赋值还有反向的,将实体中的值赋到控件中去,也很浪费时间。[王清培版权所有,转载请给出署名]

3:利用Model与UIControl之间的模型扩展基础框架

从上面所讲的问题,我们隐隐约约似乎明白点东西了。

我们先来看简单的封装。

1首要的问题就是将控件进行二次封装,将输入控件与验证控件进行组合达到自动化验证数据的有效性,这样程序员在开发的时候能减少很多验证的代码,不用在去找一些正则表达式和使用各种各样的验证控件。

2下面就是将控件与实体属性之间建立关联,这个关联有两个动作,一个是实体赋值到控件上,一个是控件赋值到实体中。我们先来说控件赋值到实体吧,控件赋值到实体,有一个比较重要的问题是数据类型,如何将控件中的值赋到属性中去,这个就跟实体的构造有直接关系了,实体的构造大部分是围绕着ORM的要求来的,那么如果你的ORM是采用比较传统的反射来对实体的数据进行赋值的话,那么这个实体就是孤立的,也只能使用反射来进行赋值。

其实我的想法是提高抽象层次将实体进行归类将实体的赋值拖入运行时,这样的好处很明显。(可以参见我的 “利用抽象、多态实现无反射的绿色环保ORM框架”一文)从ORM角度讲提高了性能,从大一点的角度讲可以借鉴领域驱动设计中的Module划分和大比例结构,将实体进行抽象后会变的很强大,如果能做到分层架构中合理的表现领域模型那就是绝对的厉害。

其实这里的数据类型就要靠程序员自己去判断了,是整形的就不能将控件的验证规则设成其他的。这样我们就可以根据实体的数据类型将控件的值进行安全转换(使用as)。

那么实体赋值到控件其实差不多的,根据控件的某种标识找到具体的属性然后设置就行了。[王清培版权所有,转载请给出署名]

我们看一下我写的一个小示例:

图3:

实体图

这个实体属性很多,由于时间关系我只使用两个属性做演示。

界面图

代码转换图

结:经过这样的封装我们确实减少了很多重复劳动,我也看到了这个效果是很明显的。这样一来就很平滑的将实体封装,送往BLL,然后再接受实体赋值到控件上。虽然简单,但是作用很大,可以适当的细化将数据表格控件进行封装,我想那个效果更明显。

上面是我在做基础库时的一点小小的经验,希望大家用的着。[王清培版权所有,转载请给出署名]

 

转载于:https://www.cnblogs.com/wangiqngpei557/archive/2012/05/24/2516885.html

classdef EmotionRecognitionSystem < handle % 面部表情识别系统主类 % 支持自定义数据集训练和表情识别 properties fig % 主窗口句柄 net % 表情识别模型 axImg % 图像显示区域 txtResult % 结果显示文本框 cam % 摄像头对象 videoPlayer % 视频播放器 isCapturing = false; % 是否正在捕获视频 end methods function obj = EmotionRecognitionSystem() % 构造函数 - 创建GUI并加载模型 % 创建主窗口 obj.fig = figure('Name', '面部表情识别系统', ... 'Position', [300 200 900 550], ... 'NumberTitle', 'off', ... 'MenuBar', 'none', ... 'CloseRequestFcn', @obj.closeApp); % 尝试加载现有模型 try load('customEmotionNet.mat', 'net'); obj.net = net; disp('自定义模型加载成功'); catch obj.net = []; end % 创建UI控件 uicontrol('Style', 'pushbutton', ... 'Position', [30 480 120 40], ... 'String', '选择图片', ... 'Callback', @obj.loadImage, ... 'FontSize', 11); uicontrol('Style', 'pushbutton', ... 'Position', [170 480 120 40], ... 'String', '摄像头捕获', ... 'Callback', @obj.captureFromCam, ... 'FontSize', 11); uicontrol('Style', 'pushbutton', ... 'Position', [310 480 120 40], ... 'String', '实时识别', ... 'Callback', @obj.realTimeRecognition, ... 'FontSize', 11); uicontrol('Style', 'pushbutton', ... 'Position', [450 480 120 40], ... 'String', '训练模型', ... 'Callback', @obj.trainModel, ... 'FontSize', 11); uicontrol('Style', 'pushbutton', ... 'Position', [590 480 120 40], ... 'String', '帮助', ... 'Callback', @obj.showHelp, ... 'FontSize', 11); % 创建图像显示区域 obj.axImg = axes('Parent', obj.fig, ... 'Position', [0.05 0.1 0.5 0.7], ... 'Box', 'on'); axis(obj.axImg, 'image'); title(obj.axImg, '输入图像'); % 创建结果显示区域 uicontrol('Style', 'text', ... 'Position', [600 400 250 40], ... 'String', '识别结果:', ... 'FontSize', 14, ... 'FontWeight', 'bold', ... 'BackgroundColor', [0.9 0.9 0.9]); obj.txtResult = uicontrol('Style', 'text', ... 'Position', [600 300 250 90], ... 'String', '等待识别...', ... 'FontSize', 16, ... 'FontWeight', 'bold', ... 'ForegroundColor', [0 0.5 0], ... 'BackgroundColor', [0.95 0.95 0.95], ... 'HorizontalAlignment', 'center'); % 置信度指示器 uicontrol('Style', 'text', ... 'Position', [600 200 250 30], ... 'String', '置信度:', ... 'FontSize', 12, ... 'BackgroundColor', [0.9 0.9 0.9]); % 表情标签 emotions = {'平静', '大笑', '微笑', '哭泣', '悲伤'}; for i = 1:length(emotions) uicontrol('Style', 'text', ... 'Position', [600 170-(i-1)*30 100 25], ... 'String', emotions{i}, ... 'FontSize', 11, ... 'HorizontalAlignment', 'left', ... 'BackgroundColor', [0.95 0.95 0.95]); end end function loadImage(obj, ~, ~) % 从文件选择图像 [file, path] = uigetfile({'*.jpg;*.png;*.bmp;*.png', '图像文件'}); if isequal(file, 0) return; end imgPath = fullfile(path, file); obj.processImage(imread(imgPath)); end function captureFromCam(obj, ~, ~) % 从摄像头捕获图像 if isempty(webcamlist) errordlg('未检测到摄像头', '硬件错误'); return; end try obj.cam = webcam; preview(obj.cam); uicontrol('Style', 'text', ... 'Position', [300 10 300 30], ... 'String', '正在捕获...3秒后自动拍照', ... 'FontSize', 12, ... 'ForegroundColor', 'r'); pause(3); img = snapshot(obj.cam); clear obj.cam; obj.processImage(img); delete(findobj(obj.fig, 'Type', 'uicontrol', 'Position', [300 10 300 30])); catch ME errordlg(['摄像头错误: ' ME.message], '硬件错误'); if ~isempty(obj.cam) clear obj.cam; end end end function realTimeRecognition(obj, ~, ~) % 实时表情识别 if obj.isCapturing obj.isCapturing = false; return; end if isempty(webcamlist) errordlg('未检测到摄像头', '硬件错误'); return; end if isempty(obj.net) warndlg('请先训练模型', '模型缺失'); return; end obj.isCapturing = true; obj.cam = webcam; obj.videoPlayer = vision.DeployableVideoPlayer; % 创建停止按钮 stopBtn = uicontrol('Style', 'pushbutton', ... 'Position', [310 480 120 40], ... 'String', '停止识别', ... 'Callback', @obj.stopRealTime, ... 'FontSize', 11, ... 'BackgroundColor', [1 0.6 0.6]); % 实时识别循环 while obj.isCapturing && ishandle(obj.fig) img = snapshot(obj.cam); [emotion, confidence, faceImg] = obj.recognizeEmotion(img); % 在图像上标注结果 if ~isempty(faceImg) bbox = faceImg.bbox; label = sprintf('%s (%.1f%%)', emotion, confidence*100); img = insertObjectAnnotation(img, 'rectangle', bbox, ... label, 'Color', 'green', 'FontSize', 18); end step(obj.videoPlayer, img); end % 清理 release(obj.videoPlayer); clear obj.cam; delete(stopBtn); end function stopRealTime(obj, ~, ~) % 停止实时识别 obj.isCapturing = false; end function processImage(obj, img) % 处理单张图像 if isempty(obj.net) warndlg('请先训练模型', '模型缺失'); return; end axes(obj.axImg); imshow(img); title('输入图像'); % 表情识别 [emotion, confidence, faceImg] = obj.recognizeEmotion(img); % 显示结果 resultStr = sprintf('表情: %s\n置信度: %.2f%%', emotion, confidence*100); set(obj.txtResult, 'String', resultStr); % 绘制检测框 if ~isempty(faceImg) hold on; rectangle('Position', faceImg.bbox, ... 'EdgeColor', 'g', 'LineWidth', 2); text(faceImg.bbox(1), faceImg.bbox(2)-20, ... [emotion ' (' num2str(round(confidence*100)) '%)'], ... 'Color', 'g', 'FontSize', 14, 'FontWeight', 'bold'); hold off; end end function [emotion, confidence, faceImg] = recognizeEmotion(obj, img) % 表情识别函数 faceImg = []; % 人脸检测 faceDetector = vision.CascadeObjectDetector(); bbox = step(faceDetector, img); if isempty(bbox) emotion = '未检测到人脸'; confidence = 0; return; end % 选择最大的人脸区域 [~, idx] = max(bbox(:,3).*bbox(:,4)); mainBbox = bbox(idx,:); % 裁剪人脸区域 faceImg.img = imcrop(img, mainBbox); faceImg.bbox = mainBbox; % 预处理 - 保持RGB三通道 resizedImg = imresize(faceImg.img, [48 48]); % 模型输入尺寸 normalizedImg = im2single(resizedImg); % 归一化 % 表情分类 [pred, scores] = classify(obj.net, normalizedImg); confidence = max(scores); % 映射到表情标签 emotionMap = containers.Map(... {'neutral', 'happy', 'smile', 'cry', 'sad'}, ... {'平静', '大笑', '微笑', '哭泣', '悲伤'}); if isKey(emotionMap, char(pred)) emotion = emotionMap(char(pred)); else emotion = '未知表情'; end end function trainModel(obj, ~, ~) % 训练自定义模型 answer = questdlg('训练模型需要较长时间,是否继续?', ... '模型训练', '是', '否', '是'); if ~strcmp(answer, '是') return; end % 创建训练进度窗口 trainFig = figure('Name', '模型训练', ... 'Position', [400 300 400 200], ... 'NumberTitle', 'off', ... 'MenuBar', 'none'); uicontrol('Style', 'text', ... 'Position', [50 150 300 30], ... 'String', '正在训练模型,请稍候...', ... 'FontSize', 12); progressBar = uicontrol('Style', 'text', ... 'Position', [50 100 300 20], ... 'String', '', ... 'BackgroundColor', [0.8 0.8 1]); % 在单独的函数中训练模型 try obj.net = obj.trainCustomModel(progressBar); save('customEmotionNet.mat', 'net'); msgbox('模型训练完成并已保存!', '训练成功'); catch ME errordlg(['训练错误: ' ME.message], '训练失败'); end close(trainFig); end function net = trainCustomModel(obj, progressBar) % 自定义模型训练函数 datasetPath = uigetdir(pwd, '选择表情数据集目录'); if datasetPath == 0 error('未选择数据集'); end imds = imageDatastore(datasetPath, ... 'IncludeSubfolders', true, ... 'LabelSource', 'foldernames'); % 检查类别数量 classes = categories(imds.Labels); if numel(classes) ~= 5 error('数据集必须包含5个类别: neutral, happy, smile, cry, sad'); end % 数据集分割 [trainImgs, valImgs] = splitEachLabel(imds, 0.7, 'randomized'); % 更新进度 set(progressBar, 'Position', [50 100 100 20], 'String', '数据加载完成'); pause(0.5); % 数据增强 augmenter = imageDataAugmenter(... 'RandXReflection', true, ... 'RandRotation', [-15 15], ... 'RandXScale', [0.8 1.2], ... 'RandYScale', [0.8 1.2]); % 使用RGB图像 (48x48x3) augTrainImgs = augmentedImageDatastore([48 48], trainImgs, ... 'DataAugmentation', augmenter, ... 'OutputSizeMode', 'resize'); augValImgs = augmentedImageDatastore([48 48], valImgs, ... 'OutputSizeMode', 'resize'); % 更新进度 set(progressBar, 'Position', [50 100 150 20], 'String', '数据预处理完成'); pause(0.5); % 构建自定义CNN模型 (支持RGB输入) layers = [ % 修改输入层为48x48x3以支持RGB图像 imageInputLayer([48 48 3], 'Name', 'input') convolution2dLayer(5, 32, 'Padding', 'same', 'Name', 'conv1') batchNormalizationLayer('Name', 'bn1') reluLayer('Name', 'relu1') maxPooling2dLayer(2, 'Stride', 2, 'Name', 'pool1') convolution2dLayer(3, 64, 'Padding', 'same', 'Name', 'conv2') batchNormalizationLayer('Name', 'bn2') reluLayer('Name', 'relu2') maxPooling2dLayer(2, 'Stride', 2, 'Name', 'pool2') convolution2dLayer(3, 128, 'Padding', 'same', 'Name', 'conv3') batchNormalizationLayer('Name', 'bn3') reluLayer('Name', 'relu3') maxPooling2dLayer(2, 'Stride', 2, 'Name', 'pool3') fullyConnectedLayer(256, 'Name', 'fc1') reluLayer('Name', 'relu4') dropoutLayer(0.5, 'Name', 'dropout1') fullyConnectedLayer(5, 'Name', 'fc2') % 5个输出类别 softmaxLayer('Name', 'softmax') classificationLayer('Name', 'classoutput') ]; % 训练选项 options = trainingOptions('adam', ... 'InitialLearnRate', 0.001, ... 'LearnRateSchedule', 'piecewise', ... 'LearnRateDropFactor', 0.5, ... 'LearnRateDropPeriod', 5, ... 'MaxEpochs', 20, ... 'MiniBatchSize', 64, ... 'Shuffle', 'every-epoch', ... 'ValidationData', augValImgs, ... 'ValidationFrequency', 50, ... 'Verbose', true, ... 'Plots', 'none', ... 'OutputFcn', @(info)obj.trainingProgress(info, progressBar)); % 更新进度 set(progressBar, 'Position', [50 100 200 20], 'String', '开始训练模型...'); drawnow; % 训练模型 net = trainNetwork(augTrainImgs, layers, options); end function trainingProgress(obj, info, progressBar) % 训练进度回调函数 if strcmp(info.State, 'iteration') % 计算整个训练过程的进度 progress = (info.Epoch - 1 + info.Iteration/info.NumIterations) / info.NumEpochs; set(progressBar, 'Position', [50 100 round(300*progress) 20], ... 'String', sprintf('训练进度: %.1f%%', progress*100)); drawnow; end end function showHelp(obj, ~, ~) % 显示帮助信息 helpText = { '面部表情识别系统使用指南' '1. 选择图片: 从文件系统加载图像进行识别' '2. 摄像头捕获: 使用摄像头拍摄照片进行识别' '3. 实时识别: 开启摄像头进行实时表情识别' '4. 训练模型: 使用自定义数据集训练新模型' '' '使用说明:' '- 首次使用需点击"训练模型"创建新模型' '- 训练完成后模型将保存为customEmotionNet.mat' '- 支持识别表情: 平静、大笑、微笑、哭泣、悲伤' '' '数据集要求:' '- 创建文件夹结构:' ' dataset/neutral' ' dataset/happy' ' dataset/smile' ' dataset/cry' ' dataset/sad' '- 每个子文件夹包含对应表情的图片' '- 图片格式支持JPG/PNG/BMP' '- 建议每个类别至少100张图片' '- 图像尺寸建议为48x48像素(系统会自动调整)' }; helpdlg(helpText, '系统帮助'); end function closeApp(obj, ~, ~) % 关闭应用程序 if obj.isCapturing obj.isCapturing = false; pause(0.5); end if ~isempty(obj.cam) clear obj.cam; end if ishandle(obj.fig) delete(obj.fig); end end end end保持训练图像输入层一致matlab完整代码
最新发布
06-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值