围绕具有相同值的垂直像素组绘制矩形
Drawing rectangles around vertical groups of pixels having the same value
考虑以下由 3 个不同的 regions/values 组成的 7x5 矩阵的可视化:
bL = toeplitz( [zeros(1,5) -2*ones(1,2)], [0 -ones(1,4)] );
hF = figure(); hA = axes(hF);
imagesc(hA,bL); axis(hA,'image'); set(hA,'XTick',[],'YTick',[]);
N = 4; cmap = parula(N); colormap(cmap(1:end-1,:));
现在假设我在每列中 "select" 0 个或更多像素,这样:
- 选中的像素只能在绿色区域选中。
- 所选像素始终是连续的。
- 选择是通过分配一个常量新值来执行的,该值与 3 个初始区域不同。
选择几个例子(使用值1
):
%Example 1:
cSF = toeplitz([ones(1,1) zeros(1,4) -2*ones(1,2)],[1 -ones(1,4)]);
%Example 2:
oSF = toeplitz( [zeros(1,5) -2*ones(1,2)], [0 -ones(1,4)] );
oSF(end-2:end,find(any(oSF==-2,1),1,'last')+1:end) = 1;
%Example 3:
iSF = toeplitz([ones(1,3) zeros(1,2) -2*ones(1,2)],[1 -ones(1,4)]);
% Plot:
hF = figure();
hP(1) = subplot(1,3,1); imagesc(cSF);
hP(2) = subplot(1,3,2); imagesc(oSF);
hP(3) = subplot(1,3,3); imagesc(iSF);
axis(hP,'image'); set(hP,'XTick',[],'YTick',[]);
我的objective是绘制一组包含属于同一列的"selected"(黄色)像素的矩形。对于上面的示例,结果应如下所示(分别):
在我看来,对于通用代码,它应该接受:(1) 一个轴句柄,其中 imagesc
应该被绘制; (2) 一个data
数组; (3) 在data
数组中找到一个值,代表"chosen"个像素;以及可选的封闭像素的颜色。
我找到了一些使用 patch
和 rectangle
来做到这一点的方法(参见 ),但我想知道这是否可以通过更少的函数调用或其他方法来实现我没有想到的方法。
使用rectangle
的解决方案:
function markStreaksRect(hA, data, selectionVal)
% Check inputs:
assert(nargin >= 2); if nargin < 3 || isempty(selectionVal), selectionVal = 1; end
% Create a mask for "selected" values:
oneMask = data == selectionVal;
% Find the first encountered "selected" element from both the top and the bottom:
[~,I1] = max(oneMask,[],1); [~,I2] = max(flipud(oneMask),[],1);
% Express the "selected" extent as a 2 row vector:
firstLast = [I1; size(oneMask,1)-I2+1].*any(oneMask,1);
% For nonzero extents, plot shifted rectangles:
for ind1 = find(all(firstLast,1))
rectangle(hA,'Position',[ind1-0.5, firstLast(1,ind1)-0.5, 1, diff(firstLast(:,ind1))+1 ]);
end
使用patch
的解决方案:
function markStreaksPatch(hA, data, selectionVal)
% Check inputs:
assert(nargin >= 2); if nargin < 3 || isempty(selectionVal), selectionVal = 1; end
% Create a mask for "selected" values:
oneMask = data == selectionVal;
% Find the first encountered "selected" element from both the top and the bottom:
[~,I1] = max(oneMask,[],1); [~,I2] = max(flipud(oneMask),[],1);
% Express the "selected" extent as a 2 row vector:
firstLast = [I1; size(oneMask,1)-I2+1].*any(oneMask,1);
% For nonzero extents, plot shifted patches:
for ind1 = find(all(firstLast,1))
[XX,YY] = meshgrid(ind1-0.5 + [0 1], firstLast(1,ind1)-0.5+[0 diff(firstLast(:,ind1))+1]);
patch(hA, XX(:), [YY(1:2) YY(4:-1:3)], 'y', 'FaceAlpha', 0);
end
可以使用以下方法测试上述解决方案:
function q45965920
iSF = toeplitz([ones(1,3) zeros(1,2) -2*ones(1,2)],[1 -ones(1,4)]);
hF = figure(); hA = axes(hF); imagesc(hA,iSF);
axis(hA,'image'); set(hA,'XTick',[],'YTick',[]);
...然后 运行 markStreaksRect(hA, iSF, 1);
或 markStreaksPatch(hA, iSF, 1);
产生所需的结果。
使用patch
的无环解决方案:
这是一个无需循环即可为 patch
生成坐标的解决方案:
function column_highlight(hA, data, selectionVal)
assert(nargin >= 2);
if (nargin < 3) || isempty(selectionVal)
selectionVal = 1;
end
nCol = size(data, 2);
data = diff([false(1, nCol); (data == selectionVal); false(1, nCol)]);
[r, c] = find(data);
r = reshape(r-0.5, 2, []);
c = c(1:2:end);
X = [c-0.5 c+0.5 c+0.5 c-0.5].';
Y = r([1 1 2 2], :);
patch(hA, 'XData', X, 'YData', Y, 'FaceColor', 'none');
end
使用regionprops
的解决方案:
如果您有 Image Processing Toolbox,您可以通过标记每个屏蔽列部分并使用 regionprops
:
获取 'BoundingBox'
形状度量来解决此问题
function column_highlight(hA, data, selectionVal)
assert(nargin >= 2);
if (nargin < 3) || isempty(selectionVal)
selectionVal = 1;
end
labelMat = bsxfun(@times, (data == selectionVal), 1:size(data, 2));
coords = regionprops(labelMat, 'BoundingBox');
coords = vertcat(coords.BoundingBox);
coords(:, 3:4) = coords(:, 1:2)+coords(:, 3:4);
X = coords(:, [1 3 3 1]).';
Y = coords(:, [4 4 2 2]).';
patch(hA, 'XData', X, 'YData', Y, 'FaceColor', 'none');
end
考虑以下由 3 个不同的 regions/values 组成的 7x5 矩阵的可视化:
bL = toeplitz( [zeros(1,5) -2*ones(1,2)], [0 -ones(1,4)] );
hF = figure(); hA = axes(hF);
imagesc(hA,bL); axis(hA,'image'); set(hA,'XTick',[],'YTick',[]);
N = 4; cmap = parula(N); colormap(cmap(1:end-1,:));
现在假设我在每列中 "select" 0 个或更多像素,这样:
- 选中的像素只能在绿色区域选中。
- 所选像素始终是连续的。
- 选择是通过分配一个常量新值来执行的,该值与 3 个初始区域不同。
选择几个例子(使用值1
):
%Example 1:
cSF = toeplitz([ones(1,1) zeros(1,4) -2*ones(1,2)],[1 -ones(1,4)]);
%Example 2:
oSF = toeplitz( [zeros(1,5) -2*ones(1,2)], [0 -ones(1,4)] );
oSF(end-2:end,find(any(oSF==-2,1),1,'last')+1:end) = 1;
%Example 3:
iSF = toeplitz([ones(1,3) zeros(1,2) -2*ones(1,2)],[1 -ones(1,4)]);
% Plot:
hF = figure();
hP(1) = subplot(1,3,1); imagesc(cSF);
hP(2) = subplot(1,3,2); imagesc(oSF);
hP(3) = subplot(1,3,3); imagesc(iSF);
axis(hP,'image'); set(hP,'XTick',[],'YTick',[]);
我的objective是绘制一组包含属于同一列的"selected"(黄色)像素的矩形。对于上面的示例,结果应如下所示(分别):
在我看来,对于通用代码,它应该接受:(1) 一个轴句柄,其中 imagesc
应该被绘制; (2) 一个data
数组; (3) 在data
数组中找到一个值,代表"chosen"个像素;以及可选的封闭像素的颜色。
我找到了一些使用 patch
和 rectangle
来做到这一点的方法(参见
使用rectangle
的解决方案:
function markStreaksRect(hA, data, selectionVal)
% Check inputs:
assert(nargin >= 2); if nargin < 3 || isempty(selectionVal), selectionVal = 1; end
% Create a mask for "selected" values:
oneMask = data == selectionVal;
% Find the first encountered "selected" element from both the top and the bottom:
[~,I1] = max(oneMask,[],1); [~,I2] = max(flipud(oneMask),[],1);
% Express the "selected" extent as a 2 row vector:
firstLast = [I1; size(oneMask,1)-I2+1].*any(oneMask,1);
% For nonzero extents, plot shifted rectangles:
for ind1 = find(all(firstLast,1))
rectangle(hA,'Position',[ind1-0.5, firstLast(1,ind1)-0.5, 1, diff(firstLast(:,ind1))+1 ]);
end
使用patch
的解决方案:
function markStreaksPatch(hA, data, selectionVal)
% Check inputs:
assert(nargin >= 2); if nargin < 3 || isempty(selectionVal), selectionVal = 1; end
% Create a mask for "selected" values:
oneMask = data == selectionVal;
% Find the first encountered "selected" element from both the top and the bottom:
[~,I1] = max(oneMask,[],1); [~,I2] = max(flipud(oneMask),[],1);
% Express the "selected" extent as a 2 row vector:
firstLast = [I1; size(oneMask,1)-I2+1].*any(oneMask,1);
% For nonzero extents, plot shifted patches:
for ind1 = find(all(firstLast,1))
[XX,YY] = meshgrid(ind1-0.5 + [0 1], firstLast(1,ind1)-0.5+[0 diff(firstLast(:,ind1))+1]);
patch(hA, XX(:), [YY(1:2) YY(4:-1:3)], 'y', 'FaceAlpha', 0);
end
可以使用以下方法测试上述解决方案:
function q45965920
iSF = toeplitz([ones(1,3) zeros(1,2) -2*ones(1,2)],[1 -ones(1,4)]);
hF = figure(); hA = axes(hF); imagesc(hA,iSF);
axis(hA,'image'); set(hA,'XTick',[],'YTick',[]);
...然后 运行 markStreaksRect(hA, iSF, 1);
或 markStreaksPatch(hA, iSF, 1);
产生所需的结果。
使用patch
的无环解决方案:
这是一个无需循环即可为 patch
生成坐标的解决方案:
function column_highlight(hA, data, selectionVal)
assert(nargin >= 2);
if (nargin < 3) || isempty(selectionVal)
selectionVal = 1;
end
nCol = size(data, 2);
data = diff([false(1, nCol); (data == selectionVal); false(1, nCol)]);
[r, c] = find(data);
r = reshape(r-0.5, 2, []);
c = c(1:2:end);
X = [c-0.5 c+0.5 c+0.5 c-0.5].';
Y = r([1 1 2 2], :);
patch(hA, 'XData', X, 'YData', Y, 'FaceColor', 'none');
end
使用regionprops
的解决方案:
如果您有 Image Processing Toolbox,您可以通过标记每个屏蔽列部分并使用 regionprops
:
'BoundingBox'
形状度量来解决此问题
function column_highlight(hA, data, selectionVal)
assert(nargin >= 2);
if (nargin < 3) || isempty(selectionVal)
selectionVal = 1;
end
labelMat = bsxfun(@times, (data == selectionVal), 1:size(data, 2));
coords = regionprops(labelMat, 'BoundingBox');
coords = vertcat(coords.BoundingBox);
coords(:, 3:4) = coords(:, 1:2)+coords(:, 3:4);
X = coords(:, [1 3 3 1]).';
Y = coords(:, [4 4 2 2]).';
patch(hA, 'XData', X, 'YData', Y, 'FaceColor', 'none');
end