How can I add text to an image and make the text become part of the image within MATLAB?

435 views (last 30 days)
I would like to add a few characters to an image. I want the characters to be part of the image, not a text object.

Accepted Answer

MathWorks Support Team
MathWorks Support Team on 16 Feb 2021
Edited: MathWorks Support Team on 22 Feb 2021
If you have the Computer Vision System Toolbox, you can use the "insertText" function:
For example:
I = imread('peppers.png');
J = insertText(I, [100 315 ], 'Peppers are good for you!');
"insertText" supports unicode format. Please refer the following link for more information:
If the Computer Vision Toolbox is not available, you can use the following workaround:
You can display a text and use the GETFRAME function to capture the text as an image first. Then you replace the image pixels with the pixels from the text. The code below demonstrates the suggested steps above. Make sure that the image and axes objects are visible within the figure window when executing the GETFRAME command.
% Read example image
im = uint8(255*ind2rgb(X,map));
%% Create the text mask
% Make an image the same size and put text in it
hf = figure('color','white','units','normalized','position',[.1 .1 .8 .8]);
set(gca,'units','pixels','position',[5 5 size(im,2)-1 size(im,1)-1],'visible','off')
% Text at arbitrary position
text('units','pixels','position',[100 100],'fontsize',30,'string','some text')
% Capture the text image
% Note that the size will have changed by about 1 pixel
tim = getframe(gca);
% Extract the cdata
tim2 = tim.cdata;
% Make a mask with the negative of the text
tmask = tim2==0;
% Place white text
% Replace mask pixels with UINT8 max
im(tmask) = uint8(255);
axis off

Sign in to comment.

More Answers (4)

Dima Lisin
Dima Lisin on 3 Jun 2014
Edited: Dima Lisin on 10 Sep 2015
There is now an insertText function in the Computer Vision System Toolbox which will draw text into an image. It supports unicode characters as of R2015b.

DGM on 15 Jul 2021
Edited: DGM on 15 Jul 2021
Doing display capture seems like a poor workaround. The suggested method will fail for any practically large images. A reduced-size text image would need to be generated and padded out to correct geometry and text position. ... and all for a crudely binarized copy of what used to be antialiased text. If you're going to do display capture, at least preserve the antialiasing.
% process parameters
textstring = 'LOOK AT ALL THESE ROCKS';
fontsize = 100; % in pixels, not points
os = [900 300]; % offset
textcolor = [85 250 118];
inpict = imread('parkavenue.jpg');
s = size(inpict);
% create a text image on a base matting assumed large enough to enclose text
% this is just a quick guess on my part. i don't know of a good way to
% predict the output size with variable width fonts
hf = figure('units','normalized','position',[0 0 1 1]);
tt = text('units','pixels','position',[fontsize fontsize],'fontunits','pixels', ...
tpict = getframe(gca);
tpict = tpict.cdata;
% crop out the base text object, invert, pad to image size
ttpos = round(tt.Extent); close(hf)
ttpos(2) = size(tpict,1)-ttpos(2);
tpict = tpict(ttpos(2)-ttpos(4):ttpos(2),ttpos(1):ttpos(1)+ttpos(3));
tpict = imcomplement(im2double(tpict));
st = size(tpict);
if st(2)>s(2)
error('text is too big to fit %dpx>%dpx',st(2),s(2))
elseif (os(2)+st(2))>s(2)
error('text is too big to fit with given offset (%dpx+%dpx)>%dpx',os(2),st(2),s(2))
tpict = padarray(tpict,os,0,'pre');
tpict = padarray(tpict,s(1:2)-(os+st),0,'post');
% generate a colored field
cpict = ones(s(1:2)).*permute(textcolor,[1 3 2]);
% composite the images
outpict = double(inpict).*(1-tpict) + double(cpict).*tpict;
outpict = uint8(outpict);
The above code is not unbreakable, particularly due to the guesstimate for the required text matting size. It will also fail if the text block itself is too large to be rendered on screen. At least this demonstrates the concept and preserves the antialiasing because it uses linear blending.
Is there something else?
I suppose it really depends what the needs and expectations are. There are a number of text to image tools on the File Exchange. The result is a small image of text. Combining that into any image should be a simple task. Some may support antialiased output suitable for linear blending like the above example. Others support only binary output, which has different utility and can allow compositing with simple masking.
For example, using textim() from MIMT (binary masking):
% process parameters
textstring = 'potato';
os = [150 150]; % offset
textcolor = [250 100 220];
% note that this is a grayscale RGB image
% also note that these operations presume a uint8 image
inpict = repmat(imread('coins.png'),[1 1 3]);
si = size(inpict);
tt = textim(textstring,'ibm-vga-16x9');
st = size(tt);
m = zeros(si(1:2));
m(os(1)+(1:st(1)),os(2)+(1:st(2))) = tt;
outpict = inpict;
outpict(repmat(logical(m),[1 1 size(inpict,3)])) = 0;
outpict = outpict + uint8(m.*permute(textcolor,[1 3 2]));
MIMT has other tools that would simplify the positioning/compositing, but this example is generalized except for the textim() call.
What's on the FEX?
MIMT has both textim() and textblock(), which generate compact images of text in legacy hardware fonts. (CP437 based)
text2im() by Tobias Kiessling is similar, but only capable of a single font (the same default font used by MIMT textim()) (also CP437 based)
text2im by Rik offers a handful of modern font faces, though it supports a small charset and requires network connection.
text_to_image by Alec Jacobson is more flexible, but uses Imagemagick (external dependency), and is consequently slower.
There are also others:
And there are slightly different approaches:

Lockywolf on 13 Mar 2016
Unfortunately, the insertText function is excruciatingly slow, 0.04 seconds per call.
That is ~1.5 seconds on 40 objects.
I'd really like some advice on how to increase the speed.
  1 Comment
test test
test test on 14 Mar 2016
If you use same font and font size for all objects you may get better performance. If it does not improve the speed, could you provide the following info:
(1) version of MATLAB you are using
(2) code snippet where you call insertText function

Sign in to comment.

ElizabethMeng on 23 Nov 2016
this doesn't work for me... The size of the data acquired by getframe is never correct.
Guy Reading
Guy Reading on 22 May 2019
I found adding this, after the line "tmask = tim2==0;", makes the mask the right size & removes some weird effects:
% re-size mask
tmask = [tmask, false(size(tmask, 1), 1, 3)];
tmask = [tmask; false(1, size(tmask, 2), 3)];

Sign in to comment.

MathWorks Support

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!