UIButton将title和image放置在任意位置上

本文介绍了如何使用UIButton的contentEdgeInsets属性,结合UIImageView和UILabel的相对位置,来实现title和image在按钮上的任意布局。通过调整EdgeInsets,可以实现图片与文字的间距、左右或上下对齐等多种效果。

实现效果图:


  1. // 设置内容对齐方式,并设置内容距离四周距离(上左下右)  
  2. button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;  
  3. button.contentEdgeInsets = UIEdgeInsetsMake(0,1000);  
  4.   
  5. // 利用EdgeInsets属性将title和image放置在任意位置上,实现上图效果  
  6.   
  7. /* 
  8.  UIButton自带了UIImageView和UILabel两个控件,可以显示image和title,通过imageEdgeInsets和titleEdgeInsets属性可以将image和title放置在任意位置上 
  9.   
  10.  其实UIImageView和UILabel是相互联系的,在设置属性时需要将两者当做一个整体来考虑 
  11.  实时计算图片宽高 CGSize imageSize = button.imageView.frame.size; 
  12.  实时计算文字宽高 CGSize stringSize = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName:button.titleLabel.font}]; 
  13. */  
  14.   
  15. #define UI_SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width  
  16. #define UI_BUTTON_HEIGH 49  
  17.   
  18. // 在默认情况下,图片在前文字在后显示,且中间没有间距(如button1)  
  19. [button1 setImageEdgeInsets:UIEdgeInsetsMake(0000)];  
  20. [button1 setTitleEdgeInsets:UIEdgeInsetsMake(0000)];  
  21.   
  22. // 让图片和文字之间间距为10(如button2)  
  23. [button2 setImageEdgeInsets:UIEdgeInsetsMake(0, (UI_SCREEN_WIDTH-imageSize.width-stringSize.width-10)/20, (UI_SCREEN_WIDTH-imageSize.width-stringSize.width-10)/2+10)];  
  24. [button2 setTitleEdgeInsets:UIEdgeInsetsMake(0, (UI_SCREEN_WIDTH-imageSize.width-stringSize.width-10)/2+100, (UI_SCREEN_WIDTH-imageSize.width-stringSize.width-10)/2)];  
  25.   
  26. // 让图片距离右侧边缘10,让文字距离左侧边缘10(如button3)  
  27. [button3 setImageEdgeInsets:UIEdgeInsetsMake(0, UI_SCREEN_WIDTH-imageSize.width-10010-stringSize.width)];  
  28. [button3 setTitleEdgeInsets:UIEdgeInsetsMake(010-imageSize.width0, UI_SCREEN_WIDTH-stringSize.width-10)];  
  29.   
  30. // 让图片距离上侧边缘10,让文字距离下侧边缘10(如button4)  
  31. [button4 setImageEdgeInsets:UIEdgeInsetsMake(100, UI_BUTTON_HEIGH-10-imageSize.height0)];  
  32. [button4 setTitleEdgeInsets:UIEdgeInsetsMake(UI_BUTTON_HEIGH-10-stringSize.height0100)];  
  33.   
  34. // 让图片和文字都居中显示,且图片距离上侧边缘5,文字距离下侧边缘5(如button5)  
  35. [button5 setImageEdgeInsets:UIEdgeInsetsMake(5, (UI_SCREEN_WIDTH-imageSize.width)/2, UI_BUTTON_HEIGH-5-imageSize.height, (UI_SCREEN_WIDTH-imageSize.width)/2-stringSize.width)];  
  36. [button5 setTitleEdgeInsets:UIEdgeInsetsMake(UI_BUTTON_HEIGH-5-stringSize.height, (UI_SCREEN_WIDTH-stringSize.width)/2-imageSize.width5, (UI_SCREEN_WIDTH-stringSize.width)/2)];  


