Compute laplacian using gradient - matlab

I'm trying to get Laplacian using 3 different method, in case 1 and 2 results the same but what is wrong with 3?
Here is code in Matlab:
m= magic(6)
Lap1Dx= convn(m,[-1 2 -1],'same')
Lap1Dy= convn(m,[-1;2;-1],'same')
%ver1
Lap2Dxy= convn(m,[0 -1 0;-1 4 -1;0 -1 0],'same')
%ver2
Lap2Dxy= Lap1Dx+Lap1Dy %same as ver 1
%ver 3
%get laplacian using gradients
gradx= convn(m,[-1 1],'same')
grady= convn(m,[-1;1],'same')
gradxx= convn(gradx,[-1 1],'same')
gradyy= convn(grady,[-1;1],'same')
Lap2Dxy= gradxx+gradyy
Output:
m =
35 1 6 26 19 24
3 32 7 21 23 25
31 9 2 22 27 20
8 28 33 17 10 15
30 5 34 12 14 16
4 36 29 13 18 11
Lap1Dx =
69 -39 -15 27 -12 29
-26 54 -39 12 0 27
53 -15 -27 15 12 13
-12 15 21 -9 -12 20
55 -54 51 -24 0 18
-28 39 9 -21 12 4
Lap1Dy =
67 -30 5 31 15 23
-60 54 6 -6 0 6
51 -42 -36 6 21 0
-45 42 30 0 -21 -6
48 -54 6 -6 0 6
-22 67 24 14 22 6
Lap2Dxy =
136 -69 -10 58 3 52
-86 108 -33 6 0 33
104 -57 -63 21 33 13
-57 57 51 -9 -33 14
103 -108 57 -30 0 24
-50 106 33 -7 34 10
Lap2Dxy =
136 -69 -10 58 3 52
-86 108 -33 6 0 33
104 -57 -63 21 33 13
-57 57 51 -9 -33 14
103 -108 57 -30 0 24
-50 106 33 -7 34 10
gradx =
34 -5 -20 7 -5 24
-29 25 -14 -2 -2 25
22 7 -20 -5 7 20
-20 -5 16 7 -5 15
25 -29 22 -2 -2 16
-32 7 16 -5 7 11
grady =
32 -31 -1 5 -4 -1
-28 23 5 -1 -4 5
23 -19 -31 5 17 5
-22 23 -1 5 -4 -1
26 -31 5 -1 -4 5
4 36 29 13 18 11
gradxx =
39 15 -27 12 -29 24
-54 39 -12 0 -27 25
15 27 -15 -12 -13 20
-15 -21 9 12 -20 15
54 -51 24 0 -18 16
-39 -9 21 -12 -4 11
gradyy =
60 -54 -6 6 0 -6
-51 42 36 -6 -21 0
45 -42 -30 0 21 6
-48 54 -6 6 0 -6
22 -67 -24 -14 -22 -6
4 36 29 13 18 11
Lap2Dxy =
99 -39 -33 18 -29 18
-105 81 24 -6 -48 25
60 -15 -45 -12 8 26
-63 33 3 18 -20 9
76 -118 0 -14 -40 10
-35 27 50 1 14 22

First of all, there are some sign issues. Convolving with [-1 1] gives you the first derivative with the minus sign: convolution flips one of two arrays so you end subtracting each element from the following one. Convolve with [1 -1] to get the first derivative. For the second derivative, use [1 -2 1].
But the main issue here has to do with truncation ('same' parameter). With the first two approaches, you convolve and then truncate. With the third, you convolve, then truncate, then convolve again and truncate again.
Since the issue can be seen already on a one-dimensional array, I'll focus on the first row of yours. Let's drop the parameter same for now:
m = [35 1 6 26 19 24]
mx = convn(m,[1 -1]) // [35 -34 5 20 -7 5 -24]
mxx = convn(mx,[1 -1]) // [35 -69 39 15 -27 12 -29 24]
m2x = convn(m,[1 -2 1]) // [35 -69 39 15 -27 12 -29 24]
As you can see, the results are identical. Next, with the 'same' parameter:
mx = convn(m,[1 -1],'same') // [-34 5 20 -7 5 -24]
mxx = convn(mx,[1 -1],'same') // [39 15 -27 12 -29 24]
m2x = convn(m,[1 -2 1],'same') // [-69 39 15 -27 12 -29]
For m2x, 'same' cleanly picks the middle part of the full convolution, which is exactly the part you want.
But for the first-order derivative, there is just one element to drop. The choice has to be made, and convn drops the first one (resulting in the forward difference). When computing mxx, it has to do it again. So, as a result of dropping the first element of full convolution twice, you end up with a shifted array. This is why mxx has most of the same numbers as m2x, except misaligned.
If you insist on having two-step convolution (first derivative, then second), the first convolution must be without any truncation. Otherwise, the truncation influences the result of the second convolution. For the second one, you can use 'same' but in addition, the last element will need to be dropped. Like this.
mx = convn(m, [1 -1])
mxx = convn(mx,[1 -1],'same')
mxx = mxx(1:end-1)
Or, equivalently,
mx = convn(m, [1 -1])
mxx = convn(mx,[1 -1])
mxx = mxx(2:end-1)

