Hi Shivu Shetty
to acquire center and surface points on the image, use the attached ginputRed.m that has red crosshairs, as the standard ginput.m does not allow to change color, and there is no switch in figure, axes or plot handles to change crosshair color.
More images uploaded as soon as 10 uploads per day cap reloaded.
1.-
acquiring one of your start images:
clear all;close all;clc
A=imread('001.jpg');
A1=A(:,:,1);
hf1=figure(1);imshow(A1);ax1=hf1.CurrentAxes;
2.-
adjusting contrast
A02=imadjust(A1,[.81;.89],[0;1]);
hf2=figure(2);h_im=imshow(A02);ax2=hf2.CurrentAxes;
3.-
trying surf
dx1=1;
[X,Y]=meshgrid([1:dx1:size(A1,2)],[1:1:size(A1,1)]);
surf(X,Y,255-A02,'EdgeColor','none')
.
.
surf has all rings clipping the roof of 255, which is good to count tree rings.
surf(255-A02) better than surf(A02)
.
.
yet one wonders if the rings could be a bit thicker to count them and if it is possible to have all rings with the highest amplitude, to avoid false counts, or missing rings
4.-
trying interpolation in case there's need for more samples
some ring peaks look too sharp with only one sample and many rings do really have a low level:
dx2=.1;
[Xq,Yq]=meshgrid([1:dx2:size(A1,2)],[1:dx2:size(A1,1)]);
A02q=interp2(X,Y,double(255-A02),Xq,Yq);
hf3=figure(3);surf(Xq,Yq,255-A02q,'EdgeColor','none');
comparing,
.
.
no discernible difference, still some peaks to sharp, some other peaks too low
5.-
let's carry on with fence-like rings as peaks, better than narrow trenches in A02
6.-
thresholding
there are some really low yet valid peaks too close to false peaks
A03(A03>=125)=255;A03(A03<125)=0;
7.-
trying single straight cross section, centre to outer crust
hf4=figure(4);hsf2=surf(Xq,Yq,A03,'EdgeColor','none');
ax4=hf4.CurrentAxes
ax4.DataAspectRatio=[1 6 1]
ax4.DataAspectRatio=[1 1 1]
campos(ax4,[250 250 3664])
how to fix ginput figure axes and plot handles not having switch for crosshair colour:
.
p=ginputRed(2)
p=floor(p)
nx=floor(linspace(p(1,1),p(2,1),max(abs(p(1,1)-p(2,1)),abs(p(1,2)-p(2,2)))))
ny=floor(linspace(p(1,2),p(2,2),max(abs(p(1,1)-p(2,1)),abs(p(1,2)-p(2,2)))))
hold(ax4,'on');plot(ax4,nx,ny,'r-');plot(ax4,[p(1,1) p(2,1)],[p(1,2) p(2,2)],'ro')
.
.
L=[];
for k=1:1:numel(nx)
L=[L A1(ny(k),nx(k))]
end
figure(5);plot(L);grid on
figure(6);plot(diff(L));grid on
.
cross sections shown in 005 and 006 above
it still doesn't get the count to the comfortable place where rings are clear tall peaks and everything else far enough below to avoid confusion.
Yet, surf has coloured the rings clearly yellow, away to everything else in magenta, let's exploit this
8.-
Isolating yellow pixels
saveas(hf4,'tree_rings_yellow.jpg')
close all;clear all;clc
A20=imread('tree_rings_yellow.jpg');
hf1=figure(1);imshow(A20);ax1=hf1.CurrentAxes
.
.
A13=A20(:,:,1)-A20(:,:,3);
[x13,y13]=find(A13>30);
hold(ax1,'all');figure(2);h1=plot(ax1,y13,x13,'r.')
axis(ax1,[325 684 349 686])
the previous was marking ring pixels red, just to make sure marking the right pixels
9.-
solving the too short peaks, we need tall peaks against everything else for such purpose let's binarize
B=zeros(size(A20(:,:,1)));
for k=1:1:numel(x13)
B(x13(k),y13(k))=1;
end
hf2=figure(2);imshow(B);
ax2=hf2.CurrentAxes
axis(ax2,[325 684 349 686])
10.-
Now let's use flexible cross section, let's zig-zag, no need to count rings while pulling the cross section line,
but let's make sure that each straight section of cross section clearly gets one or more tree ring and if not just for clarity, that new sections start in between cross sections
p2=ginputRed
p2=floor(p2)
n=[p2(1,1) p2(1,2)];
for k=1:1:size(p2,1)-1
nx_section=floor(linspace(p2(k,1),p2(k+1,1),max(abs(p2(k,1)-p2(k+1,1)),abs(p2(k,2)-p2(k+1,2)))));
ny_section=floor(linspace(p2(k,2),p2(k+1,2),max(abs(p2(k,1)-p2(k+1,1)),abs(p2(k,2)-p2(k+1,2)))));
n=[n;nx_section' ny_section'];
end
n(1,:)=[];
hold(ax2,'all');
plot(ax2,p2(:,1),p2:,2),'r-','LineWidth',4);
plot(ax2,[p2(1,1) p2(end,1)],[p2(1,2) p2(end,2)],'ro','LineWidth',4);
variable peaks of interest amplitude solved, now all rings are 1s, and all space between rings are 0s
L=[];
for s=1:1:size(n,1)
L=[L B(n(s,2),n(s,1))];
end
mind the gap attempting the reading loop with B(n(s,1),n(s,2)) a result that looks ok is reached but neither the amount of rings nor the initial values of the cross section are correct.
figure(3);plot(L','r','LineWidth',3);grid on
.
counting peaks
.
[pks,locs]=findpeaks(L)
pks =
Columns 1 through 9
1 1 1 1 1 1 1 1 1
Columns 10 through 17
1 1 1 1 1 1 1 1
locs =
Columns 1 through 9
60 118 165 210 260 297 319 338 364
Columns 10 through 17
375 382 397 411 421 434 442 453
.
And the result is:
.
amount_rings=numel(pks)
=
17
.
Shivu
if you find this answer useful would you please be so kind to consider marking my answer as Accepted Answer?
To any other reader, if you find this answer useful please consider clicking on the thumbs-up vote link
thanks in advance for time and attention
John BG
.