Drawing bounding box onto an image without imshow and hold on ...
35 views (last 30 days)
Show older comments
Alfian Abdul Halin
on 9 Dec 2015
Hi there. I was wondering if its possible to draw a rectangle, whose coordinates is obtained from regoingprops. I however, am not interested to show the image first. What I intend to do is to get the bounding box coordinates form regionprops, and then just superimpose it onto an image without displaying it. I would then like to save the image (saving is ok... just drawing the rectangle got me a bit tangled up :P ). Would appreciate any advice!
The code I'm currently using is as shown above. (It's in a for loop) where 'l' is the counter.
THANKS in advance!!!
f = figure,imshow(frame, 'Border', 'tight');
hold on;
rectangle('Position',s(l).BoundingBox,'EdgeColor','y','LineWidth',2)
print(f, '-r80', '-djpeg', [dirName 'results' '\' jpegFiles(i).name]);
close all;
0 Comments
Accepted Answer
Walter Roberson
on 9 Dec 2015
If you have the Computer Vision Toolbox then you can use shapeInserter
If you do not have that, then you can just assign values to the appropriate rows and columns in the array. Watch out for the possibility that the values for the coordinates are not integral
bb = s(l).BoundingBox;
from_row = ceil(bb(2));
to_row = from_row + bb(4) - 1;
from_col = ceil(bb(1));
to_col = from_col + bb(3) - 1;
yellow = [255, 255, 0];
%left and right side
frame(from_row:to_row, [from_col, to_col], 1) = yellow(1);
frame(from_row:to_row, [from_col, to_col], 2) = yellow(2);
frame(from_row:to_row, [from_col, to_col], 3) = yellow(3);
%top and bottom
frame([from_row, to_row], from_col+1:to_col-1, 1) = yellow(1);
frame([from_row, to_row], from_col+1:to_col-1, 1) = yellow(2);
frame([from_row, to_row], from_col+1:to_col-1, 1) = yellow(3);
4 Comments
Sandipan Dey
on 23 Aug 2022
Edited: Sandipan Dey
on 23 Aug 2022
or slightly moifiying the abovr code to change color channels at once and draw a bounding box (e.g., one obtained using regionprops) with a given (odd) width (e.g., 3):
function frame = drawBB(bb, frame, width)
from_row = ceil(bb(2));
to_row = from_row + bb(4) - 1;
from_col = ceil(bb(1));
to_col = from_col + bb(3) - 1;
yellow = [255, 255, 0];
for i = -fix(width/2):fix(width/2)
%left and right side
frame(from_row:to_row, [from_col+i, to_col+i], :) = ...
permute(repmat(yellow, to_row-from_row+1, 1, 2), [1,3,2]);
%top and bottom
frame([from_row+i, to_row+i], from_col+1:to_col-1, :) = ...
permute(repmat(yellow, 2, 1, to_col-from_col-1), [1,3,2]);
end
end
The output can be seen in the following montage (the input image is taken from a coursera course by mathworks).
J. Alex Lee
on 30 Dec 2024 at 16:51
Had a need for this, and the added width option was nice, but it is not robust to BB's on the edge of the image (out-of-bounds indices), so here is a version in case it helps anyone else.
It should be a bit faster by aggregating all indices to color in first before checking for out-of-bounds and coloring.
function rgb = BoundBoxOverlay(in,bb,opts)
arguments
in
bb
opts.Width = 1
opts.Color = [0 255 0]
end
sz = size(in);
if class(in)=="double"
in = im2uint8(in);
end
if numel(sz)>2
rgbp{1} = in(:,:,1);
rgbp{2} = in(:,:,2);
rgbp{3} = in(:,:,3);
else
rgbp{1} = in;
rgbp{2} = in;
rgbp{3} = in;
end
% compute sizes
N = sz(1);
NM = sz(1)*sz(2);
% list of offsets based on width of bounding box to draw
hw = floor(opts.Width/2);
offsetList = (-hw:hw)';
% bounding boxes may be supplied as cell array
if ~iscell(bb)
bb{1} = bb;
end
for k = numel(bb):-1:1
idxList{k} = bb2idx(bb{k} , N,offsetList);
end
idxList = vertcat(idxList{:});
% post-process to remove out-of-bounds
mask = idxList < 1 | idxList > NM;
idxList(mask) = [];
% color in bounding box by page
rgbp{1}(idxList) = opts.Color(1);
rgbp{2}(idxList) = opts.Color(2);
rgbp{3}(idxList) = opts.Color(3);
% concatenate pages into an rgb image
rgb = cat(3,rgbp{:});
end
function idxList = bb2idx(bb , N,offsetList)
% compute row and column limits
subLims = cumsum(ceil(reshape(bb,2,2)),2) - [0,1];
% colLims = cumsum(ceil(bb([1,3])) - [0,1];
% rowLims = cumsum(ceil(bb([2,4])) - [0,1];
% construct list of subscripts (x,y) defining the bounding box
xAll = subLims(1,1):subLims(1,2) - 1;
yAll = subLims(2,1):subLims(2,2);
xLim = subLims(1,:) + offsetList - 1;
yLim = subLims(2,:) + offsetList;
% convert subscripts to indices on the image plane (rgb page)
idxList = [
reshape(yAll + xLim(:)*N,[],1);
reshape(yLim(:) + xAll*N,[],1)
];
end
More Answers (1)
DGM
on 5 Jan 2025 at 0:19
Just because I felt like doing it my way.
% any image
inpict = imread('peppers.png');
% some 2D logical mask of the same page geometry
% there are only two blobs, one each for the named objects
mask = imread('redpepmask.png')>128 ...
| imread('chilipepmask.png')>128;
% get boundingbox list
S = regionprops(mask,'boundingbox');
R = vertcat(S.BoundingBox);
% generate composite image
fgcolor = [1 1 0]; % an I/RGB color tuple
outpict = overlaybb(inpict,R,fgcolor);
% show the composition
imshow(outpict)
function outpict = overlaybb(inpict,R,fgcolor)
% OUTPICT = OVERLAYBB(INPICT,R,FGCOLOR)
% Draw colored rectangles on an image.
%
% INPICT is an I/IA/RGB/RGBA image of any class
% R is a NBLOBSx4 array of bounding box coordinates
% as given by regionprops().
% FGCOLOR is an I/IA/RGB/RGBA tuple of any class.
% This is typically RGB, expressed as unit-scale float.
% Regardless of class, FGCOLOR must be properly-scaled
% for its class.
%
% Output depth is expanded as needed.
% Output class is inherited from INPICT.
% convert to vertex locations (one row per rectangle)
% these lines are tangential to the blob without any overlap
vy = [floor(R(:,2)) ceil(sum(R(:,[2 4]),2))];
vx = [floor(R(:,1)) ceil(sum(R(:,[1 3]),2))];
% generate a composite mask
sz = imsize(inpict,2); % MIMT; size() can't do this directly in R2015x
Rmask = false(sz);
for k = 1:size(R,1)
V = [vx(k,[1 2 2 1 1]); vy(k,[1 1 2 2 1])].';
Rmask = Rmask | brline(sz,V); % MIMT
end
% do the composition
outpict = replacepixels(fgcolor,inpict,Rmask); % MIMT
end
This example relies on some MIMT tools, and is only partially period-accurate for 2015. While the above code and the current MIMT version will run on R2015x, it wouldn't have in 2015.
While an early version of replacepixels() should have been capable of handling this usage, brline() and imsize() were not yet included in MIMT. That said, other relevant composition options such as imoverlay() and labeloverlay() were also not part of IPT yet either. See other solid-color masked composition options circa 2015:
There are other ways to draw the line masks. There were ROI tools available in R2015x (e.g. imline()). It requires the use of a figure, but at least it wouldn't require figure capture. That still doesn't seem very elegant to me.
If thicker lines are needed, the simple offset of vx,vy and the difference of two poly2mask() calls will get the mask without the need for brline(). ... or you can just do it by direct indexing.
If you wanted each box to inherit a color from a color table (sort of like the later labeloverlay()), that's just a minor rearrangement of the steps. Instead of incrementally generating the mask, incrementally generate the composite image.
0 Comments
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!