Related

Density plot of a matrix

I have a 100x200 matrix and I would like to show this matrix as a density plot. Here is a 8x10 sample.
X = [104 122 138 159 149 167 184 164 190 158; ...
54 42 55 55 63 75 72 73 66 76; ...
15 22 28 21 23 28 32 47 32 40; ...
18 12 20 22 28 17 30 17 22 18; ...
10 7 14 10 14 11 14 20 16 10; ...
5 6 3 3 6 12 6 2 8 9; ...
4 8 9 2 5 3 3 12 7 7; ...
6 6 2 3 10 1 9 8 11 8]
I have tried to use functions like bar3, surf, hist and so on but they don't have the end result I am after.
I would also like to represent the y axis on the new successful plot to be on a log axis. So similar to having semilogy(x,y,'rx') for example.
Are there any other methods I could use?
How about "surf" it like a spectrogram?
XX = log([104 122 138 159 149 167 184 164 190 158;
54 42 55 55 63 75 72 73 66 76;
15 22 28 21 23 28 32 47 32 40;
18 12 20 22 28 17 30 17 22 18;
10 7 14 10 14 11 14 20 16 10;
5 6 3 3 6 12 6 2 8 9;
4 8 9 2 5 3 3 12 7 7;
6 6 2 3 10 1 9 8 11 8]
figure
surf(XX, 'edgecolor', 'none'); view(0,90); axis tight;
xlabel ('x')
ylabel ('y')
NOTE:The first row represent the first row (104,122,138...)
and row 8 represent row 8 (6,7,2....)
Dark red = high value
light blue = low value
Matlab also provides a heatmap function.
>> X = [104 122 138 159 149 167 184 164 190 158; ...
54 42 55 55 63 75 72 73 66 76; ...
15 22 28 21 23 28 32 47 32 40; ...
18 12 20 22 28 17 30 17 22 18; ...
10 7 14 10 14 11 14 20 16 10; ...
5 6 3 3 6 12 6 2 8 9; ...
4 8 9 2 5 3 3 12 7 7; ...
6 6 2 3 10 1 9 8 11 8];
>> heatmap(X)
ans =
HeatmapChart with properties:
ColorData: [8×10 double]
Show all properties
The following plot appears:

MATLAB: How to make 2D binary mask from mesh?

I'm using MESH2D in Matlab in order to mesh ROI (Region Of Interest) from images. Now I would like to make binary masks from these triangular meshes. The outputs from [p,t] = mesh2d(node) are:
p = Nx2 array of nodal XY co-ordinates.
t = Mx3 array of triangles as indicies into P, defined with a counter-clockwise node ordering.
Example of an initial code (feel free to improve it!):
mask= logical([0 0 0 0 0; 0 1 1 0 0; 0 1 1 1 1; 0 1 1 0 0]) %let's say this is my ROI
figure, imagesc(mask)
lol=regionprops(mask,'all')
[p,t] = mesh2d(lol.ConvexHull); %it should mesh the ROI
How to make masks from this triangular mesh?
Thank you in advance!
This is p:
1,50000000000000 2
1,50000000000000 2,50000000000000
1,50000000000000 3
1,50000000000000 3,50000000000000
1,50000000000000 4
1,93703949778653 2,56171771423604
1,96936200278303 3,98632617574682
2 1,50000000000000
2 4,50000000000000
2,00975325040940 3,53647067507122
2,01137717786904 2,05700769275495
2,05400996239344 3,03376821385856
2,41193753423879 2,49774899749798
2,45957145752038 3,46313210038859
2,50000000000000 1,50000000000000
2,50000000000000 4,50000000000000
2,51246316199066 3,99053096338726
2,56500321259084 1,97186739050944
2,64423955240966 2,98576823004855
3 1,50000000000000
3 4,50000000000000
3,00248771086621 2,47385860181019
3,01650848812758 3,52665319517610
3,08981230082503 3,98949609178151
3,12731558449295 2,02370031640169
3,36937385842331 2,99811446160210
3,50000000000000 1,75000000000000
3,50000000000000 4,25000000000000
3,85193739480358 3,46578962137238
3,85353024582881 2,53499308989903
4 2
4 4
4,42246720814684 3,00037409439956
4,50000000000000 2,25000000000000
4,50000000000000 3,75000000000000
4,97304775909580 2,99999314296989
5 2,50000000000000
5 3,50000000000000
5,50000000000000 3
and t:
9 5 7
20 18 15
1 8 11
8 15 11
11 15 18
11 2 1
6 2 11
20 27 25
25 18 20
27 30 25
17 10 14
7 10 17
24 21 17
9 7 17
29 35 32
26 30 29
23 19 26
14 19 23
26 29 23
23 29 24
23 17 14
24 17 23
6 11 13
13 11 18
34 30 31
31 30 27
3 2 6
12 19 14
14 10 12
6 13 12
12 13 19
12 3 6
28 21 24
28 29 32
24 29 28
9 17 16
16 17 21
38 35 33
35 29 33
33 29 30
34 37 33
33 30 34
19 13 22
26 19 22
18 25 22
22 13 18
22 30 26
22 25 30
4 7 5
4 10 7
4 12 10
3 12 4
38 33 36
36 33 37
39 38 36
36 37 39
To get the mask for the ix-th triangle, use:
poly2mask(p(t(ix,:),1),p(t(ix,:),2),width,height)
t is used to index n to get the data for one triangle.

Intersect between two vectors but should have the same index

I am trying to get the intersection between two vectors but the index in both vectors should be the same. For example:
x = [1 2 3 4 5 6 7 80 9 100 11 12 103 14 150 16 170 18 20 19]
y = [22 1 3 40 5 4 70 8 90 10 110 12 13 140 15 160 17 18 19 20]
the intesection should be [3 5 12 18] only.
My code:
x = [1 2 3 4 5 6 7 80 9 100 11 12 103 14 150 16 170 18 20 19];
y = [22 1 3 40 5 4 70 8 90 10 110 12 13 140 15 160 17 18 19 20];
inter = intersect(x,y);
It's simple with logical indexing:
>> x = [1 2 3 4 5 6 7 80 9 100 11 12 103 14 150 16 170 18 20 19];
>> y = [22 1 3 40 5 4 70 8 90 10 110 12 13 140 15 160 17 18 19 20];
>> x(x==y)
ans =
3 5 12 18
>> x(abs(x-y)<=3) %// or y(abs(x-y)<=3) for the y values instead of the x values
ans =
2 3 5 6 12 18 20 19

Stacked-area with date format at x-axis on Gnuplot

I have created graphs using filledcurves. Now, the graphs looks bad because long range of data.
This is my data:
a b c d e f g h i
201312 49 26 34 30 14 25 9 4 1
201311 38 22 47 30 9 9 4 3 1
201310 44 24 43 38 9 14 5 7 0
201309 65 18 33 39 15 12 4 5 1
201308 42 31 44 30 5 11 0 2 2
201307 58 27 35 29 8 4 2 4 2
201306 30 22 15 17 2 6 3 4 0
201305 61 52 20 16 11 12 2 3 0
201304 62 60 33 18 13 9 5 6 0
201303 43 53 49 27 9 11 7 0 0
201302 31 30 42 27 10 8 4 2 0
201301 42 30 20 47 9 13 3 2 1
201212 26 19 39 24 9 11 0 0 0
201211 26 26 30 28 1 2 0 2 1
201210 55 46 34 30 13 5 0 2 1
201209 56 31 27 28 27 13 2 4 1
201208 48 75 38 46 22 10 0 1 0
201207 60 56 37 47 19 11 2 1 0
201206 60 41 37 28 17 12 5 1 0
201205 49 43 38 46 15 16 2 2 0
201204 43 50 36 33 4 7 3 0 2
201203 49 63 35 43 16 7 1 2 0
201202 43 59 59 52 16 13 3 4 1
201201 51 44 30 37 20 9 4 1 0
201112 50 38 36 36 8 2 3 1 1
201111 75 35 30 36 16 7 3 3 1
201110 68 53 41 27 11 15 1 2 1
201109 68 46 48 47 16 19 4 0 1
201108 45 41 20 36 17 10 1 0 0
201107 48 34 30 24 13 7 3 3 1
201106 49 29 24 25 5 6 0 3 0
201105 45 35 21 37 1 7 2 1 0
201104 53 35 23 18 4 6 1 5 1
201103 58 42 20 18 6 4 1 0 4
201102 54 32 19 20 4 10 0 2 0
201101 42 41 21 28 3 6 1 2 1
and this is my gnuplot file:
set terminal postscript eps color font 20
set xtics 1 out
set tics front
#set style fill transparent solid 0.5 noborder
set key below autotitle columnheader
set ylabel "Count"
set xlabel "across time"
set output 't1.eps'
set title "t1-Across time of Aspects"
set xtics 1
plot for [i=10:2:-1] \
"< awk 'NR==1 {print \"year\",$".(i-1)."} NR>=2 {for (i=2; i<=".i."; i++) \
{sum+= $i} {print $1, sum; sum=0} }' data.dat" \
using (column(2)):xtic(1) with filledcurves x1 t column(2)
When I add time in xdata:
set xdata time
set timefmt "%Y%m"
set xtics format "%b"
Erros message:
Need full using spec for x time data
Is the Errors because of my date format? I have googling this and do not have any answer about it. Please give me suggestion about this.
In the script you show, you specify only a single column in the using statement (besides the xtic). That means, that this value is taken as y-value and the row number is implicitely used as x-value.
When using time data, you must explicitely specify all columns which are needed for the plotting style, there is no assumption about what might be the first column. Use:
set key below autotitle columnheader
set ylabel "Count"
set xlabel "across time"
set tics front
set xdata time
set timefmt "%Y%m"
set xtics format "%b'%y"
set autoscale xfix
plot for [i=10:2:-1] \
"< awk 'NR==1 {print \"year\",$".(i-1)."} NR>=2 {for (i=2; i<=".i."; i++) \
{sum+= $i} {print $1, sum; sum=0} }' data.dat" \
using 1:2 with filledcurves x1 t column(2)
Result with 4.6.4:
I guess you don't want xtic(1) if you have time data and specify the x format.

Matlab: sum column elements with restrictions

We have a MxN matrix and a constrain cstrn = 100;.
The constrain is the summarize limit of column's elements (per column):
sum(matrix(:,:))<=cstrn.
For a given example as the following:
Columns 1 to 5:
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41
I want to find the max number of element per column who fulfill this constrain.
How can i summarize every column element with the others elements in same column and find which sum combinations uses the max number of elements per column?
In the given example solution is:
4 3 5 2 5
where
column 1: 15 + 50 + 31 +7 +(-2)
column 2: 18 +(-15) + 52 or 63 etc.
Thank you in advance.
Since it is always easier to fit small elements into a sum, you can do a sort, followed by the cumulative sum:
m= [
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41];
cs = cumsum(sort(m))
cs =
-2 -15 -15 22 -8
5 3 -20 61 -2
20 55 -11 106 17
51 118 21 164 55
101 216 73 235 96
171 315 153 315 168
Now you easily identify at which element you cross the threshold cnstrn (thanks, #sevenless)!
out = sum(cs <= cnstrn)
out =
4 3 5 2 5
I'd add to Jonas's answer, that you can impose your constraint in a way that outputs a logical matrix then sum over the 1's and 0's of that matrix like so:
cstrn = 100
m= [
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41];
val_matrix = cumsum(sort(m))
logical_matrix = val_matrix<=cstrn
output = sum(logical_matrix)
Giving output:
cstrn =
100
val_matrix =
-2 -15 -15 22 -8
5 3 -20 61 -2
20 55 -11 106 17
51 118 21 164 55
101 216 73 235 96
171 315 153 315 168
logical_matrix =
1 1 1 1 1
1 1 1 1 1
1 1 1 0 1
1 0 1 0 1
0 0 1 0 1
0 0 0 0 0
output =
4 3 5 2 5
Here is a logic, on mobile so can't give a code.
Check this out. Go to a column, sort it ascending order, loop to sum, break when hits <=100. Get counter. Refer back to original column, get the indices of elements matching the elements you just summed up :-)