![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1256942/image.png)
How to get the RGB values of each point on a surface when illuminated by 'light' objects?
5 次查看(过去 30 天)
显示 更早的评论
I generated a surface with 200x200 points and illuminated it under some light. Now I want to know how the color of each pixel/point is perceived when the surface is viewed from top. I looked at the 'CData' matrix of the surface but it just returns the z-values of the surface. What I want is a 200x200x3 array with RGB values for the second image below and haven't figured out how to do so. I hope my inquiry makes sense.
% generating 200 by 200 surface
m = 200;
n = 200;
x = single(linspace(-8,8,m));
y = single(linspace(-8,8,n));
[X,Y] = meshgrid(x,y);
%Z = (4-abs(X)) + (4-abs(Y));
Z = X.^3-3.*X.*Y.^2;
figure(1)
surf(X,Y,Z,'EdgeColor','none');
figure(2)
s = surf(X,Y,Z);
s.EdgeColor = 'none';
view(0,90)
% making light objects
l1 = light;
l1.Position = [160 400 80];
l1.Style = 'local';
l1.Color = [0 0.8 0.8];
l2 = light;
l2.Position = [.5 -1 .4];
l2.Color = [0.8 0.8 0];
% painting the surface red
s.FaceColor = [0.9 0.2 0.2];
% assigning reflectance values
s.FaceLighting = 'gouraud';
s.AmbientStrength = 0.3;
s.DiffuseStrength = 0.6;
s.BackFaceLighting = 'lit';
s.SpecularStrength = 1;
s.SpecularColorReflectance = 1;
s.SpecularExponent = 7;
0 个评论
采纳的回答
DGM
2023-1-9
移动:DGM
2023-1-9
I don't have exportgraphics(), and I can't seem to ever get predictably-clean (i.e. unpadded) results from saveas or print, so I'm not bothering with any of those. truesize() doesn't work without an image or texturemapped surface in the axes, so I'm going to ignore that for now as well.
It's hardly elegant, but here's one workaround. This only really works so long as the figure is undocked.
% ... prior plotting stuff
% make sure axes box matches the data extents
xlim([-8 8])
ylim([-8 8])
% make sure the figure is large enough for the sample
set(gcf,'units','normalized');
set(gcf,'position',[0 0 1 1]);
% set size of axes
set(gca,'units','pixels');
set(gca,'position',[100 100 200 200]);
% get screenshot of axes
thisframe = frame2im(getframe(gca));
rawframesize = size(thisframe) % this should match the axes height,width
% instead of trying to reset the figure, i'm just going to close it
close gcf
% show the captured image
imshow(thisframe)
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/1256942/image.png)
3 个评论
DGM
2023-1-9
移动:DGM
2023-1-9
I've noticed that it's difficult to get consistent behavior, and I kind of expected that this might behave differently the moment someone else tries to run it.
I suppose it's worth trying to see whether
get(gca,'position')
actually got set to [100 100 200 200], or whether something else is going on.
EDIT: For me, the code worked in R2019b, but the results in R2015b are completely erratic. At least for me, the axes position does get set correctly, but the results returned by getframe are unpredictable in size, aspect ratio, and amount of padding -- even when an explicit RECT property is given. I can't say I have an answer. I'm sure you're not using R2015b, but this only goes to show that when it comes to figure capture, inconsistency is a consistency all in itself.
更多回答(4 个)
Walter Roberson
2023-1-8
... Unless you are lucky enough to find something in the File Exchange.
2 个评论
Sulaymon Eshkabilov
2023-1-8
If understood your question correctly, this might be the solution:
...
s.SpecularStrength = 1;
s.SpecularColorReflectance = 1;
s.SpecularExponent = 7;
%% Create an RGB image
RGBim(:,:,1)=X; RGBim(:,:,2) = Y; RGBim(:,:,3)=Z;
imshow(RGBim)
% See pixelvalues
impixelinfo
DGM
2023-1-9
In a sense, this is a non-serious answer, but perhaps consider this as tangential commentary.
For what it's worth, this is what I had to do to get it to behave in R2015b. I don't know if this works for anyone else, but maybe it demonstrates a concept.
% plot some data of arbitrary size
p = peaks(200);
s = pcolor(p);
s.EdgeColor = 'none';
view(0,90)
% make sure axes box matches the data extents
axis tight
% make sure the figure is large enough for the screenshot
set(gcf,'units','normalized');
set(gcf,'position',[0 0 1 1]);
% set size of axes by trial and error
axsz0 = [200 200]; % [x y]
set(gca,'units','pixels');
bg = permute(get(gcf,'color'),[1 3 2])*255; % background color
actualsize = [0 0]; % initialize
axsz = axsz0; % initialize
while any(actualsize ~= axsz0)
set(gca,'position',[100 100 axsz]);
% try to make behavior more consistent?
% neither option seem to work 100%, but both are better
drawnow
%pause(1)
% get frame
thisframe = frame2im(getframe(gca));
% get mask describing padding
% i'm assuming padding occurs on N and E edges (i can't guarantee that)
% i'm using bsxfun() because i'm testing in R2015b
padimg = abs(bsxfun(@minus,double(thisframe),bg));
padimg = all(padimg<2,3);
% calculate padding amount and base image geometry
% padding color is only inconsistently equal to figure color
% corners exhibit occasional gray spur pixels
% hence the soft check that at least 98% of pixels match
rawframesize = [size(padimg,2) size(padimg,1)]; % [x y]
padding = [sum(mean(padimg,1)>0.98) sum(mean(padimg,2)>0.98)]; % [x y]
actualsize = rawframesize-padding % [x y]
% try to correct for padding or improper sizing
axsz = axsz.*axsz0./actualsize;
end
% crop out the good portion of the padded image
% again, i'm assuming padding only occurs on N and E edges
outpict = thisframe(1+padding(2):end,1:actualsize(1),:);
On the first pass, this usually returns an oversize image which, when the padding is removed, is the correct size. The added padding is typically 1-4px. Occasionally, the base geometry or padding will be different (by 10-40px), but the routine will correct for it within about 3-5 attempts. As I mentioned, this doesn't happen for me in R2019b (hooray?). In R2009b, getframe() consistently returns an unpadded image exactly 1px oversize (though other concessions need to be made for the script to work that far back). I have no idea what this will do in a different environment.
One might ask, if getframe() returns a correctly-sized base image with some random additional padding, why not call getframe() with an explicit geometry so as to omit said padding? in R2015b, calling getframe() with an explicit geometry will return a predictably-sized frame with an unpredictable amount of padding. In other words, instead of the raw frame (outer) geometry being random, the base image (inner) geometry is random. I decided to manipulate the axes geometry instead; it solves more potential problems that way anyway.
Am I missing some magic bullet that makes figure capture something other than an unpredictable mess? Something that I can expect works the same way on another computer ... or even the same computer? Something that I can actually recommend to anyone without immediately causing them disappointment?
Cropping and resizing the captured frame after the fact might be sufficient, but the fact that anything so routine involves an unpredictable element is bothersome. Maybe that's just a side effect of dealing with all that's involved in rendering across different platforms.
P.S.
As I use R2009b rarely these days, I've forgotten how much faster it can be at these things.
0 个评论
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Graphics Performance 的更多信息
产品
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!