This is supposed to be very simple I think but I can't get it right...
I plot several graphical objects in a figure and now I want a bitmap of the figure, that maintains the position on the objects and the dimensions of the figure.
To give a very simple example, if I plot 2 points in coordinates (0,0) and (200,200) I expect the rendering to output a matrix of size (200,200) where pixels (0,0) and (200,200) have a gray level of 255 and the rest of the pixels are zeroed (this is in case of a 8-bit per pixel grayscale though 3I prefer a color bitmap that will reflect the colors of the objects as appear in the original figure)
Thanks
To answer my own question, this is what I did to render a figure with graphical objects to a bitmap in memory and keep it in scale: I used getFrame and then resized the result to the size of the axes. Here goes:
% plot stuff on the current axes, then...
set(gca, 'ydir', 'reverse');
xLim = get(gca, 'XLim');
yLim = get(gca, 'YLim');
rendered = getframe(gca);
imageMat = imresize(rendered.cdata, [floor(yLim(2)), floor(xLim(2))]);
Here the image is sampled twice which is both inefficient in terms of processing time and gives a somewhat degraded image. For my purposes it's ok but still a single-sample solution would be nice...
Related
I have a little mess with a GUI developed on Matlab. Basically, I have two axes, one to plot a bitmap I want to keep all the time and another one to do some ordinary plots. My problem is that when I try to do any plot on the second axes, the image on the first one disappears and the axis get restarted. I tried to plot over the image and it remains on the figure (only shifts because the axis change once the previous image is gone).
Any idea aout what is happening? By the way, it is for a chromatic tuner that plots a degradation from green to red depending on the accuracy and the FFT of the received signal.
1) Here is the code for the image plot:
colormap(cmap);
imagesc(bmp,'Parent',handles.axes_tuner);
hold(handles.axes_tuner,'on');
% Vertical line in front of the image
plot([L/2,L/2],[-length(bmp(:,1)),2*length(bmp(:,1))],'b','LineWidth',1.5);
axis(handles.axes_tuner,'off');
hold(handles.axes_tuner,'off');
2) Plot on the other axes
cla(handles.axes_fft);
hold(handles.axes_fft,'on');
plot(f,spectrum,'b-','Parent',handles.axes_fft);
xlabel(handles.axes_fft,'Frequency','FontSize',8);
axis([0 Fs -50 0]);
ylabel(handles.axes_fft,'Normalized Amplitude','FontSize',8);
hold(handles.axes_fft,'off');
I've seen a few libraries that pixelate images, some of them even feature non-square shapes such as The Pixelator's circle and diamond shapes.
I'm looking however to make a particular shape, I want a "pixel" that is 19x27 px. Essentially, the image would still look pixelated but it would use tallish rectangle shapes as the pixel base.
Are there any libraries out there that do this, if not, what alterations to existing algorithms/functions would I need to make to accomplish this?
Unless I am not understanding your question, the algorithm you need is quite simple!
Just break your image up into a grid of rectangles the size you want (in this case 19x27). Loop over each section of the grid and take the average color of the pixels inside (you can simply take the average of each channel in RGB independently). Then set all of the pixels contained inside to the average color.
This would give you an image that is the same size as your input. You could of course resize your image first to a more appropriate output size.
You might want to look up convolution matrices.
In a shader, you would use your current pixel location to grab a set of nearby pixels from the original image to render to a pixel in a new buffer image.
It is actually just a slight variation of the Box Blur image processing algorithm except that instead of grabbing from the nearby pixels you would grab by the divisions of the original image relative to the 19x27 divisions of the resulting image.
Is there a special webGL trick to check if a texture contains at least one black rgb pixel, without having to read pixels on CPU ?
To me, it seems that checking pixels on CPU is the only solution. In this case,
is there a way for example, to compress a high resolution texture to a 1x1 texture containing a single boolean color information, so that I only have to read one single pixel for performance reason.
Thanks !
Only idea I have is erm... at least complex.
Lets say we have texture with dimension N, then:
Make canvas 1x1 pixel large.
Create array of N*N points, each point with different [x,y] attributes representing pixel position we will look for.
In vertex shader do texture lookup based on the point position. If the color of that pixel is not black then discard;
Set point position [0,0]
In fragment shader simply draw black color (assuming we have white canvas) for point.
Then what you have is 1x1 canvas with black color if there were any black pixels, or white color if there werent any and you can simply read it with cpu.
The bottle neck in this case is second step = point array building, and also cpu-gpu communication. This will run faster only if you need to do a lot of reads in short time and if you know size of the texture before the application runs so you can reuse same buffer for points for all textures.
Just idea, not sure if it would work.
Make a render target, draw your texture into it using a shader that draws white if the pixel is rgb 0,0,0 and black otherwise. Let's assume is 1024x768 and now has 1 white pixel. Draw that into a texture 1/4 it's size. In this case 512x384. With linear filtering on if we have the worst case, just 1 white pixel then it will average to 0.25 (63). We can do that 2 more times first to 256x192, then again 128x96. That one original white (255) pixel will now be (3). So run the black/white shader again and repeat 64x48, 32x24, 16x12, run the black/white shader, then again 8x6, 4x4, 2x2, run the black/white shader. Then 1x1. Now check If that's not pure black there was at least 1 black pixel.
Instead of doing a 1/2 size reduction each time you could try reducing those 3 levels into one by averaging a bunch of pixels in a shader. 15x15 pixels for example would still leave something > 0 if only 1 pixel was white and the rest black. In that case starting at 1024x768 it would be
1024x768 -> 67x52 -> 5x4 -> 1x1
I have no idea if that would be faster or slower.
Is there any way of labeling plots with images. For example, when I use the following:
plot(Y(:,1),Y(:,2),'o','LineWidth',2);
gname(names)
I can label each dot in a plot with a name. Is there any way to insert images instead of names?
It is possible, but not as convenient as gname by far. You can use the low-level version of image to insert images in your plot at arbitrary positions. Here's a simple example which puts the "Mandrill" image that comes with Matlab with its upper left corner pixel at the position (pi/2, 0):
% example plot
x = linspace(0, 2*pi, 100);
plot(x, cos(x))
% insert image
load mandrill
colormap(map)
image('CData', X, 'XData', [pi/2, pi/2 + 0.5], 'YData', [0, -0.3])
The result looks like this:
Problems with this approach:
There is no interactive point-and-click facility, you have to explicitly insert and position the image labels programmatically, or program such a point-and-click facility yourself. ginput might help doing so.
A figure window can only have one associated color map. That means if you have different images, they either all have to use the same colormap or have to be truecolor images.
Not just the position, but also the display size of the image has to be specified in the call to image, and both are by default specified with respect to the plot's coordinate system. This makes it hard to achieve the correct aspect ratio. You can switch (temporarily) to absolute units using the axes property 'Units' , but then you have to figure out the correct position in e.g. absolute millimeters or inches. Moreover, images are usually indexed with vertical coordinates increasing from top to bottom, while plots usually have vertical coordinates increasing from bottom to top. This is the reason for the negative value -0.3 in the 'YData' property above.
Alternatively, you can insert images each in their own little axes sitting on top of the plot's axes, which makes it easy to get the right orientation and aspect ratio using axis image. You'll still have the problem though to figure out the correct position for the axes.
Is it possible to display an image in multiple subplot axes, such that the image appears at the desired scale?
subplot(3,3,[1 4 7]);
%# image scaled down to fit 1 set of axes
imshow(img);
subplot(3,3,2);
plot(relevantData);
%# And so on with 5 other plots
I want to have the image scaled to either a fixed size or to fit the axes available to it, rather than to the size of a single axes.
My use case is to show a video alongside plots derived from the video, such that the plots are progressively drawn in step with the video. Once the display is correct I can save each image and combine them into a video.
Clarification
I am asking if it is possible to produce a figure as described without specifying the position of every element in absolute terms. Though one can make arbitrary figures that way (and in fact I have done so for this project), it is very tedious.
Edit:
For changing the size of the subplot:
In help subplot they mention that you can set parameters on the selected "axes" (that's what they call a plotting area in Matlab).
Using that, you can set the 'position', as seen in help axes. This property takes takes as argument:
[left, bottom, width, height]
As pointed out by #reve_etrange, one should use absolute positioning for axes 'Position'and 'OuterPosition' parameters. they can be in normalized coordinates, though.
For changing the size of the image in the subplot:
I think there are 2 useful things for you in the help imshow output:
'InitialMagnification': setting the magnification of the image.
'Parent': determines which parent imshow will use to put the image in (never tried using imshow with subplots).