function fruitImageProcessingGUI% 创建主窗口和控件mainFigure = figure('Units', 'normalized', 'Position', [0.3, 0.3, 0.4, 0.4]);instructionText = uicontrol('Style', 'text', 'String', '请点击按钮执行相应的图像处理步骤', ...'Units', 'normalized', 'Position', [0.1, 0.7, 0.8, 0.2], 'FontSize', 12);readImageBtn = uicontrol('Style', 'pushbutton', 'String', '读取图像', ...'Units', 'normalized', 'Position', [0.2, 0.4, 0.6, 0.1], 'FontSize', 12, ...'Callback', @readImageBtn_Callback);thresholdBtn = uicontrol('Style', 'pushbutton', 'String', '阈值化', ...'Units', 'normalized', 'Position', [0.2, 0.3, 0.6, 0.1], 'FontSize', 12, ...'Enable', 'off', 'Callback', @thresholdBtn_Callback);% 在这里继续添加其他按钮和控件% 存储GUI数据的结构体handles = struct();% 读取图像按钮的回调函数function readImageBtn_Callback(~, ~)% 读取图像rgb = imread('fruit.jpg');[m, n, d] = size(rgb);% 更新说明文本框set(instructionText, 'String', '图像已读取');% 将图像保存到GUI数据中,以便其他按钮功能使用handles.rgb = rgb;handles.m = m;handles.n = n;handles.d = d;% 启用下一个按钮set(thresholdBtn, 'Enable', 'on');% 更新GUI数据guidata(mainFigure, handles);end% 阈值化按钮的回调函数function thresholdBtn_Callback(~, ~)% 获取GUI数据中的图像和尺寸信息rgb = handles.rgb;m = handles.m;n = handles.n;d = handles.d;% 阈值设置level1 = [255 * 0.2, 255 * 0.3];% 转换数据类型,图像输出类型只能是uint型rgb = uint8(rgb);% 剔除r-g < level1(1), r-g < level1(2)的部分r = rgb;for i = 1:mfor j = 1:nif (rgb(i, j, 1) - rgb(i, j, 2)) < level1(1) && (rgb(i, j, 1) - rgb(i, j, 3)) < level1(2)r(i, j, 1) = 0;r(i, j, 2) = 0;r(i, j, 3) = 0;endendend% 更新说明文本框set(instructionText, 'String', '图像阈值化完成');% 在此处可以添加显示阈值化后的图像的代码,例如使用imshow函数显示r% 更新GUI数据handles.rgb = r;guidata(mainFigure, handles);end% 在这里继续添加其他按钮的回调函数end
function imageSegmentationGUI()% 创建GUI窗口fig = figure('Name', '目标与背景的分割与提取', 'NumberTitle', 'off', 'Position', [200, 200, 900, 600]);% 创建UI组件btnSelectImage = uicontrol('Style', 'pushbutton', 'String', '选择图像', 'Position', [50, 500, 100, 30], 'Callback', @selectImage);btnMeanFilter = uicontrol('Style', 'pushbutton', 'String', '均值滤波', 'Position', [50, 450, 100, 30], 'Callback', @applyMeanFilter);btnThresholding = uicontrol('Style', 'pushbutton', 'String', '二值图像', 'Position', [50, 400, 100, 30], 'Callback', @applyThresholding);btnOpening = uicontrol('Style', 'pushbutton', 'String', '开启运算', 'Position', [50, 350, 100, 30], 'Callback', @applyOpening);btnClosing = uicontrol('Style', 'pushbutton', 'String', '闭合运算', 'Position', [50, 300, 100, 30], 'Callback', @applyClosing);btnEdgeDetection = uicontrol('Style', 'pushbutton', 'String', '提取边缘', 'Position', [50, 250, 100, 30], 'Callback', @applyEdgeDetection);btnShowResult = uicontrol('Style', 'pushbutton', 'String', '显示结果', 'Position', [50, 200, 100, 30], 'Callback', @showResult);btnSegmentation = uicontrol('Style', 'pushbutton', 'String', '分割图像', 'Position', [50, 150, 100, 30], 'Callback', @performSegmentation);btnExit = uicontrol('Style', 'pushbutton', 'String', '退出', 'Position', [50, 100, 100, 30], 'Callback', @exitGUI);axesHandle1 = axes('Parent', fig, 'Position', [0.3, 0.1, 0.6, 0.8]);% 全局变量rgb = [];r=[];grayImage = [];thresholdedImage = [];openedImage = [];closedImage = [];edgeImage = [];resultImage = [];% 图像处理函数function selectImage(~, ~)[fileName, pathName] = uigetfile({'*.jpg;*.png;*.bmp', '图像文件 (*.jpg, *.png, *.bmp)'}, '选择图像');if isequal(fileName, 0) || isequal(pathName, 0)return;end% 读取图像rgb = imread(fullfile(pathName, fileName));% 显示原图像imshow(rgb, 'Parent', axesHandle1);endfunction applyMeanFilter(~, ~)if isempty(rgb)errordlg('请先选择图像!', '错误');return;end% 均值滤波r2=rgb;grayImage = rgb2gray(r2);n = 3;template = ones(n) / (n * n);filteredImage = imfilter(double(grayImage), template, 'replicate');% 显示均值滤波后的图像imshow(filteredImage, 'Parent', axesHandle1);endfunction applyThresholding(~, ~)if isempty(grayImage)errordlg('请先进行均值滤波!', '错误');return;end% 二值图像threshold = graythresh(grayImage);thresholdedImage = imbinarize(grayImage, threshold);% 显示二值图像imshow(thresholdedImage, 'Parent', axesHandle1);endfunction applyOpening(~, ~)if isempty(thresholdedImage)errordlg('请先进行二值图像处理!', '错误');return;end% 开启运算se = strel('disk', 12);openedImage = imopen(thresholdedImage, se);% 显示开启运算后的图像imshow(openedImage, 'Parent', axesHandle1);endfunction applyClosing(~, ~)if isempty(openedImage)errordlg('请先进行开启运算!', '错误');return;end% 闭合运算se = strel('disk', 5);closedImage = imclose(openedImage, se);% 显示闭合运算后的图像imshow(closedImage, 'Parent', axesHandle1);endfunction applyEdgeDetection(~, ~)if isempty(closedImage)errordlg('请先进行闭合运算!', '错误');return;end% 提取边缘edgeImage = edge(closedImage, 'canny');% 显示边缘图像imshow(edgeImage, 'Parent', axesHandle1);endfunction showResult(~, ~)if isempty(edgeImage)errordlg('请先进行边缘提取!', '错误');return;end% 分割完成的图像resultImage = edgeImage; % 这里将边缘图像作为分割结果,您可以根据需要修改这部分代码% 显示分割结果imshow(resultImage, 'Parent', axesHandle1);endfunction performSegmentation(~, ~)if isempty(rgb)errordlg('请先选择图像!', '错误');return;end% 在这里执行分割任务% 根据您的代码进行相应的处理% ...% 显示分割结果resultImage = rgb; % 这里将原图像作为分割结果,您可以根据需要修改这部分代码% 显示分割结果imshow(resultImage, 'Parent', axesHandle1);endfunction exitGUI(~, ~)choice = questdlg('确定要退出吗?', '退出', '是', '取消', '取消');if strcmp(choice, '是')close(fig);endend
end
GUI界面设计如下
实现目标与背景的分割和提取
clear
clc
close allh = 0.002; % 步长
x1 = 100;
x0 = 0:h:x1;
y0 = [2; 2; 2; 2]; % 初始条件,对应 x, y, z, w
% 不同的 c
c = 1:1:500;
N_c = length(c);
N_P = 300; % 假设穿过截面的共有 300 个点
BF = nan(N_c, N_P);
for k = 1:N_cc_k = c(k);disp(c_k)% 计算轨迹[y1, ~] = ODE_RK4_hyh(0:10*h:x1, 10*h, y0, [c_k, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]); % 先粗略的计算前几步,然后排除初始点的影响,舍弃不要[y1, ~] = ODE_RK4_hyh(x0 + x1, h, y1(:, end), [c_k, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]);% 计算 Poincare 平面Plane = [1; -1; 0; 0]; % x - y = 0 平面 (正方向)[tP_List, yP_List] = Solve_Poincare(x0, y1, Plane); % 计算 Poincare 平面% 对于混沌系统再加一条,如果系统稳定了,则将稳定点也记录在最终分岔图内:if isempty(tP_List) && abs(y1(1, end) - y1(2, end)) < 1e-2 % 如果最后 x 和 y 足够接近,则认为收敛了tP_List = x0(end - 1:end);yP_List = y1(:, end - 1:end);end% 储存 y 值作为待会分岔图的点N_P_temp = size(tP_List, 2);if N_P_temp > N_PBF(k, 1:N_P) = yP_List(2, 1:N_P);elseBF(k, 1:N_P_temp) = yP_List(2, 1:N_P_temp);end
end% 绘制分岔图
figure()
hold on
for k = 1:N_Pc_k = c(k);plot(c_k * ones(1, N_P), BF(k, 1:N_P), ...'LineStyle', 'none', 'Marker', '.', 'MarkerFaceColor', 'k', 'MarkerEdgeColor', 'k', ...'MarkerSize', 1)
end
hold offfunction [tP_List, yP_List] = Solve_Poincare(t, y, Plane)% 截面方程 z = 0% Plane = [0; 0; 1; 0]; % 一般情况下是个垂直某个轴的平面% 一般只记录从负到正穿越。如果想反向也记录,可以设置 Plane = -Plane.% 第二步,插值得到线与面的交点yP_List = [];tP_List = [];Dis = DistancePlane(y, Plane);N = size(y, 2);for k = 1:N - 1if Dis(k) <= 0 && Dis(k + 1) > 0t0 = t(k);t1 = t(k + 1);yP0 = y(:, k);yP1 = y(:, k + 1);Dis0 = Dis(k);Dis1 = Dis(k + 1);% 一维线性插值,求 Dis = 0 时的 t 和 yyP = yP0 + (yP1 - yP0) / (Dis1 - Dis0) * (0 - Dis0);tP = t0 + (t1 - t0) / (Dis1 - Dis0) * (0 - Dis0);% 储存yP_List = [yP_List, yP];tP_List = [tP_List, tP];endend
end% 点到平面的距离
function Dis = DistancePlane(xk, Plane)% xk,坐标点,如果是 3 维坐标,大小就是 3*N 的矩阵。% Plane,平面,形如 Ax + By + Cz + D = 0 形式的平面。N = size(xk, 2); % 计算总共多少个点xk2 = [xk; ones(1, N)];Dis = dot(xk2, Plane * ones(1, N), 1) / norm(Plane(1:end - 1));
endfunction [F, Output] = Fdydx(x, y, Input)% 形式为 Y' = F(x, Y) 的方程,参见数值分析求解常系数微分方程相关知识% 高次用列向量表示,F = [dy(1); dy(2)]; y(1) 为函数,y(2) 为函数导数% 给定混沌系统的微分方程a = Input(1);b = Input(2);c = Input(3);d = Input(4);e = Input(5);f = Input(6);g = Input(7);h = Input(8);dxdt = a * y(3) * y(2) + c * y(4) * cos(y(2));dydt = -y(1) * y(3) + b * y(2) + e * y(1) + f * y(2);dzdt = y(1) * y(2) - c * y(3) + f * y(3);dwdt = y(2) * y(3) - d * y(4) + g * y(1) * cos(y(2)) + h * y(2) * sin(y(3));F = [dxdt; dydt; dzdt; dwdt];Output = [];
endfunction [y, Output] = ODE_RK4_hyh(x, h, y0, Input)% 4阶RK方法% h 间隔为常数的算法y = zeros(size(y0, 1), size(x, 2));y(:, 1) = y0;for ii = 1:length(x) - 1yn = y(:, ii);xn = x(ii);[K1, ~] = Fdydx(xn, yn, Input);[K2, ~] = Fdydx(xn + h / 2, yn + h / 2 * K1, Input);[K3, ~] = Fdydx(xn + h / 2, yn + h / 2 * K2, Input);[K4, ~] = Fdydx(xn + h, yn + h * K3, Input);y(:, ii + 1) = yn + h / 6 * (K1 + 2 * K2 + 2 * K3 + K4);endOutput = [];
end
使用matlab对图像进行去噪处理、对彩色图像 进行目标和背景分析,通过阈值法将图像进行分割,提取特征参数,并对圆度和直径进行标定。使用均值滤波等一系列方法实现了对苹果的分割提取以及特征参数的标定。但是本次设计存在不足之处,对于重叠区域的分割与提取暂未处理好。
[1]陈贝文,陈淦.水果分类识别与成熟度检测技术综述[J].计算机时代,2022(07):62-65.DOI:10.16644/j.cnki.cn33-1094/tp.2022.07.016.
[2]王运祥,马本学,贾艳婷等.采用夹持果梗方法的水果检测分级机设计[J].食品与机械,2015,31(05):107-110.DOI:10.13652/j.issn.1003-5788.2015.05.027.
[3]苗玉彬,王浙明,刘秦.水果轮廓特征提取的Zernike矩分水岭分割方法[J].农业工程学报,2013,29(01):158-163.
[4]应义斌.水果图像的背景分割和边缘检测技术研究[J].浙江大学学报(农业与生命科学版),2000(01):37-40.
[5]徐琳,吕宇玲,王晓娟.水果的分割算法研究[J].数字通信世界,2018(05):274-275.
[6]苗玉彬,王浙明,刘秦.水果轮廓特征提取的Zernike矩分水岭分割方法[J].农业工程学报,2013,29(01):158-163.