敏捷灰度--select 代替 update、delete的灰度策略

本文介绍了一种灰度发布的策略,并通过实例演示了如何在微服务系统中实施此策略以减少因代码更新导致的问题。

        本文讲述的是一种灰度策略,在讲灰度策略之前,先说一下线上数据库的delete,update操作。

程序员删除线上数据时运行以下示例语句:

        delete from table where id=xxx and name=’xxx’;

        如果忘记加where条件或者where条件少了一个and或者or,将会删除很多数据。

        稍微有经验的程序员,会分两步操作:

        1. select * from table where id=xxx andname=’xxx’; 观察满足删除条件的数据情况

        2.用“delete”替换第一点语句的“select*”

        第一点可以理解为“灰度发布观察”,第二点可以理解为“全量发布”。

        那么接下来讲的就是在微服务中实现上面思路的灰度发布。


        举个例子:

        
       某个微服务系统中,要对A表添加一个uid字段,插入数据时填写上uid数据,update数据时where再加上“uid=xxx”的条件。系统的服务杂性,无法预料到插入的uid和update的uid是否一致,如果存在大量不一致,将导致大量数据无法被update更新,引起大面积报障。

        
       该改造要上线,就是要先摸清不一致的情况有多少。

       按以下步骤上线:

       1.      线上数据表增加uid字段

       2.      上线程序,上线的程序有insert uid的功能,update逻辑先不加上uid=xxx的过滤条件。再加多几行程序,程序执行”select * from table where condition=yyy and uid=xxx”,当返回的结果集为0时,打印日志并且上报到统计系统中,通过日志或者统计系统监控将要update的影响记录条数。

       3.      第二点灰度观察一天,正常无误后把”select * from table where condition=yyy and uid=xxx”的执行语句去掉,再到原来的update语句加上uid=xxx,再上线灰度一台服务器

       4.      第三点的一台服务器灰度一天无误后,再继续灰度其他机器。

 

 

        
