<think>我们遇到的主要问题是:在图形更新函数`updateVehicleGraphics`中,我们尝试更新一个图形对象的'Vertices'属性,但该对象实际上是一个无效的图形对象(可能是被删除或未正确初始化)。具体错误是:“名称 'Vertices' 不是类 'matlab.graphics.GraphicsPlaceholder' 的实例可以访问的属性”。
原因分析:
1. 在`initializeGraphics`函数中,我们初始化`actorPlots`为一个空的图形对象数组(`gobjects(0)`)。然后,在`updateVehicleGraphics`中,我们试图使用这个数组来更新每个车辆的图形。
2. 在循环中,我们检查`actorPlots(i)`是否有效。但是,当`i`大于当前`actorPlots`数组的长度时,我们尝试创建一个新的图形对象(patch对象)并存储在`actorPlots(i)`中。然而,这里存在一个问题:当`actorPlots`数组为空时,我们直接通过索引`i`来赋值,这会导致`actorPlots`数组在索引`i`之前的位置(从1到i-1)都是空的图形占位符(GraphicsPlaceholder),而不是有效的图形对象。
3. 在后续的更新中,当我们尝试访问`actorPlots(i)`(其中`i`大于1)时,如果之前的索引位置没有被正确初始化,那么这些位置就是GraphicsPlaceholder对象,它们没有'Vertices'属性,从而导致错误。
解决方案:
我们需要确保`actorPlots`数组中的每个元素都是有效的图形对象(patch对象)或者为空(但后续会创建)。具体修改如下:
在`updateVehicleGraphics`函数中:
- 初始化时,如果`actorPlots`的长度小于车辆数量,我们将其扩展为一个新的图形对象数组,并且将新增的元素初始化为空的图形对象(但这里我们使用预分配并初始化为无效句柄,然后在循环中为每个位置创建patch对象)。
- 在循环中,对于每一个车辆,我们检查`actorPlots(i)`是否是一个有效的图形对象(并且是patch对象)。如果不是,我们就创建一个新的patch对象并赋值给`actorPlots(i)`。
但是,我们之前的代码已经尝试这样做了,但可能由于预分配的方式不对,导致产生了GraphicsPlaceholder对象。
我们修改预分配方式:在扩展`actorPlots`数组时,使用`gobjects`函数创建一个新的数组,并将原有的有效对象复制过去,新位置初始化为无效的图形对象(即0x0的GraphicsPlaceholder数组)。这样,在循环中,当我们检查到某个位置是无效的图形对象时,我们就创建一个新的patch对象。
然而,问题在于:在MATLAB中,使用`gobjects`预分配一个数组,然后对某个位置进行赋值(例如`actorPlots(i) = patch(...)`)是可行的,但是如果我们直接通过索引`i`来赋值,而`i`超过了数组的当前长度,那么MATLAB会自动将数组扩展到`i`,并在中间插入GraphicsPlaceholder对象。
为了避免这种情况,我们应该在循环之前确保`actorPlots`数组的长度至少等于车辆的数量。我们可以在循环开始前,将`actorPlots`数组扩展到车辆的数量,并且将新添加的元素设置为`gobjects(1)`(即一个无效的图形对象),然后在循环中为每个无效的位置创建patch对象。
修改后的`updateVehicleGraphics`函数如下:
```matlab
function actorPlots = updateVehicleGraphics(vehicles, actorPlots, hAx)
if ~isgraphics(hAx) || ~isvalid(hAx)
return;
end
numVehicles = numel(vehicles);
% 如果actorPlots的长度小于车辆数量,则扩展数组,并用无效的图形对象填充
if numel(actorPlots) < numVehicles
% 预分配至车辆数量,新位置用gobjects(1)填充(即无效对象)
actorPlots(numVehicles) = gobjects(1);
end
for i = 1:numVehicles
% 如果当前图形对象无效,则创建新的patch对象
if ~isvalid(actorPlots(i)) || ~isa(actorPlots(i), 'matlab.graphics.primitive.Patch')
% 创建新的patch对象
actorPlots(i) = patch(hAx, 'Vertices', [], 'Faces', 1:4, ...
'FaceColor', 'b', 'EdgeColor', 'k', ...
'Tag', sprintf('VehiclePatch%d', i));
end
actor = vehicles(i);
pos = actor.Position(1:2);
yaw = actor.Yaw;
len = actor.Length;
wid = actor.Width;
% 计算车辆轮廓
corners = [
-len/2, -wid/2;
len/2, -wid/2;
len/2, wid/2;
-len/2, wid/2;
];
% 旋转和平移
rotMat = [cosd(yaw) -sind(yaw); sind(yaw) cosd(yaw)];
corners = corners * rotMat;
corners(:,1) = corners(:,1) + pos(1);
corners(:,2) = corners(:,2) + pos(2);
% 更新图形数据
set(actorPlots(i), 'Vertices', corners);
end
end
```
但是,我们注意到在循环中,我们使用`isa(actorPlots(i), 'matlab.graphics.primitive.Patch')`来检查是否为patch对象。这是因为在重建图形系统时,我们可能会遇到不同类型的对象,但这里我们期望的是patch对象。
此外,在`initializeGraphics`函数中,我们初始化`actorPlots`为`gobjects(0)`,这是一个空的图形对象数组。在第一次调用`updateVehicleGraphics`时,由于车辆数量为3,所以我们会将`actorPlots`扩展为长度为3的数组,其中每个元素都是无效的,然后我们为每个车辆创建一个patch对象。
这样,在后续的更新中,我们就会直接更新这些patch对象的顶点。
另外,我们还注意到在`updateVehicleGraphics`函数中,我们使用`set(actorPlots(i), 'Vertices', corners)`来更新顶点。如果图形对象是有效的,这应该没有问题。
此外,还有一个错误是在`initializeGraphics`函数中调用`updateRoadGraphics`时传入了空场景,而我们在`updateRoadGraphics`函数中已经处理了空场景的情况(设置道路边界数据为空)。但是,在第一次初始化时,我们调用`updateRoadGraphics([], hAx)`,这会导致道路边界被清空(即没有显示)。我们可以在初始化时不调用`updateRoadGraphics`,而是在循环中传入实际的场景对象来更新道路。但为了在初始化时显示道路,我们可以传入一个空的道路边界(比如画一个空线)。所以这个部分可以保持不变。
最后,我们注意到在错误日志中,还有一个错误发生在`axis(hAx, 'equal')`。这可能是由于在图形窗口关闭后重新初始化时,坐标轴对象被删除导致的。但是,我们在重建图形系统时已经重新创建了坐标轴,所以应该没有问题。不过,为了安全,我们可以在调用`axis`之前检查坐标轴是否有效。
修改`initializeGraphics`中的坐标轴设置:
```matlab
hAx = axes('Parent', hFig);
if isgraphics(hAx) && isvalid(hAx)
axis(hAx, 'equal');
hold(hAx, 'on');
grid(hAx, 'on');
xlabel(hAx, 'X (m)');
ylabel(hAx, 'Y (m)');
title(hAx, '驾驶场景预览');
set(hAx, 'Tag', 'DrivingSimAxes');
end
```
但是,由于我们刚刚创建了坐标轴,所以它一定是有效的。因此,这个错误可能是由于在关闭图形窗口时,重建过程中被中断导致的。我们可以忽略这个错误,因为它不会影响主要功能,或者我们可以通过更健壮的重建机制来避免。
考虑到时间,我们先解决主要的车辆图形更新问题。
我们将按照上述修改`updateVehicleGraphics`函数,并确保在重建图形系统后,`actorPlots`数组被正确重置(在`initializeGraphics`中,我们将其初始化为空,然后在第一次更新时重新创建)。
此外,在重建图形系统后,我们在主循环中重新获取了`[hFig, hAx, actorPlots]`,所以后续的更新会使用新的图形对象数组。
因此,请将`updateVehicleGraphics`函数替换为上述修改后的版本。
同时,我们注意到在`updateVehicleGraphics`函数中,我们使用了`isa`来检查是否是patch对象。但是,在图形对象被删除后,`isvalid`会返回false,所以我们可以只检查`isvalid`。但是,为了确保类型正确,我们也可以同时检查类型。不过,如果图形对象被删除,`isvalid`就会返回false,所以我们只需检查有效性即可。
因此,我们可以简化条件:
```matlab
if ~isvalid(actorPlots(i))
% 创建新的patch对象
actorPlots(i) = patch(hAx, ...);
end
```
修改后的完整`updateVehicleGraphics`函数如下:
```matlab
function actorPlots = updateVehicleGraphics(vehicles, actorPlots, hAx)
if ~isgraphics(hAx) || ~isvalid(hAx)
return;
end
numVehicles = numel(vehicles);
% 如果actorPlots的长度小于车辆数量,则扩展数组,并用无效的图形对象填充
if numel(actorPlots) < numVehicles
actorPlots(numVehicles) = gobjects(1); % 扩展数组,新元素为无效图形对象
end
for i = 1:numVehicles
% 如果当前图形对象无效,则创建新的patch对象
if ~isvalid(actorPlots(i))
actorPlots(i) = patch(hAx, 'Vertices', [], 'Faces', 1:4, ...
'FaceColor', 'b', 'EdgeColor', 'k', ...
'Tag', sprintf('VehiclePatch%d', i));
end
actor = vehicles(i);
pos = actor.Position(1:2);
yaw = actor.Yaw;
len = actor.Length;
wid = actor.Width;
% 计算车辆轮廓
corners = [
-len/2, -wid/2;
len/2, -wid/2;
len/2, wid/2;
-len/2, wid/2;
];
% 旋转和平移
rotMat = [cosd(yaw) -sind(yaw); sind(yaw) cosd(yaw)];
corners = corners * rotMat;
corners(:,1) = corners(:,1) + pos(1);
corners(:,2) = corners(:,2) + pos(2);
% 更新图形数据
set(actorPlots(i), 'Vertices', corners);
end
end
```
请尝试使用这个修改后的函数。
另外,请注意,在重建图形系统后,我们调用了`initializeGraphics`,它会返回一个新的`actorPlots`数组(初始为空)。然后我们在更新车辆图形时,会重新创建所有的图形对象。所以这个修改应该能够解决问题。
如果问题仍然存在,请检查在重建图形系统后,`actorPlots`是否被正确重置(即初始化为空数组),并且在更新车辆图形时,由于`actorPlots`是空的,会进入创建新patch对象的流程。
我们修改后的代码将放在下面。由于整个代码较长,我们只替换`updateVehicleGraphics`函数,并确保其他部分保持不变。
注意:由于代码较长,我们只提供修改后的完整代码,但为了节省空间,我们省略了未修改的部分。请重点替换`updateVehicleGraphics`函数。
完整代码(仅修改部分)如下:</think>### 问题分析与修复
根据错误日志,核心问题是 `updateVehicleGraphics` 函数中图形对象句柄管理不当导致的"Vertices属性访问错误"。具体原因如下:
1. **图形对象初始化问题**:
- `actorPlots` 数组初始化时使用了 `gobjects(0)` 创建空句柄数组
- 当首次尝试访问 `actorPlots(i)` 时(如 `actorPlots(1)`)
- MATLAB 会自动创建 `matlab.graphics.GraphicsPlaceholder` 实例
- 该占位符对象**没有**`Vertices`属性
2. **对象有效性检查不足**:
- 仅使用 `isvalid()` 检查无法区分实际图形对象和占位符
- 占位符对象通过 `isvalid()` 检查返回 `true`,但没有实际图形属性
3. **重建机制缺陷**:
- 当图形系统重建时,`initializeGraphics` 返回新的空句柄数组
- 但后续更新仍尝试访问旧的占位符对象
### 完整修复代码
```matlab
%% 1. 场景创建与传感器配置 (保持不变)
scenario = drivingScenario('SampleTime', 0.1, 'StopTime', 30);
roadCenters = [0 0 0; 50 0 0; 100 20 0; 200 40 0; 250 50 0; 300 40 0];
road(scenario, roadCenters, 'Lanes', lanespec(3));
vehicles = [...
vehicle(scenario, 'ClassID', 1, 'Position', [0 0 0], 'Length', 4.7, 'Width', 1.8, 'Height', 1.4),...
vehicle(scenario, 'ClassID', 1, 'Position', [40 0 0], 'Length', 4.7, 'Width', 1.8, 'Height', 1.4),...
vehicle(scenario, 'ClassID', 1, 'Position', [60 -3 0], 'Length', 4.7, 'Width', 1.8, 'Height', 1.4)...
];
egoVehicle = vehicles(1);
focalLength = [1000, 1000];
principalPoint = [320, 240];
imageSize = [480, 640];
camIntrinsics = cameraIntrinsics(focalLength, principalPoint, imageSize);
height = 1.5;
pitch = 10;
sensor = monoCamera(camIntrinsics, height, 'Pitch', pitch);
%% 2. 数据采集 - 优化初始化
totalFrames = round(scenario.StopTime/scenario.SampleTime);
cameraFrames = cell(totalFrames, 1);
vehiclePoses = zeros(totalFrames, 3);
% 初始化图形系统 (保持不变)
[hFig, hAx, actorPlots] = initializeGraphics();
setappdata(hFig, 'GraphicsActive', true);
%% 3. 场景渲染循环 - 修复图形更新错误
frameCount = 0;
while advance(scenario) && frameCount < totalFrames
frameCount = frameCount + 1;
position = egoVehicle.Position(1:2);
yaw = egoVehicle.Yaw;
vehiclePoses(frameCount, :) = [position, yaw];
if isgraphics(hFig) && isvalid(hFig) && getappdata(hFig, 'GraphicsActive')
try
updateRoadGraphics(scenario, hAx);
% 关键修复:传递当前帧计数用于重建检测
actorPlots = updateVehicleGraphics(vehicles, actorPlots, hAx, frameCount);
catch ME
warning('图形更新错误: %s', ME.message);
[hFig, hAx, actorPlots] = initializeGraphics();
setappdata(hFig, 'GraphicsActive', true);
end
if isgraphics(hAx) && isvalid(hAx)
set(hAx, 'XLim', [position(1)-20, position(1)+50], ...
'YLim', [position(2)-10, position(2)+10]);
end
if mod(frameCount, 5) == 0
try
cameraFrames{frameCount} = safeCaptureFrame(hFig);
if ~isempty(cameraFrames{frameCount})
showFrameInSeparateWindow(cameraFrames{frameCount}, frameCount, totalFrames, position, yaw);
end
catch ME
warning('帧捕获失败: %s', ME.message);
cameraFrames{frameCount} = [];
end
else
cameraFrames{frameCount} = [];
end
else
cameraFrames{frameCount} = [];
end
end
if ishandle(hFig)
close(hFig);
end
fprintf('数据采集完成: 共 %d 帧\n', frameCount);
%% 4. 车道线检测与鸟瞰图生成 (保持不变)
config = struct(...
'VehicleWidth', egoVehicle.Width, ...
'VehicleFront', 2.0, ...
'VehicleRear', 1.0, ...
'OutputImageSize', [600, 800], ...
'WorldUnitsPerPixel', 0.1);
birdsEyeConfig = birdsEyeView(...
'VehicleWidth', config.VehicleWidth, ...
'VehicleFront', config.VehicleFront, ...
'VehicleRear', config.VehicleRear, ...
'OutputImageSize', config.OutputImageSize, ...
'WorldUnitsPerPixel', config.WorldUnitsPerPixel);
laneDetectionParams = struct(...
'Sensitivity', 0.85, ...
'LaneWidthRange', [2.5 4.5], ...
'MaxNumLanes', 3, ...
'ROI', [1 400; 1 720; 1280 720; 1280 400]);
figure('Name', '车道线鸟瞰图', 'Position', [100 100 1200 600])
hAxes = axes;
hold(hAxes, 'on');
axis(hAxes, 'equal');
grid(hAxes, 'on');
xlabel('X (m)'); ylabel('Y (m)');
title('实时车道线检测与车辆轨迹');
for frameIdx = 1:min(100, frameCount)
I = cameraFrames{frameIdx};
if isempty(I), continue; end
[laneBoundaries, valid] = detectLanes(I, laneDetectionParams);
if valid
birdsEyeImage = transformImage(birdsEyeConfig, I);
imshow(birdsEyeImage, 'Parent', hAxes);
title(hAxes, sprintf('帧 %d/%d | 检测到 %d 条车道线', frameIdx, frameCount, numel(laneBoundaries)));
colors = ['r', 'g', 'b', 'c'];
for laneIdx = 1:numel(laneBoundaries)
lanePoints = laneBoundaries(laneIdx).Points;
lanePointsVehicle = imageToVehicle(birdsEyeConfig, lanePoints);
plot(hAxes, lanePointsVehicle(:,1), lanePointsVehicle(:,2), ...
[colors(laneIdx) '-'], 'LineWidth', 2);
end
vehiclePos = vehiclePoses(frameIdx, 1:2);
yaw = vehiclePoses(frameIdx, 3);
plot(hAxes, vehiclePos(1), vehiclePos(2), 'yo', 'MarkerSize', 10, 'MarkerFaceColor', 'y');
arrowLength = 3;
endX = vehiclePos(1) + arrowLength * cosd(yaw);
endY = vehiclePos(2) + arrowLength * sind(yaw);
quiver(hAxes, vehiclePos(1), vehiclePos(2), endX-vehiclePos(1), endY-vehiclePos(2), ...
0, 'Color', 'y', 'LineWidth', 2, 'MaxHeadSize', 2);
if frameIdx > 1
plot(hAxes, vehiclePoses(1:frameIdx,1), vehiclePoses(1:frameIdx,2), 'g-', 'LineWidth', 2);
end
legendEntries = arrayfun(@(x) sprintf('车道 %d', x), 1:numel(laneBoundaries), 'UniformOutput', false);
legendEntries = [legendEntries, '车辆位置', '行驶方向', '行驶轨迹'];
legend(hAxes, legendEntries, 'Location', 'northeastoutside');
drawnow;
end
end
%% 5. 完整车道线地图构建 (保持不变)
finalMap = uint8(zeros(birdsEyeConfig.OutputImageSize));
laneMaps = cell(1, 3);
for i = 1:3
laneMaps{i} = false(birdsEyeConfig.OutputImageSize(1:2));
end
for frameIdx = 1:frameCount
I = cameraFrames{frameIdx};
if isempty(I), continue; end
[laneBoundaries, valid] = detectLanes(I, laneDetectionParams);
if ~valid, continue; end
for laneIdx = 1:min(numel(laneBoundaries), 3)
lanePoints = laneBoundaries(laneIdx).Points;
lanePointsVehicle = imageToVehicle(birdsEyeConfig, lanePoints);
lanePixels = vehicleToImage(birdsEyeConfig, lanePointsVehicle);
laneMask = false(size(finalMap, 1), size(finalMap, 2));
for j = 1:size(lanePixels, 1)
x = round(lanePixels(j, 1));
y = round(lanePixels(j, 2));
if x >= 1 && x <= size(finalMap, 2) && y >= 1 && y <= size(finalMap, 1)
laneMask(y, x) = true;
end
end
se = strel('disk', 3);
laneMask = imdilate(laneMask, se);
laneMaps{laneIdx} = laneMaps{laneIdx} | laneMask;
end
end
colorMap = repmat(finalMap, [1 1 3]);
colors = uint8([255 0 0; 0 255 0; 0 0 255]);
for laneIdx = 1:3
mask = laneMaps{laneIdx};
for c = 1:3
channel = colorMap(:, :, c);
channel(mask) = colors(laneIdx, c);
colorMap(:, :, c) = channel;
end
end
trajectoryVehicleCoords = zeros(size(vehiclePoses,1), 2);
for i = 1:size(vehiclePoses,1)
worldPos = vehiclePoses(i,1:2);
egoYaw = vehiclePoses(i,3);
R = [cosd(egoYaw) sind(egoYaw); -sind(egoYaw) cosd(egoYaw)];
trajectoryVehicleCoords(i,:) = (worldPos - vehiclePoses(1,1:2)) * R';
end
trajectoryPixels = vehicleToImage(birdsEyeConfig, [trajectoryVehicleCoords zeros(size(trajectoryVehicleCoords,1),1)]);
trajectoryPixels = round(trajectoryPixels);
for i = 1:size(trajectoryPixels, 1)
x = trajectoryPixels(i, 1);
y = trajectoryPixels(i, 2);
if x >= 1 && x <= size(colorMap,2) && y >= 1 && y <= size(colorMap,1)
yRange = max(1,y-2):min(size(colorMap,1),y+2);
xRange = max(1,x-2):min(size(colorMap,2),x+2);
colorMap(yRange, xRange, 1) = 255;
colorMap(yRange, xRange, 2) = 255;
colorMap(yRange, xRange, 3) = 0;
end
end
figure('Name', '完整车道线鸟瞰图', 'Position', [100 100 1000 800])
imshow(colorMap)
title('车道线鸟瞰图 (红色: 左车道, 绿色: 中车道, 蓝色: 右车道)');
hold on;
text(50, 50, '↑ 行驶方向', 'Color', 'w', 'FontSize', 14, 'FontWeight', 'bold');
%% ================ 修复的关键辅助函数 ================
function [hFig, hAx, actorPlots] = initializeGraphics()
hFig = figure('Position', [100, 100, 1280, 720], 'Name', '场景预览', ...
'CloseRequestFcn', @closeFigureCallback, ...
'Tag', 'DrivingSimFigure');
% 修复:确保坐标轴创建成功
try
hAx = axes('Parent', hFig);
axis(hAx, 'equal');
hold(hAx, 'on');
grid(hAx, 'on');
xlabel(hAx, 'X (m)');
ylabel(hAx, 'Y (m)');
title(hAx, '驾驶场景预览');
set(hAx, 'Tag', 'DrivingSimAxes');
catch
hAx = axes('Parent', hFig);
axis(hAx, 'equal');
end
% 修复:初始化非空图形对象数组
actorPlots = gobjects(1, 3); % 预分配3个车辆位置
for i = 1:3
actorPlots(i) = patch(hAx, 'Vertices', [], 'Faces', 1:4, ...
'FaceColor', 'b', 'EdgeColor', 'k', ...
'Tag', sprintf('VehiclePatch%d', i), ...
'Visible', 'off'); % 初始不可见
end
updateRoadGraphics([], hAx);
function closeFigureCallback(~,~)
setappdata(hFig, 'GraphicsActive', false);
delete(hFig);
end
end
function updateRoadGraphics(scenario, hAx)
roadBorderPlot = findobj(hAx, 'Tag', 'RoadBorderPlot');
if isempty(roadBorderPlot) || ~isvalid(roadBorderPlot)
roadBorderPlot = plot(hAx, NaN, NaN, 'k-', 'LineWidth', 2, 'Tag', 'RoadBorderPlot');
end
if isempty(scenario)
set(roadBorderPlot, 'XData', [], 'YData', []);
return;
end
roadBorders = roadBoundaries(scenario);
allX = [];
allY = [];
for i = 1:numel(roadBorders)
border = roadBorders{i};
allX = [allX; border(:,1); NaN];
allY = [allY; border(:,2); NaN];
end
set(roadBorderPlot, 'XData', allX, 'YData', allY);
end
% 完全重写的车辆图形更新函数
function actorPlots = updateVehicleGraphics(vehicles, actorPlots, hAx, frameCount)
% 确保坐标轴有效
if ~isgraphics(hAx) || ~isvalid(hAx)
return;
end
numVehicles = numel(vehicles);
% 重建检测:当帧计数为1或图形对象无效时
if frameCount == 1 || ~all(isvalid(actorPlots))
% 删除现有无效对象
for i = 1:numel(actorPlots)
if isvalid(actorPlots(i))
delete(actorPlots(i));
end
end
% 创建新的图形对象数组
actorPlots = gobjects(1, numVehicles);
for i = 1:numVehicles
actorPlots(i) = patch(hAx, 'Vertices', [], 'Faces', 1:4, ...
'FaceColor', 'b', 'EdgeColor', 'k', ...
'Tag', sprintf('VehiclePatch%d', i));
end
end
% 更新车辆图形
for i = 1:numVehicles
actor = vehicles(i);
pos = actor.Position(1:2);
yaw = actor.Yaw;
len = actor.Length;
wid = actor.Width;
corners = [
-len/2, -wid/2;
len/2, -wid/2;
len/2, wid/2;
-len/2, wid/2;
];
rotMat = [cosd(yaw) -sind(yaw); sind(yaw) cosd(yaw)];
corners = corners * rotMat;
corners(:,1) = corners(:,1) + pos(1);
corners(:,2) = corners(:,2) + pos(2);
% 安全更新:检查对象有效性
if isvalid(actorPlots(i))
set(actorPlots(i), 'Vertices', corners, 'Visible', 'on');
else
% 重建单个车辆图形
actorPlots(i) = patch(hAx, corners(:,1), corners(:,2), 'b', ...
'Tag', sprintf('VehiclePatch%d', i));
end
end
% 隐藏多余图形对象
if numel(actorPlots) > numVehicles
for i = numVehicles+1:numel(actorPlots)
if isvalid(actorPlots(i))
set(actorPlots(i), 'Visible', 'off');
end
end
end
end
% 其余辅助函数保持不变 (safeCaptureFrame, showFrameInSeparateWindow, detectLanes等)
```
### 关键修复说明:
1. **图形对象初始化重构**:
- 在 `initializeGraphics` 中预分配**实际图形对象**而非空句柄
- 初始设置为不可见(`'Visible','off'`),避免渲染空对象
- 避免创建 `GraphicsPlaceholder` 实例
2. **车辆更新函数重写**:
- 新增 `frameCount` 参数用于重建检测
- 在首帧或对象失效时完全重建图形对象数组
- 添加对象有效性双重检查:
```matlab
if frameCount == 1 || ~all(isvalid(actorPlots))
% 重建所有图形对象
end
```
3. **安全更新机制**:
- 更新前检查对象有效性:`if isvalid(actorPlots(i))`
- 对象失效时重建单个车辆图形
- 隐藏多余图形对象避免残留渲染
4. **错误处理增强**:
- 坐标轴创建添加异常处理
- 图形重建时删除旧对象避免资源泄漏
### 相关问题