How best to change the colors of pixels in an image with known X (column) Y (row) coordinates?
3 views (last 30 days)
Show older comments
The obvious way is to loop over every XY pair and change the color of the identified pixel, but this is very slow. I can do a lot better using indexing, but it is a clumsy approach, as it does the same thing three times. Is there a better, more intuitive way (even if it's not much faster)?
Image = uint8(repmat(randi(100, [9, 9]), [1, 1, 3]));
Image2 = Image;
Image3 = Image;
Color = uint8([1, 0.25, 0.1] .* 255);
Xs = [2; 2; 3; 3; 3; 4; 5; 6; 7; 7; 7; 8; 8];
Ys = [3; 6; 2; 3; 7; 8; 8; 8; 2; 3; 7; 3; 6];
% Adding lots of duplicates to make this simple problem harder.
Xs = repmat(Xs, [1000000, 1]);
Ys = repmat(Ys, [1000000, 1]);
% Looping is slow.
tic
for ii = 1:numel(Xs)
Image(Ys(ii), Xs(ii), :) = Color;
end
t1 = toc;
% The best I could come up with. It's faster, but inelegant.
tic
idx = sub2ind(size(Image2, [1, 2]), Ys, Xs);
Image2(idx) = Color(1);
Image2(idx + prod(size(Image3, [1, 2]))) = Color(2);
Image2(idx + 2.*prod(size(Image3, [1, 2]))) = Color(3);
t2 = toc;
% Is there a better way?
tic
% Do something...
t3 = toc;
montage({Image, Image2, Image3}, 'Size', [1, 3])
disp(['Loop time = ', num2str(t1, 3), ' seconds.'])
disp(['Index time = ', num2str(t2, 2), ' seconds.'])
disp(['New time = ', num2str(t3, 2), ' seconds.'])
disp(['Indexing is ~', num2str(round(t1./t2), '%d'), ' times faster than looping.'])
0 Comments
Accepted Answer
DGM
on 16 Feb 2023
Edited: DGM
on 16 Feb 2023
Normally, you'd do region replacement using a mask of some sort.
Image = uint8(repmat(randi(100, [9, 9]), [1, 1, 3]));
Image2 = Image;
Image3 = Image;
Color = uint8([1, 0.25, 0.1] .* 255);
Xs = [2; 2; 3; 3; 3; 4; 5; 6; 7; 7; 7; 8; 8];
Ys = [3; 6; 2; 3; 7; 8; 8; 8; 2; 3; 7; 3; 6];
% Adding lots of duplicates to make this simple problem harder.
Xs = repmat(Xs, [1000000, 1]);
Ys = repmat(Ys, [1000000, 1]);
% Looping is slow.
tic
for ii = 1:numel(Xs)
Image(Ys(ii), Xs(ii), :) = Color;
end
t1 = toc;
% The best I could come up with. It's faster, but inelegant.
tic
idx = sub2ind(size(Image2, [1, 2]), Ys, Xs);
Image2(idx) = Color(1);
Image2(idx + prod(size(Image3, [1, 2]))) = Color(2);
Image2(idx + 2.*prod(size(Image3, [1, 2]))) = Color(3);
t2 = toc;
% use a mask
tic
sz = size(Image2, [1, 2]);
idx = sub2ind(sz, Ys, Xs);
mask = false(sz);
mask(idx) = true;
% IPT imoverlay() can work with I/RGB images
% BG must be an image, FG must be an RGB tuple
% mask can only be binarized
% and FG color must be unit-scale float
Image3 = imoverlay(Image3,mask,im2double(Color));
% MIMT replacepixels() can work with I/IA/RGB/RGBA/RGBAAA images
% FG/BG can be images or tuples
% mask can be binarized or smooth, I/RGB
% color can be anything so long as it's correctly-scaled for its class
%Image3 = replacepixels(Color,Image3,mask);
t3 = toc;
montage({Image, Image2, Image3}, 'Size', [1, 3])
disp(['Loop time = ', num2str(t1, 3), ' seconds.'])
disp(['Index time = ', num2str(t2, 2), ' seconds.'])
disp(['New time = ', num2str(t3, 2), ' seconds.'])
disp(['Indexing is ~', num2str(round(t1./t2), '%d'), ' times faster than looping.'])
disp(['Masking is ~', num2str(round(t1./t3), '%d'), ' times faster than looping.'])
If all you need are binary selections and you're replacing the regions with a single color, then IPT imoverlay() works. If the selected regions are to be replaced by another image, then imoverlay() won't work.
Filling with another image, using only basic tools:
0 Comments
More Answers (0)
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!