<think>我们需要在原有代码基础上增加一个功能:在图像上绘制一个可移动、可调整大小的圆圈,并计算圆圈内所有像素点的灰度值之和(或平均值等,根据需求)。这里我们实现一个可拖拽和调整大小的圆形ROI(Region of Interest),并实时计算圆圈内像素的灰度值之和。 修改思路: 1. 添加一个按钮用于启用圆圈绘制模式。 2. 在图像上绘制一个圆形ROI(使用imellipse或自定义)。 3. 允许用户移动和调整圆圈大小(通过拖拽)。 4. 当圆圈移动或调整时,实时计算圆圈内像素的灰度值之和,并显示。 由于MATLAB的ROI对象(如imellipse)有回调函数,我们可以利用这一点。但是,为了保持代码的简洁和兼容性,我们使用imellipse,因为它提供了交互式的移动和调整大小的功能。 注意:imellipse需要Image Processing Toolbox。 步骤: 1. 在界面上添加一个按钮“添加圆圈”。 2. 点击该按钮后,在当前图像上创建一个可拖拽和调整大小的圆圈。 3. 为圆圈设置位置改变的回调函数,当圆圈改变时,计算圆圈内所有像素的灰度值之和(注意:圆圈内的像素可能不是整数坐标,我们需要创建一个二值掩码,然后求和)。 4. 在界面上显示圆圈内灰度值之和。 我们将修改原有的程序,增加以下功能: - 一个“添加圆圈”按钮 - 存储当前圆圈对象的变量 - 当圆圈位置或大小改变时更新计算结果 由于同一个图像上可能点击多个位置,我们每次只允许一个圆圈存在(新的圆圈会替代旧的)。 代码修改如下: 注意:由于圆圈可能超出图像边界,我们需要在计算时处理边界。 我们将添加一个全局变量(在data结构体中)来存储当前的ROI对象,并添加一个显示圆圈内灰度值和的文本框。 修改后的代码:</think>我将修改之前的MATLAB代码,添加一个可调整大小和移动的圆形ROI(感兴趣区域),用于计算区域内所有像素的灰度值之和。以下是实现该功能的完整代码: ```matlab function image_gray_value_viewer() % 创建主窗口 fig = figure('Name', '图像灰度值查看器', 'NumberTitle', 'off', ... 'Position', [200, 200, 900, 650], 'MenuBar', 'none'); % 创建图像显示区域 ax = axes('Parent', fig, 'Position', [0.1, 0.25, 0.8, 0.7]); axis off % 创建文件选择按钮 uicontrol('Style', 'pushbutton', 'String', '选择图片', ... 'Position', [20, 50, 100, 30], ... 'Callback', @select_image); % 创建灰度值显示文本框 txt = uicontrol('Style', 'text', 'String', '灰度值: ', ... 'Position', [150, 50, 300, 30], ... 'HorizontalAlignment', 'left', ... 'FontSize', 11); % 创建ROI区域灰度值显示文本框 roi_txt = uicontrol('Style', 'text', 'String', 'ROI区域灰度总和: ', ... 'Position', [150, 20, 300, 30], ... 'HorizontalAlignment', 'left', ... 'FontSize', 11); % 创建文件列表框 file_list = uicontrol('Style', 'listbox', 'String', {}, ... 'Position', [480, 50, 300, 30], ... 'Callback', @listbox_selected); % 创建圆圈大小滑块 uicontrol('Style', 'text', 'String', '圆圈半径:', ... 'Position', [20, 100, 80, 20], ... 'HorizontalAlignment', 'left'); radius_slider = uicontrol('Style', 'slider', ... 'Position', [100, 100, 150, 20], ... 'Min', 5, 'Max', 100, 'Value', 20, ... 'Callback', @update_roi); % 创建圆圈位置标签 uicontrol('Style', 'text', 'String', '圆圈位置:', ... 'Position', [20, 130, 80, 20], ... 'HorizontalAlignment', 'left'); pos_txt = uicontrol('Style', 'text', 'String', 'X:0, Y:0', ... 'Position', [100, 130, 150, 20], ... 'HorizontalAlignment', 'left'); % 存储数据的结构体 data = struct('current_image', [], 'image_path', '', ... 'file_names', {}, 'folder_path', '', ... 'roi_center', [0, 0], 'roi_radius', 20, ... 'roi_handle', []); guidata(fig, data); % 选择图片回调函数 function select_image(~, ~) [file, path] = uigetfile({'*.jpg;*.jpeg;*.png;*.bmp;*.tif', ... '图片文件 (*.jpg,*.jpeg,*.png,*.bmp,*.tif)'}, ... '选择图片'); if isequal(file, 0) return; % 用户取消选择 end data = guidata(fig); data.image_path = fullfile(path, file); data.folder_path = path; % 获取文件夹中所有图片文件 img_files = dir(fullfile(path, '*.jpg')); img_files = [img_files; dir(fullfile(path, '*.jpeg'))]; img_files = [img_files; dir(fullfile(path, '*.png'))]; img_files = [img_files; dir(fullfile(path, '*.bmp'))]; img_files = [img_files; dir(fullfile(path, '*.tif'))]; data.file_names = {img_files.name}; set(file_list, 'String', data.file_names); set(file_list, 'Value', find(strcmp(data.file_names, file))); % 加载并显示图像 load_and_display_image(data.image_path); guidata(fig, data); end % 列表框选择回调函数 function listbox_selected(~, ~) data = guidata(fig); idx = get(file_list, 'Value'); if ~isempty(idx) && ~isempty(data.file_names) selected_file = data.file_names{idx}; data.image_path = fullfile(data.folder_path, selected_file); load_and_display_image(data.image_path); guidata(fig, data); end end % 加载并显示图像 function load_and_display_image(img_path) try img = imread(img_path); % 转换为灰度图像(如果是彩色图像) if size(img, 3) == 3 img = rgb2gray(img); elseif size(img, 3) == 4 % 处理带透明通道的PNG img = rgb2gray(img(:,:,1:3)); end % 存储当前图像数据 data = guidata(fig); data.current_image = img; % 设置初始ROI位置(图像中心) [h, w] = size(img); data.roi_center = [round(w/2), round(h/2)]; set(pos_txt, 'String', sprintf('X:%d, Y:%d', data.roi_center(1), data.roi_center(2))); % 显示图像 imshow(img, 'Parent', ax); title(ax, ['当前图像: ' strrep(img_path, '\', '\\')], ... 'Interpreter', 'none'); % 创建或更新ROI圆圈 create_or_update_roi(); % 设置图像点击回调 set(get(ax, 'Children'), 'ButtonDownFcn', @image_click); % 计算并显示ROI区域灰度值总和 calculate_roi_sum(); guidata(fig, data); catch ME errordlg(['无法加载图像: ' ME.message], '图像错误'); end end % 创建或更新ROI圆圈 function create_or_update_roi() data = guidata(fig); % 删除旧的ROI(如果存在) if ~isempty(data.roi_handle) && ishandle(data.roi_handle) delete(data.roi_handle); end % 创建新的ROI圆圈 hold(ax, 'on'); theta = linspace(0, 2*pi, 100); x = data.roi_center(1) + data.roi_radius * cos(theta); y = data.roi_center(2) + data.roi_radius * sin(theta); data.roi_handle = plot(ax, x, y, 'r-', 'LineWidth', 2); hold(ax, 'off'); % 添加拖拽功能 set(data.roi_handle, 'ButtonDownFcn', @start_roi_drag); guidata(fig, data); end % 开始拖拽ROI function start_roi_drag(src, ~) data = guidata(fig); set(fig, 'WindowButtonMotionFcn', @dragging_roi); set(fig, 'WindowButtonUpFcn', @stop_roi_drag); % 存储初始点击位置 current_point = get(ax, 'CurrentPoint'); data.drag_start_point = [current_point(1,1), current_point(1,2)]; data.drag_start_center = data.roi_center; guidata(fig, data); end % 拖拽ROI中 function dragging_roi(~, ~) data = guidata(fig); current_point = get(ax, 'CurrentPoint'); new_x = current_point(1,1); new_y = current_point(1,2); % 计算移动距离 dx = new_x - data.drag_start_point(1); dy = new_y - data.drag_start_point(2); % 更新ROI中心位置 data.roi_center = data.drag_start_center + [dx, dy]; % 更新位置显示 set(pos_txt, 'String', sprintf('X:%d, Y:%d', round(data.roi_center(1)), round(data.roi_center(2)))); % 更新ROI显示 create_or_update_roi(); % 计算并显示ROI区域灰度值总和 calculate_roi_sum(); guidata(fig, data); end % 停止拖拽ROI function stop_roi_drag(~, ~) set(fig, 'WindowButtonMotionFcn', ''); set(fig, 'WindowButtonUpFcn', ''); end % 更新ROI大小 function update_roi(~, ~) data = guidata(fig); data.roi_radius = get(radius_slider, 'Value'); create_or_update_roi(); calculate_roi_sum(); guidata(fig, data); end % 计算ROI区域灰度值总和 function calculate_roi_sum() data = guidata(fig); if isempty(data.current_image) return; end img = data.current_image; [h, w] = size(img); center_x = round(data.roi_center(1)); center_y = round(data.roi_center(2)); radius = round(data.roi_radius); % 创建网格坐标 [X, Y] = meshgrid(1:w, 1:h); % 计算每个点到圆心的距离 dist_from_center = sqrt((X - center_x).^2 + (Y - center_y).^2); % 创建ROI掩码(圆形区域) roi_mask = dist_from_center <= radius; % 计算ROI区域内的灰度值总和 roi_sum = sum(img(roi_mask), 'all'); % 计算ROI区域内的像素数量 roi_pixels = sum(roi_mask, 'all'); % 更新显示 set(roi_txt, 'String', sprintf('ROI区域灰度总和: %d (像素数: %d)', roi_sum, roi_pixels)); end % 图像点击回调函数 function image_click(~, event) data = guidata(fig); if isempty(data.current_image) return; end % 获取点击位置坐标 click_point = get(ax, 'CurrentPoint'); x = round(click_point(1,1)); y = round(click_point(1,2)); % 获取图像尺寸 [h, w] = size(data.current_image); % 检查坐标是否在图像范围内 if x >= 1 && x <= w && y >= 1 && y <= h % 获取灰度值 gray_val = data.current_image(y, x); % 更新显示 set(txt, 'String', sprintf('灰度值: %d (位置: [%d, %d])', gray_val, x, y)); % 在图像上标记点 hold(ax, 'on'); plot(ax, x, y, 'r+', 'MarkerSize', 10, 'LineWidth', 1.5); hold(ax, 'off'); else set(txt, 'String', '点击位置超出图像范围'); end end end ``` ### 新增功能说明: 1. **可移动的圆形ROI**: - 在图像中心添加了一个红色圆圈 - 可以通过拖拽圆圈来移动位置 - 实时显示圆圈中心坐标 2. **可调整大小的圆圈**: - 添加了滑块控制圆圈半径(5-100像素) - 滑块值改变时自动更新圆圈大小 3. **ROI区域灰度值计算**: - 计算圆圈内所有像素的灰度值总和 - 显示圆圈内包含的像素数量 - 实时更新计算结果(移动或调整大小时) 4. **界面优化**: - 增加了ROI控制区域 - 添加了位置和半径显示 - 优化了布局和空间利用 ### 使用说明: 1. **基本操作**: - 点击"选择图片"按钮加载图像 - 点击图像任意位置显示该点灰度- 通过列表框切换不同图片 2. **ROI操作**: - 拖拽圆圈可以移动位置 - 使用滑块调整圆圈半径 - ROI区域灰度值总和显示在底部 3. **交互功能**: - 位置文本显示圆圈中心坐标 - 滑块显示当前圆圈半径 - 圆圈移动或调整大小时自动更新计算结果 ### 技术实现细节: 1. **ROI创建**: - 使用参数方程绘制圆形:`x = center_x + radius * cos(theta)` - 设置100个点确保圆滑度 2. **拖拽功能**: - `ButtonDownFcn`捕获拖拽开始事件 - `WindowButtonMotionFcn`处理拖拽过程 - `WindowButtonUpFcn`结束拖拽 3. **灰度值计算**: - 创建网格坐标计算点到圆心距离 - 使用逻辑掩码选择圆形区域 - `sum(img(roi_mask), 'all')`计算总和 4. **边界处理**: - 当圆圈超出图像边界时自动处理 - 只计算图像范围内的像素
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值