Replace pixels with symbols - matlab

I am trying to write a function that would take an indexed image as an input and will replace all its pixels by symbols or characters.
An image is worth more than a 1000 words: This is the desired look output. Each of the symbols represent an unique color value of the image.
My problem is that I don't know how to print in the screen the symbols in the correct place. My first approach has been to use the "Wingdings" font and to put text on the places, but does not work as expected. The text changes sizes when zoomed, and does not behave accordingly to the rest of the plot.
I leave here a small piece of code that creates a small grid and uses an example image.
function drawChars (img)
if nargin==0
load mandrill
img=X(1:4:end,1:4:end);
end
chars=randperm(numel(unique(img)));
[h,w]=size(img);
% Form a grid
figure
hold on
for ii=0:h
plot([ii ii],[0 w],'k');
end
for ii=0:w
plot([0 h],[ii ii],'k');
end
axis equal;
axis([0 h 0 w])
%% This does not work as expected
for ii=1:h
for jj=1:w
text(ii, jj, char(chars(img(ii,jj))), 'fontname', 'Wingdings', 'fontsize',10);
end
end
end
Short question: What approach would you use to solve the problem?
NOTE: there is a problem with the choice of chars also, but ignore it for the time being (if char { is chosen does not work nicely)

With figure changed to f=figure
r=size(img).*16;
set(f,'paperunits','points')
set(f,'papersize',r)
set(f,'paperposition',[0 0 r]);
print(f,'example.png','-dpng');
Prints the created figure to a png of sufficient size.

Related

MATLAB axes colors change when writing a GIF

Relevant Information: MATLAB R2015b, Mac
I am currently trying to write a GIF from a series of datasets (txt files) I took. I have no trouble writing the GIF file, however, when played back (in PowerPoint) or previewed in the OS X Finder, the axes labels change in color. In addition to the color change, I receive this warning:
Warning: Image data contains values that are out of range. Out of range values will be given the nearest valid value.
Currently, I grab all the data files in the directory, plot them, grab each frame, and put them into a GIF. Here is my code:
%Create MATLAB movie from plots
clearvars
%addpath('C:\Users\ucmuser\Documents\MATLAB')
filename='cooldown_movie.gif';
ext_in='txt';
[~,listing]=f_search(ext_in);
[r,~]=size(listing);
listing=natsortfiles(listing);
F=figure;
%r=20 is used for quick debugging (original is 460 files).
r=20;
% y=linspace(1,2*pi,100);
% x=linspace(1,100,100);
%C(1,1,1,r)=0;
for i=1:r
A=dlmread(listing{i});
listing{i}=strrep(listing{i},'_','\_');
x=A(1,:); %X Array
y=A(2,:); %Y Array
plot(x./1E9,y.*1E3,'-','LineWidth',1.2,...
'Color',[0.8500 0.3250 0.0980]);
grid off
xlabel('Frequency (GHz)','FontSize',18,'FontWeight','bold')
ylabel('Voltage (mV)','FontSize',18,'FontWeight','bold')
title('Cooldown Movie','FontSize',24,'FontWeight','bold')
G(i)=getframe(gcf);
drawnow
frame = G(i);
% im = frame2im(frame);
[C(:,:,1,i),map] = rgb2ind(frame.cdata,256,'nodither');
% if r == 1;
% imwrite(C,map,filename,'gif','LoopCount',Inf,'DelayTime',0);
% else
% imwrite(C,map,filename,'gif','WriteMode','append','DelayTime',0);
% end
end
imwrite(C,map,filename,'gif','LoopCount',Inf,'DelayTime',0);
A sample image is shown below. The axes labels change in color. If I turn on the grid, the effect is even more apparent with the grid changing in grayscale intensity. I've tried setting limits and the effect is still present.
I've found a solution for the time being although I'm not quite sure why it works. I started going through the figure properties and turned off the GraphicsSmoothing property (type F=figure;F.GraphicsSmoothing='off'; before the "for loop"). This seemed to fix the problem as well as clear the original out of range error.
With the GraphicsSmoothing property turned "on" and going through the first 20 data files, I have a maximum indexed color value of 22 via max(max(max(C))). Performing the same code with the GraphicsSmoothing turned "off" yields a maximum value of 4.
I am attaching two images displaying the extreme color differences with the GraphicsSMoothing turned on and off.
GraphicsSmoothing turned On (default)
GraphicsSmoothing turned Off
If someone knew why this is the case, I would greatly appreciate it.
UPDATE: I attempted to use this solution with grid on and the background border turned orange. I am confused on this whole issue.

how can i apply exact dct2 on 8x8 blocks and display them in subplots?

I=imread('ft.jpg');
[a b]=size(I);
figure;imshow(I);
j=rgb2ycbcr(I);
[m n]=size(j);
figure;
imshow(j);
ca=mat2cell(j,8*ones(1,size(j,1)/8),8*ones(1,size(j,2)/8),3);
p = 1;
figure;
figure;
X=ones(m,n,8,8);
for c=1:size(ca,1)
for r=1:size(ca,2)
temp=zeros(8,8,'uint8');
temp(:,:)=X(c,r,:,:);
temp=temp-128;
temp=dct2(temp);
subplot(size(ca,1),size(ca,2),temp(:,:)); %// Change
imshow(ca{c,r});
p=p+1;
end
end
the error is:
Error using ==> subplot at 309
Illegal plot number.
Error in ==> project at 22
subplot(size(ca,1),size(ca,2),temp(:,:)); %// Change
That's because you're not calling subplot properly. It needs p as the parameter for the third argument, not temp. p determines which slot you want to place your figure in. You putting in a doublevector as the third parameter makes no sense. Also, ca contains 8 x 8 pixel blocks, and you'd like to show the DCT of each block. Your current code does not do this. Actually, X is what you're trying to find the DCT of, and it's all ones.... doesn't make much sense.
You probably want to show the DCT of each block inside the figure as well, not ca.... and so you need to do this:
for c=1:size(ca,1)
for r=1:size(ca,2)
temp = double(ca{c,r}); %// Change - cast to double for precision
temp=temp-128;
temp=dct2(temp);
subplot(size(ca,1),size(ca,2),p); %// Change
imshow(temp,[]); %// Change here too
p=p+1;
end
end
Note that I did imshow(temp,[]); so that we can contrast stretch the block so that the minimum value gets mapped to black while the maximum value gets mapped to white. Everything else is a shade of gray in between. Be advised that this doesn't change the image itself. It only changes it for display.
Suggestion
You should read up on my post on how subplot works here: How does subplot work and what is the difference between subplot(121) and subplot(1,2,1) in MATLAB?
Once you read through this post, you'll have a better understanding of how each parameter works for subplot, and how you can display graphs / images in a figure.
Minor Note
Looks like you took that code from this post but you didn't copy and paste properly :) That %// Change comment, as well as the variable name ca looked oddly familiar.

Matlab, gplot custom linewidth for some lines, but not all

In the past, there has been asked a question about customizing the linewidth in gplot (see In MatLab, how to adjust the line width drawn by the function 'gplot'?). I am dealing with a slightly more complicated version, which prevents me from using the solution given there. Therefore, I would like to ask how to do the following: I would like to adapt the line width of some of the calls of gplot, and not of others. I am namely calling gplot several times and using hold on to plot them in one figure. I am trying to draw a graph, with multiple types of edges (A and A2). And k paths in it. I am currently using the following code:
figure
hold on
gplot(A,coor,'k*:')
gplot(A2,coor,'k-')
plot(coor(T,1),coor(T,2),'k.','MarkerSize',20)
plot(coor(T,1),coor(T,2),'bo','MarkerSize',20)
% a line where I define my own colors (not shown, since not relevant)
set(gca,'ColorOrder',colors)
hold all
for i=1:k
gplot(Path,coor)
end
hold off
But I would like to draw the paths with a larger line width, while keeping the A and A2 at the standard line width 1.
Can someone help me? Thank you very much!
You can get the children of the axis before and after adding the extra lines, and only set the new ones to have a larger linewidth:
figure
hold on
gplot(A,coor,'k*:')
gplot(A2,coor,'k-')
plot(coor(T,1),coor(T,2),'k.','MarkerSize',20)
plot(coor(T,1),coor(T,2),'bo','MarkerSize',20)
ChildrenBefore=get(gca,'children');
% a line where I define my own colors (not shown, since not relevant)
set(gca,'ColorOrder',colors)
hold all
for i=1:k
gplot(Path,coor)
end
hold off
ChildrenAfter=get(gca,'children');
NewChildren=setdiff(ChildrenAfter,ChildrenBefore);
set(intersect(findall(gcf,'type','line'),NewChildren),'LineWidth',5)

Printing figure at same size as figure window

I'm trying to save a figure in PDF format such that I don't get extraneous white space around it, i.e. the figure should be the same size as the figure window.
I'm pretty sure that the way to do it is
figureNames = {'a', 'b', 'c'};
for i = 1:3
set(figure(i), 'paperpositionmode', 'auto');
print(figure(i), '-dpdf', figureNames{i})
end
But it's not working. I'm getting as much white space as ever. Can someone enlighten me as to what's wrong?
You can try "all in one" solutions for converting figures to pdf-files. I use mlf2pdf
(http://www.mathworks.com/matlabcentral/fileexchange/28545) and it seems to work quite well. Moreover, the quality of the produced figures is much better due to Latex typesetting of everything
I've also had issues with this. The workaround is by printing in -depsc (color) or -deps if you just need grayscale figures. The encapsulated postscript file has practically no white margin. You can later convert the .eps file to pdf without trouble, if you working in LaTeX you can use it as it is.
It seems that setting PaperPositionMode to auto will get rid of extraneous white space for EPS files, but not PDF's.
To get rid of white space for PDF's, I wrote a little script to resize the paper to the figure size. Since it's so short, I've included it below in case anyone else needs it.
It is inspired by this document, as well as this StackOverflow question.
My solution works by manipulating only the paper size, not the figure axes, because manipulating the axes runs into trouble with subplots. This also means that some white space will remain. In MATLAB's vocabulary, the figures is bounded by its OuterPosition rather than TightInset.
function [filename] = printpdf(fig, name)
% printpdf Prints image in PDF format without tons of white space
% The width and height of the figure are found
% The paper is set to be the same width and height as the figure
% The figure's bottom left corner is lined up with
% the paper's bottom left corner
% Set figure and paper to use the same unit
set(fig, 'Units', 'centimeters')
set(fig, 'PaperUnits','centimeters');
% Position of figure is of form [left bottom width height]
% We only care about width and height
pos = get(fig,'Position');
% Set paper size to be same as figure size
set(fig, 'PaperSize', [pos(3) pos(4)]);
% Set figure to start at bottom left of paper
% This ensures that figure and paper will match up in size
set(fig, 'PaperPositionMode', 'manual');
set(fig, 'PaperPosition', [0 0 pos(3) pos(4)]);
% Print as pdf
print(fig, '-dpdf', name)
% Return full file name
filename = [name, '.pdf'];
end

Adding letters to 3D plot data points in Matlab

I am currently working on a 3D representation of a hand fingers moving. You can see on the picture below how it looks like, since it would be too complicated to describe otherwise:
It is an animation, so it's moving constantly. There is one dot for each finger, and one dot for the palm. However, I can't keep track of the fingers. I tried to give them different colors, but it doesn't help a lot.
So the question is:
Is there a way to replace the circles, or any other symbol, with an actual letter, or even short word (3-4 letters)?
Alternatively (and it is quite a stretch, but why not ask?), would there be a way to draw lines joining these dots together? This is optional, and I might open another question regarding it if necessary.
Thanks!
Here is the actual code; I know it is far from being elegant coding, and am sorry about it, but it works, which is already a great step for me:
clear all
clc
csv=csvread('pilot6/maindroite.csv',1,0); %read the values from a csv
both = csv(:,2:19);
ax=axes;
set(ax,'NextPlot','replacechildren');
Dt=0.1; %sampling period in secs
k=1;
hp1=plot3(both(k,1),both(k,2),both(k,3),'ok'); %get handle to dot object
hold on;
hp2=plot3(both(k,4),both(k,5),both(k,6),'og');
hp3=plot3(both(k,7),both(k,8),both(k,9),'ob');
hp4=plot3(both(k,10),both(k,11),both(k,12),'oc');
hp5=plot3(both(k,13),both(k,14),both(k,15),'om');
hp6=plot3(both(k,16),both(k,17),both(k,18),'or');
hold off;
t1=timer('TimerFcn','k=doPlot(hp1,hp2,hp3,hp4,hp5,hp6,both,t1,k)','Period', Dt,'ExecutionMode','fixedRate');
start(t1);
and the function used:
function k=doPlot(hp1,hp2,hp3,hp4,hp5,hp6,pos,t1,k)
k=k+1;
if k<5000%length(pos)
set(hp1,'XData',pos(k,1),'YData',pos(k,2),'ZData',pos(k,3));
axis([0 255 0 255 0 255]);
set(hp2,'XData',pos(k,4),'YData',pos(k,5),'ZData',pos(k,6));
set(hp3,'XData',pos(k,7),'YData',pos(k,8),'ZData',pos(k,9));
set(hp4,'XData',pos(k,10),'YData',pos(k,11),'ZData',pos(k,12));
set(hp5,'XData',pos(k,13),'YData',pos(k,14),'ZData',pos(k,15));
set(hp6,'XData',pos(k,16),'YData',pos(k,17),'ZData',pos(k,18));
else
k=1;
set(hp,'XData',pos(k,1),'YData',pos(k,2),'ZData',pos(k,3));
axis([0 255 0 255 0 255]);
end
I just want to mention this is based heavily on Jorge's answer on this question, so thanks to him again
text(x,y,z,'string') instead of plot3 should work in changing the points to text where [x,y,z] is the coordinate of each point you are plotting.
Note: calls to set will need to change from set(hp3,'XData',x,'YData',y,'ZData',z) to set(htext,'pos',[x,y,z]). Where hp3 is the handle to a plot3-handle object and htext is a handle to a text-handle object.
To connect the points with a line use plot3(X,Y,Z) where X=[x_1,x_2,...,x_n], Y=[y_1,y_2,...,y_n] and Z=[z_1,z_2,...,z_n].