clear;clc; %% 轨迹生成部分 % XY平面参数 R =input('输入元件的检测半径 (mm): '); % 目标圆半径 (mm) r = input('输入检测光源的有效半径 (mm): '); % 采样圆半径 (mm) alpha = input('输入重叠率 (mm): ');% 重叠率 dr = 1.5*r*(1-alpha); % 径向步长 % 交互式输入接口 [核心修改] cx = input('输入圆心X坐标 (mm): '); cy = input('输入圆心Y坐标 (mm): '); cz0 = input('输入Z起始高度 (mm): '); % 新增Z初始位置 dz = input('输入Z方向切片间距 (mm): '); % 新增Z方向间隔 nz = input('输入Z方向切片数量: '); % 新增切片层数 %% 生成单层径向扫描轨迹 base_points = [cx, cy]; % 基点为自定义圆心 for k = 1:ceil(R/dr) radius = k * dr; if radius > (R-r) , break; end % 动态计算每圈点数 circumference = 2 * pi * radius; n_theta = max(6, ceil(circumference / (2*r*(1-alpha)))); theta = linspace(0, 2*pi, n_theta+1)'; theta(end) = []; % 生成环形采样点 x = cx + radius * cos(theta); y = cy + radius * sin(theta); base_points = [base_points; x, y]; % 保存为二维点 end % 筛选有效点 dist = sqrt((base_points(:,1)-cx).^2 + (base_points(:,2)-cy).^2); valid_base = base_points(dist <= R - r, :); % 路径排序 (径向分组) radial_groups = round(sqrt((valid_base(:,1)-cx).^2 + (valid_base(:,2)-cy).^2)/dr); sorted_base = []; for g = unique(radial_groups)' group_idx = radial_groups == g; group_points = valid_base(group_idx, :); % 按角度排序 rel_angle = atan2(group_points(:,2)-cy, group_points(:,1)-cx); [~, idx] = sort(rel_angle); sorted_base = [sorted_base; group_points(idx, :)]; end all_points = []; % 存储所有三维点 for z_layer = 1:nz z_val = cz0 + (z_layer-1)*dz; % 计算当前Z高度 layer_points = [sorted_base, repmat(z_val, size(sorted_base,1), 1)]; % 添加Z坐标 all_points = [all_points; layer_points]; % 添加到总点集 % 添加层间过渡点 (NaN断开) if z_layer < nz all_points = [all_points; [NaN, NaN, NaN]]; end end %% 覆盖率计算 (XY平面单层) num_mc = 1e6; mc_x = cx - R + 2*R*rand(num_mc, 1); mc_y = cy - R + 2*R*rand(num_mc, 1); inside_target = ((mc_x-cx).^2 + (mc_y-cy).^2 <= R^2); covered = false(num_mc, 1); for i = 1:size(sorted_base,1) dist = sqrt((mc_x - sorted_base(i,1)).^2 + (mc_y - sorted_base(i,2)).^2); covered = covered | (dist <= r); end coverage_ratio = sum(covered & inside_target) / sum(inside_target) * 100; fprintf('\n===== 扫描参数统计 =====\n'); fprintf('总采样点数: %d (单层) × %d层 = %d点\n', size(sorted_base,1), nz, size(all_points,1)-nz+1); fprintf('Z轴范围: %.1fmm 到 %.1fmm\n', cz0, cz0+(nz-1)*dz); fprintf('单层覆盖率: %.2f%%\n', coverage_ratio); %% 坐标导出 output_points = all_points(~isnan(all_points(:,1)), :); % 移除NaN分隔符 writematrix(output_points, '3D_scan_coordinates.csv'); fprintf('三维坐标已导出至: 3D_scan_coordinates.csv\n'); %% 图像处理 % 定义裁剪区域 [起始X, 起始Y, 宽度, 高度] input_path = uigetdir('','选择需要处理图像所在文件夹'); if input_path == 0 error('用户取消了图像处理所在文件夹选择'); end output_path = uigetdir('','选择裁剪图像存储文件夹'); if output_path == 0 error('用户取消了图像处理所在文件夹选择'); end center_x = 300; % 固定圆心X坐标 center_y = 250; % 固定圆心Y坐标 radius = 140; % 固定半径 %% 裁剪图像 batchImageCrop(input_path, output_path,center_x, center_y, radius); %% 消除不均匀 batch_illumination_correction(); %% 抠图 % 配置路径 inputFolder2 = 'D:\01-工作\02-实验数据\图像采集\20250825\0825-ZJCL'; % 存放BMP图像的文件夹 outputFolder2 = 'D:\01-工作\02-实验数据\图像采集\20250825\0825-koutu'; % 新建输出文件夹 % 创建输出目录(如果不存在) if ~exist(outputFolder2, 'dir') mkdir(outputFolder2); end % 获取所有BMP文件 fileList = dir(fullfile(inputFolder2, '*.bmp')); totalFiles = length(fileList); % 处理参数设置 tolerance = 10; % 黑色检测容差 (0-255) % 进度显示 fprintf('开始处理 %d 个BMP文件...\n', totalFiles); % 批量处理循环 for i = 1:totalFiles try % 读取当前文件 bmpFile = fullfile(inputFolder2, fileList(i).name); img = imread(bmpFile); % 确保为RGB格式(处理灰度图) if size(img, 3) == 1 img = cat(3, img, img, img); end % 创建透明通道 % 原理:$ \text{alpha}(x,y) = % \begin{cases} % 0 & \text{若 } \forall c \in \{R,G,B\}, \, I_c(x,y) \leq \text{tolerance} \\ % 255 & \text{其他} % \end{cases} $ alpha = all(img <= tolerance, 3); alpha = uint8(255 * ~alpha); % 黑色区域透明 % 生成输出文件名(保持原名称) [~, baseName] = fileparts(fileList(i).name); pngFile = fullfile(outputFolder2, [baseName, '.png']); % 保存透明PNG imwrite(img, pngFile, 'png', 'Alpha', alpha); fprintf('已处理: %s -> %s\n', fileList(i).name, [baseName, '.png']); catch ME fprintf('文件 %s 处理失败: %s\n', fileList(i).name, ME.message); end end fprintf('\n处理完成! 共成功转换 %d/%d 个文件\n', totalFiles, length(dir(fullfile(outputFolder2, '*.png')))); %% 图像拼接 imageDir = 'D:\01-工作\02-实验数据\图像采集\20250825\0825-koutu'; WidthCm=7.44; HeightCm=7.44; imageStitching(imageDir, WidthCm, HeightCm); %% 主体函数 %% 裁剪主函数 function batchImageCrop(input_folder, output_folder, center_x, center_y, radius) % 参数说明: % input_folder: 输入图像文件夹路径 % output_folder: 输出图像文件夹路径 % center_x: 圆形中心点x坐标(固定值) % center_y: 圆形中心点y坐标(固定值) % radius: 圆形半径(固定值) % 创建输出文件夹 if ~exist(output_folder, 'dir') mkdir(output_folder); end % 获取所有JPG图像文件 img_files = dir(fullfile(input_folder, '**', '*.bmp')); total_imgs = length(img_files); % 处理进度显示 fprintf('开始处理%d张图像...\n', total_imgs); progress_interval = max(floor(total_imgs/10), 1); % 进度更新间隔 % 固定位置圆形掩码(只需计算一次) [xx, yy] = meshgrid(1:2*radius+1, 1:2*radius+1); mask = (xx - radius - 1).^2 + (yy - radius - 1).^2 <= radius^2; % 遍历所有图像 for i = 1:total_imgs % 读取图像 img_path = fullfile(img_files(i).folder, img_files(i).name); img = imread(img_path); % 固定位置圆形裁剪 cropped = circular_crop(img, center_x, center_y, radius, mask); % 保存结果 [~, name, ext] = fileparts(img_files(i).name); output_path = fullfile(output_folder, [name '_cropped' ext]); imwrite(cropped, output_path); % 显示进度 if mod(i, progress_interval) == 0 fprintf('已处理: %d/%d (%.1f%%)\n', ... i, total_imgs, 100*i/total_imgs); end end fprintf('处理完成! 结果保存在: %s\n', output_folder); end function cropped = circular_crop(img, cx, cy, radius, mask) % 执行固定位置圆形裁剪 % 计算裁剪区域边界 x_start = max(1, round(cx - radius)); x_end = min(size(img, 2), round(cx + radius)); y_start = max(1, round(cy - radius)); y_end = min(size(img, 1), round(cy + radius)); % 裁剪矩形区域 rect_crop = img(y_start:y_end, x_start:x_end, :); % 调整掩码尺寸以适应实际裁剪区域 actual_height = size(rect_crop, 1); actual_width = size(rect_crop, 2); resized_mask = mask(1:actual_height, 1:actual_width); % 应用圆形遮罩 cropped = rect_crop; for c = 1:size(img, 3) channel = cropped(:,:,c); channel(~resized_mask) = 0; % 圆形外部设为黑色 cropped(:,:,c) = channel; end end %% 消除不均匀 function batch_illumination_correction() % 批量光照校正主函数 % 1. 获取用户输入的文件夹路径 bg_dir = uigetdir('', '选择背景图像文件夹'); if bg_dir == 0 error('用户取消了背景文件夹选择'); end target_dir = uigetdir('', '选择待校正目标图像文件夹'); if target_dir == 0 error('用户取消了目标文件夹选择'); end output_dir = uigetdir('', '选择校正后图像保存文件夹'); if output_dir == 0 error('用户取消了输出文件夹选择'); end % 2. 读取背景图像 bg_files = dir(fullfile(bg_dir, '*.bmp')); if isempty(bg_files) error('背景文件夹中未找到BMP图像'); end fprintf('正在加载背景图像...\n'); bg_stack = []; for i = 1:length(bg_files) img_path = fullfile(bg_dir, bg_files(i).name); img = imread(img_path); % 转换为灰度图(如果背景是彩色) if size(img, 3) == 3 img = rgb2gray(img); end % 添加到背景堆栈 if isempty(bg_stack) bg_stack = double(img); else bg_stack = cat(3, bg_stack, double(img)); end fprintf('已加载背景图像: %s\n', bg_files(i).name); end % 3. 计算平均背景校正映射 fprintf('计算光照校正映射...\n'); avg_bg = mean(bg_stack, 3); global_mean = mean(avg_bg(:)); correction_map = global_mean ./ avg_bg; % 处理除零错误 correction_map(isinf(correction_map)) = 1; correction_map(isnan(correction_map)) = 1; % 4. 处理目标图像 target_files = dir(fullfile(target_dir, '*.bmp')); if isempty(target_files) error('目标文件夹中未找到BMP图像'); end fprintf('开始批量校正图像...\n'); for i = 1:length(target_files) % 读取目标图像 img_path = fullfile(target_dir, target_files(i).name); target_img = imread(img_path); % 5. 应用校正 if size(target_img, 3) == 3 % 处理彩色图像 corrected_img = zeros(size(target_img), 'like', target_img); for channel = 1:3 % 转换到double进行运算 channel_data = double(target_img(:, :, channel)); % 应用校正映射 corrected_channel = channel_data .* correction_map; % 归一化并转换回原始数据类型 corrected_channel = uint8(255 * mat2gray(corrected_channel)); corrected_img(:, :, channel) = corrected_channel; end else % 处理灰度图像 target_img_double = double(target_img); corrected_img = target_img_double .* correction_map; % 归一化并转换回原始数据类型 corrected_img = uint8(255 * mat2gray(corrected_img)); end % 6. 保存结果 output_path = fullfile(output_dir, target_files(i).name); imwrite(corrected_img, output_path); fprintf('已校正并保存: %s\n', target_files(i).name); end fprintf('\n处理完成! 共校正 %d 张图像\n', length(target_files)); fprintf('输出文件夹: %s\n', output_dir); % 7. 显示示例结果 try fig = figure('Name', '光照校正结果对比', 'NumberTitle', 'off'); subplot(1,2,1); imshow(imread(fullfile(target_dir, target_files(1).name))); title('原始图像'); subplot(1,2,2); imshow(imread(fullfile(output_dir, target_files(1).name))); title('校正后图像'); catch warning('结果预览失败,但仍已保存所有图像'); end end %% 增强版图像拼接程序 - 基于强度的融合处理 %% 增强版图像拼接程序 - 支持Z分层 function fullImage = imageStitching(imageDir, pptWidthCm, pptHeightCm) % 参数说明: % imageDir: 图像文件夹路径 % pptWidthCm: PPT中图像显示的宽度(cm) % pptHeightCm: PPT中图像显示的高度(cm) %% 步骤1: 读取并解析图像文件(包含Z坐标) [imageFiles, positions, zValues] = parseImageFilesWithZ(imageDir); uniqueZ = unique(zValues); numLayers = numel(uniqueZ); %% 按Z层分组处理 for zIdx = 1:numLayers currentZ = uniqueZ(zIdx); fprintf('\n====== 处理 Z=%.3f 的图像层 ======\n', currentZ); % 筛选当前Z层的图像 layerIdx = (zValues == currentZ); layerFiles = imageFiles(layerIdx); layerPositions = positions(layerIdx, :); % 检查是否为空 if isempty(layerFiles) fprintf('警告: Z=%.3f 没有找到图像,跳过\n', currentZ); continue; end % 加载第一张图像确定基准尺寸 img1 = imread(fullfile(imageDir, layerFiles(1).name)); [height, width, numChannels] = size(img1); % 计算缩放因子 scaleFactor = calculateScaleFactor(pptWidthCm, pptHeightCm, width, height); %% 计算像素位置并创建结果画布 [pixelPositions, minPos, maxPos] = computeCanvasSize(layerPositions, scaleFactor, width, height); canvasWidth = ceil(maxPos(1) - minPos(1) + width); canvasHeight = ceil(maxPos(2) - minPos(2) + height); % 创建带透明通道的结果图像 fullImage = zeros(canvasHeight, canvasWidth, numChannels, 'like', img1); alphaCanvas = zeros(canvasHeight, canvasWidth, 'single'); weightAccumulator = zeros(canvasHeight, canvasWidth, 'single'); fprintf('当前层图像数: %d\n', numel(layerFiles)); fprintf('画布尺寸: %dx%d 像素\n', canvasWidth, canvasHeight); %% 逐图像处理并拼接 for i = 1:numel(layerFiles) % 读取当前图像 imgPath = fullfile(imageDir, layerFiles(i).name); currentImg = imread(imgPath); % 确保所有图像尺寸一致 if any(size(currentImg) ~= [height, width, numChannels]) currentImg = imresize(currentImg, [height, width]); end % 处理无效区域 [processedImg, alpha, validMask] = removeBlackBorders(currentImg); % 计算当前图像在画布上的位置 canvasX = round(pixelPositions(i, 1) - minPos(1)); canvasY = round(pixelPositions(i, 2) - minPos(2)); % 计算权重图 weightMap = calculateWeightMap(validMask); % 将图像放置在画布上 [fullImage, alphaCanvas, weightAccumulator] = intensityBlend(... fullImage, alphaCanvas, weightAccumulator, ... processedImg, alpha, weightMap, canvasX, canvasY); % 进度显示 if mod(i, 10) == 0 fprintf('已处理 %d/%d (%.1f%%)\n', ... i, numel(layerFiles), i/numel(layerFiles)*100); end end %% 应用最终融合处理 fullImage = applyFinalBlend(fullImage, weightAccumulator); %% 转换alpha通道 alphaCanvasUint8 = im2uint8(alphaCanvas); %% 保存带Z坐标的拼接结果 outputPath = fullfile(imageDir, sprintf('Z=%.3f_stitched.png', currentZ)); imwrite(fullImage, outputPath, 'Alpha', alphaCanvasUint8); fprintf('拼接完成! 结果保存至: %s\n', outputPath); end end %% 辅助函数 - 解析包含Z坐标的图像文件 function [imageFiles, positions, zValues] = parseImageFilesWithZ(imageDir) files = dir(fullfile(imageDir, '*.png')); if isempty(files) files = dir(fullfile(imageDir, '*.jpg')); end positions = zeros(numel(files), 2); zValues = zeros(numel(files), 1); for i = 1:numel(files) filename = files(i).name; % 增强正则表达式匹配 X,Y,Z tokens = regexp(filename, 'X=([\d\.\-]+)[,_\s]Y=([\d\.\-]+)[,_\s]Z=([\d\.\-]+)', 'tokens'); if ~isempty(tokens) x = str2double(tokens{1}{1}); y = str2double(tokens{1}{2}); z = str2double(tokens{1}{3}); positions(i, :) = [x, y]; zValues(i) = z; else tokens = regexp(filename, '([\d\.\-]+)_([\d\.\-]+)_([\d\.\-]+)', 'tokens'); if ~isempty(tokens) && numel(tokens{1}) >= 3 x = str2double(tokens{1}{1}); y = str2double(tokens{1}{2}); z = str2double(tokens{1}{3}); positions(i, :) = [x, y]; zValues(i) = z; else % 使用文件名序号作为位置 positions(i, :) = [i*10, i*10]; zValues(i) = 0; fprintf('警告: 无法解析位置,使用默认值: %s\n', filename); end end end imageFiles = files; end %% 基于强度融合的核心函数 function [canvas, alphaCanvas, weightAccumulator] = intensityBlend(... canvas, alphaCanvas, weightAccumulator, img, alpha, weightMap, x, y) % 获取尺寸信息 [imgH, imgW, imgC] = size(img); [canvasH, canvasW, canvasC] = size(canvas); % 计算有效区域 x1 = max(1, x); y1 = max(1, y); x2 = min(canvasW, x + imgW - 1); y2 = min(canvasH, y + imgH - 1); % 计算图像中对应的区域 imgX1 = max(1, 1 - (x - x1)); imgY1 = max(1, 1 - (y - y1)); imgX2 = min(imgW, imgW - ((x + imgW - 1) - x2)); imgY2 = min(imgH, imgH - ((y + imgH - 1) - y2)); % 提取画布区域 canvasRegion = canvas(y1:y2, x1:x2, :); alphaRegion = alphaCanvas(y1:y2, x1:x2); weightRegion = weightAccumulator(y1:y2, x1:x2); % 提取图像区域 imgRegion = img(imgY1:imgY2, imgX1:imgX2, :); alphaImg = alpha(imgY1:imgY2, imgX1:imgX2); weightImg = weightMap(imgY1:imgY2, imgX1:imgX2); % 验证尺寸一致性 regionH = size(canvasRegion, 1); regionW = size(canvasRegion, 2); if size(imgRegion, 1) ~= regionH || size(imgRegion, 2) ~= regionW % 调整图像区域尺寸以匹配画布区域 imgRegion = imresize(imgRegion, [regionH, regionW]); alphaImg = imresize(alphaImg, [regionH, regionW]); weightImg = imresize(weightImg, [regionH, regionW]); end % 仅在有效区域应用融合(忽略透明区域) validMask = alphaImg > 0.01; % 处理每个通道 for ch = 1:canvasC srcCh = single(imgRegion(:, :, ch)); dstCh = single(canvasRegion(:, :, ch)); % 计算混合权重 weightSum = weightRegion + weightImg; weightSum(weightSum == 0) = 1; % 避免除以零 % 仅在有效区域应用基于强度的融合 blended = dstCh; idx = validMask; blended(idx) = (dstCh(idx) .* weightRegion(idx) + ... srcCh(idx) .* weightImg(idx)) ./ weightSum(idx); canvasRegion(:, :, ch) = blended; end % 更新透明通道(取最大值) alphaRegion = max(alphaRegion, alphaImg); % 更新权重累加器 weightRegion = max(weightRegion, weightImg); % 更新画布 canvas(y1:y2, x1:x2, :) = canvasRegion; alphaCanvas(y1:y2, x1:x2) = alphaRegion; weightAccumulator(y1:y2, x1:x2) = weightRegion; end %% 计算权重图 - 基于有效区域的距离变换 function weightMap = calculateWeightMap(validMask) % 计算距离变换:距离有效区域中心越近,权重越高 distMap = bwdist(~validMask); % 距离边缘的距离 % 高斯滤波器平滑权重 weightMap = imgaussfilt(single(distMap), 5); % 标准偏差为5 % 归一化权重(0-1范围) weightMap = weightMap / max(weightMap(:)); % 设置无效区域权重为0 weightMap(~validMask) = 0; end %% 修复后的最终融合处理函数 function blendedImage = applyFinalBlend(image, weightAccumulator) % 创建掩码:只处理重叠区域(权重>1的区域) overlapMask = weightAccumulator > 1.3; % 如果没有重叠区域,直接返回 if ~any(overlapMask(:)) blendedImage = image; return; end % 转换为双精度以进行高质量处理 doubleImage = im2double(image); blendedResult = doubleImage; % 复制原始图像作为基准 % 获取图像尺寸 [h, w, numChannels] = size(doubleImage); % 创建三维重叠掩码 overlapMask3D = repmat(overlapMask, [1, 1, numChannels]); % 分离处理每个通道 for ch = 1:numChannels % 提取当前通道 channelData = doubleImage(:, :, ch); % 应用导向滤波(边缘感知平滑) smoothedChannel = imguidedfilter(... channelData, ... 'NeighborhoodSize', [15 15], ... 'DegreeOfSmoothing', 0.01); % 仅在重叠区域应用平滑结果 blendedChannel = channelData; blendedChannel(overlapMask) = smoothedChannel(overlapMask); blendedResult(:, :, ch) = blendedChannel; end % 转换回原始数据类型 if isa(image, 'uint8') blendedImage = im2uint8(blendedResult); elseif isa(image, 'uint16') blendedImage = im2uint16(blendedResult); elseif isa(image, 'single') blendedImage = im2single(blendedResult); else blendedImage = blendedResult; end end %% 辅助函数 - 最终结果显示 function showResultImage(fullImage, alphaCanvas) % 计算缩放比例以适合屏幕显示 screenSize = get(0, 'ScreenSize'); maxWidth = screenSize(3) * 0.8; maxHeight = screenSize(4) * 0.8; [h, w, ~] = size(fullImage); scale = min([maxWidth/w, maxHeight/h, 1]); if scale < 1 smallImg = imresize(fullImage, scale); smallAlpha = imresize(alphaCanvas, scale); else smallImg = fullImage; smallAlpha = alphaCanvas; end % 创建图形窗口 fig = figure('Name', '拼接结果', 'NumberTitle', 'off', ... 'CloseRequestFcn', @closeWindowCallback); % 显示图像 if size(fullImage, 3) == 1 % 灰度图像 hImg = imshow(smallImg, 'Border', 'tight'); set(hImg, 'AlphaData', smallAlpha); else % RGB图像 hImg = imshow(smallImg, 'Border', 'tight'); set(hImg, 'AlphaData', smallAlpha); end % 添加帮助信息 uicontrol('Style', 'text', ... 'Position', [10 10 300 30], ... 'String', '提示: 按任意键关闭窗口或点击右上角X按钮', ... 'BackgroundColor', [1 1 1 0.7], ... 'FontSize', 10); pan on; zoom on; % 设置键盘回调 set(fig, 'KeyPressFcn', @keyPressCallback); % 等待用户操作(按键或关闭窗口) waitfor(fig); %% 嵌套回调函数 function closeWindowCallback(src, ~) delete(src); end function keyPressCallback(~, ~) delete(fig); end end %% 辅助函数 - 移除黑色边框(返回有效区域掩码) function [processedImg, alpha, validMask] = removeBlackBorders(img) [h, w, c] = size(img); % 创建透明度通道 alpha = ones(h, w, 'single'); validMask = true(h, w); % 检测无效区域(黑色边框) if c == 3 grayImg = rgb2gray(img); else grayImg = img; end % 自适应阈值检测黑色区域 threshold = graythresh(grayImg) * 50; blackMask = grayImg < threshold; % 形态学操作去除噪点 se = strel('disk', 7); cleanedMask = imclose(blackMask, se); % 创建圆形蒙版 [x, y] = meshgrid(1:w, 1:h); centerX = w/2; centerY = h/2; radius = min(w, h) * 0.55; circleMask = ((x - centerX).^2 + (y - centerY).^2) <= (radius^2); % 组合蒙版:黑色区域或圆形区域外为透明 invalidMask = cleanedMask | ~circleMask; alpha(invalidMask) = 0; validMask(invalidMask) = false; processedImg = img; end %% 辅助函数 - 计算画布大小 function [pixelPositions, minPos, maxPos] = computeCanvasSize(positions, scaleFactor, imgW, imgH) % 坐标系转换 pixelX = positions(:,2) * scaleFactor; pixelY = -positions(:,1) * scaleFactor; % 计算左上角位置 topLeftX = pixelX - imgW/2; topLeftY = pixelY - imgH/2; pixelPositions = [topLeftX, topLeftY]; % 计算画布边界 minPos = min(pixelPositions); maxPos = max(pixelPositions) + [imgW, imgH]; % 添加安全边界 border = 50; minPos = minPos - border; maxPos = maxPos + border; end %% 辅助函数 - 计算缩放因子 function scaleFactor = calculateScaleFactor(pptW, pptH, imgW, imgH) physicalWidthUm = pptW * 10000; % cm→μm转换 physicalHeightUm = pptH * 10000; pxWidth = physicalWidthUm / imgW; pxHeight = physicalHeightUm / imgH; positionUnitUm = 10000; % 1单位位置 = 10,000μm = 1cm scaleX = positionUnitUm / pxWidth; scaleY = positionUnitUm / pxHeight; scaleFactor = (scaleX + scaleY)/2; fprintf('自动缩放因子:水平=%.4f, 垂直=%.4f, 使用=%.4f px/单位\n', ... scaleX, scaleY, scaleFactor); end %% 辅助函数 - 解析图像文件名 function [imageFiles, positions] = parseImageFiles(imageDir) files = dir(fullfile(imageDir, '*.png')); if isempty(files) files = dir(fullfile(imageDir, '*.jpg')); end positions = zeros(numel(files), 2); for i = 1:numel(files) filename = files(i).name; % 更健壮的正则表达式匹配 tokens = regexp(filename, 'X=([\d\.\-]+)[,_\s]Y=([\d\.\-]+)', 'tokens'); if ~isempty(tokens) x = str2double(tokens{1}{1}); y = str2double(tokens{1}{2}); positions(i, :) = -[x, y]; else % 尝试其他模式 tokens = regexp(filename, '([\d\.\-]+)_([\d\.\-]+)', 'tokens'); if ~isempty(tokens) && numel(tokens{1}) >= 2 x = str2double(tokens{1}{1}); y = str2double(tokens{1}{2}); positions(i, :) = -[x, y]; else % 使用文件名序号作为位置 positions(i, :) = [i*10, i*10]; fprintf('警告: 无法解析位置,使用默认值: %s\n', filename); end end end imageFiles = files; end 将这一程序打包成一个整体,并为其设计一个软件界面
最新发布
09-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值