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
将这一程序打包成一个整体,并为其设计一个软件界面
最新发布