Cross stitch in Matlab

A friend of mine said that she might start doing Cross Stitching and that she might want to do a drawing, image, or whatever. At that point I though "Well, I would have to create Matlab code to get any image and convert it to cross stitch." It turns out that I'm not the first to think about it.

But I'm not sure if I'm doing the right thing.

So let's illustrate with an example:

Suppose a pixelated image, any size, any color palette. for example the following screenshot from pixel artist WANEELLA

enter image description here

Suppose we don't want to scale the image, the result image will have the same number of pixels as the original (otherwise a will be executed imresize

).

Now the problem is using only the available color palette. I decided to use the DCM palette mainly because I found an RGB conversion.

I created color quantization. I am using Lab colors to find the closest color in the DCM palette and use that.

clear;clc;
% read image (its a gif)
[img,C]=imread('wn.gif');
% Convert it to RGBimage.
img2=img(:,:,:,3);

imgC=zeros([size(img2) 3]);

for ii=1:size(img2,1)
    for jj=1:size(img2,2)
        imgC(ii,jj,:)=C(img2(ii,jj)+1,:);
    end
end
img=imgC;
imshow(img)

% read DCMtoRB conversion
fid=fopen('DCMRGB.txt');
fgets(fid);
ii=0;
tline = fgets(fid);
while ischar(tline)
    ii=ii+1;
    table{ii}=tline;
    tline = fgets(fid);
end
fclose(fid);

for ii=1:size(table,2)
   DCMRGB(ii,1)=str2num(table{ii}(1:4));
   DCMRGB(ii,4)=hex2dec(table{ii}(end-5:end-4));
   DCMRGB(ii,3)=hex2dec(table{ii}(end-7:end-6));
   DCMRGB(ii,2)=hex2dec(table{ii}(end-9:end-8));
end

% origColous=reshape(img, [], 3);
Colours=double(unique(reshape(img, [], 3), 'rows'));
Ncol=size(Colours,1);



cform = makecform('srgb2lab');
DCMLab = applycform(DCMRGB(:,2:4)./255,cform);
Colourslab = applycform(Colours,cform);


eudist=@(p)sqrt(p(:,1).^2+p(:,2).^2+p(:,3).^2);
Cind=zeros(Ncol,1);

for ii=1:Ncol
    aux=ones(size(DCMLab,1),3);
    aux(:,1)=Colourslab(ii,1);
    aux(:,2)=Colourslab(ii,2);
    aux(:,3)=Colourslab(ii,3);
    d=eudist(DCMLab-aux);
    [~,Cind(ii)]=min(d);
end
% now DCMRGB will have  DCMcode, R, G, B
% Perform map conversion
img2=zeros(size(img));
indimg=zeros(size(img,1),size(img,2));
for ii=1:size(img,1)
    for jj=1:size(img,2)
        %wich colour is the pixel?
        [~,indx]=ismember(double(squeeze(img(ii,jj,:)))',Colours,'rows'); 
        indimg(ii,jj)=Cind(indx);
        img2(ii,jj,:)=DCMRGB(Cind(indx),2:4);
    end
end


%%
subplot(121)
imshow((img))
% subplot(222)
% [X_dither,map]=rgb2ind(img,DCMRGB(:,2:4)./255,'nodither');
% imshow(uint16(X_dither),map);

subplot(122)
imshow(double(img2)./255)

      

The result looks like this:

enter image description here However, on this web page: http://www.picturecraftwork.com/ As you can see, the color choices are different on the web page and it actually makes more sense and it feels good even without a real color map.

After a lot, I believe there may be two main things that I need to change and implement.

1.- I don't 100% trust the DCMRGB values. I emailed the company looking for more details on theyr color palette.

2.- The values ​​of brightness, contrast, hue and saturation have a huge impact on the output.

how can I change these 4 values ​​(like on a webpage) in the image I want using Matlab?



DMC2RGB file: (you can copy it here if needed)

http://pastebin.com/qixUgnvy

DCM color palette:

enter image description here

+3


source to share


1 answer


Okay, here's a generalized proposal, although I haven't had great results yet.

1) Start by reducing the original image to a reasonable number of colors rgb2ind

with using nodither

, specifying only the number of colors (not used card).

[I_ind, old_map] = rgb2ind(I,64,'nodither);

      

You can experiment with the number of colors for a given image without losing too much detail. Basically you want to figure out how many unique colors you need in the first place (seeing that you are cross-stitching the output you don't need a bunch of colors that are only used for three stitches each).

2) Convert both maps (the ones the output rgb2ind

and the one you load from dcm to the rgb file) to the appropriate color space (I used HSV because I felt lazy L*a*b

probably better).

3) Pick colors by checking which indexed colors have the most pixels, pick the closest one and then remove that color from the candidate list so we end up with 64 or others

% use histogram and sorting - assign colours to most common values first
[plist pbins] = hist(I_ind(:),0:63);
[plist_sorted, sort_ind] = sort(plist, 'descend');

% old_map = the output of rbg2ind
% new_map = the new one we're about to make
% dcm_map = (copy of!) the dcm map in the same colorspace 
new_map = zeros(size(old_map)); 

% loop through from most to least common, remove a colour from the dcm map if we've used it.
for n = 1:sort_ind
   D = pdist2(old_map(n,:),dcm_map);
   m = find(D==min(D),1,'first');
   new_map(n,:) = dcm_map(m,:);
   dcm_map(m,:) = [];
end

      



I used the image you used to answer the question. Since this comes out of rgb2ind

:

pixel image with 64 colors

How does it end up with 64 DCM colors (bit off, probably because my comparison choice is wrong, but guaranteed to have 64 distinct dcm colors).

pixel image with 64 dcm colors

I assume you need to find the correct weighting of the different factors (you can easily add the weighting function to pdist2

). For example, weighing the HSV as [0.8, 0.1, 0.1] gave me this brilliant madness:

enter image description here

+1


source







All Articles