How do I reduce the number of points in a plotted trace?
6 views (last 30 days)
Show older comments
Hello,
I am trying to create an algorithm that converts an image of a black and white tracing into a plot. So far, my code can convert the image into points using the code:
lion = imread('lion.png')
r = 1024;
c = 768;
count = 1;
for i = 1:r
for j = 1:c
if lion(i,j,1) ~= 255
%lion
lion_y(count) = -i + 1000;
lion_x(count) = j;
end
count = count + 1;
end
end
plot(lion_x,-lion_y,'.')
It can successfully convert the png into plotted points (I have attached the png to this posting as well):
--->
But, when zooming in, the line is composed of multiple points to make it appear thicker:
How would I create a trace of these points (perhaps some sort of average?) so that the image can be reduced to a single-point width?
so that the final image would look something like this:
This was made by manually outlining the trace using ginput(). This is not the ideal approach because it is not as accurate and it would be time consuming for processing over 100 images. Is there a way to automate this process?
I tried using the boundry function but it did not capture the details inside the image. It also didn't have a high enough resolution to capture the sharp edges (like in the mane).
Thank you for your help!
0 Comments
Accepted Answer
DGM
on 26 Aug 2021
Edited: DGM
on 26 Aug 2021
I don't know of any simple means to convert an image into a minimal line drawing. Features like the intersection of the facial lines with the nose or the intersection of the tail lines with the tuft are structurally the same -- they're a transition between a constant-width line and a solid region. Yet whatever operation we use must somehow recognize that they are to be handled in completely different ways and interpret where the stroke should be. I don't know that basic filtering or morphological operations can do that neatly and consistently.
Something like this might work, but it's going to collapse some solid features.
% read image, convert to a logical image
A = rgb2gray(imread('lion.png'))<127;
% reduce line width
B = bwmorph(A,'thin',Inf);
% display the image
imshow(~B); hold on
This is a little bit better at not collapsing cusps, but it leaves them heavy. That's not much better.
A = rgb2gray(imread('lion.png'))<127;
D = bwdist(bwperim(A,4));
C = (D>4 & D<7) & A;
C = bwmorph(C,'thin',Inf);
C = ~bwareaopen(~C,500,4);
Other methods still have similar issues with thick cusps. This destroys open curves and still leaves small islands.
A = rgb2gray(imread('lion.png'))>127;
[L nb] = bwlabel(A);
st = strel('disk',11);
B = false(size(A));
Bm = false(size(A));
for b = 1:nb
% dilate each blob
thisblob = L == b;
thisblob = imdilate(thisblob,st);
% and trim it against the others
maskedblob = thisblob & ~Bm;
Bm = Bm | thisblob;
maskedblob = bwperim(maskedblob);
B = B | maskedblob;
end
B = bwmorph(B,'thin',Inf);
B = imclearborder(B);
Like I said, I don't know of a good way to do this. Maybe someone else does.
The above examples should give you a line image without any need for finding coordinates. If you really truly want to use plot(), just use find(), since B is already a logical image.
% or if you really want to use xy coordinates
[y x] = find(B);
plot(x,y,'.')
2 Comments
DGM
on 28 Aug 2021
Edited: DGM
on 28 Aug 2021
Your images are both different sizes. The output image should be the same size as the original. I don't know whether that's because your source is a different size or because you're saving the figure.
If it's because your source image was a different size, then you might have to adjust some parameters. Things like the strel diameter in this version depend on the line thickness.
If you're saving the figure, don't do that. Save images using imwrite(). Saving the figure means that the saved image is dependent on the figure geometry and is subject to destructive nearest-neighbor interpolation. It's tantamount to a screenshot. With single-pixel features like those in these images, lines simply disappear, so if that's what's going on, the result will make it hard to tell.
For example, this is the same code running on the web-version with the attached source image:
A = rgb2gray(imread('lion.png'))>127;
[L nb] = bwlabel(A);
st = strel('disk',11);
B = false(size(A));
Bm = false(size(A));
for b = 1:nb
% dilate each blob
thisblob = L == b;
thisblob = imdilate(thisblob,st);
% and trim it against the others
maskedblob = thisblob & ~Bm;
Bm = Bm | thisblob;
maskedblob = bwperim(maskedblob);
B = B | maskedblob;
end
B = bwmorph(B,'thin',Inf);
B = imclearborder(B);
size(A)
size(B) % same size as source
imshow(~B)
Since the displayed image is subject to nearest-neighbor interpolation and it's been downscaled, most of it disappears. If you saved the figure at this point, that's all you'd get. If you were able to zoom in on it, you'd see what's missing.
clf
imshow(~B(100:400,100:400))
That's just my guess.
More Answers (0)
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!