|
| 1 | +%% oblique Allen Atlas cross-section script |
| 2 | +% Michael Krumin, October 2020 |
| 3 | + |
| 4 | +% typically can be found in '..\allenCCF\Browsing Functions\' folder |
| 5 | +brainGridData = readNPY('brainGridData.npy'); |
| 6 | + |
| 7 | +voxelSize = 0.01; % Allen data has voxel size of 10 microns |
| 8 | +bp = double(brainGridData); |
| 9 | +bp(sum(bp,2)==0,:) = NaN; % when saved to uint16, NaN's become zeros. There aren't any real vertices at (0,0,0) and it shouldn't look much different if there were |
| 10 | +bregma = allenCCFbregma; % [AP, DV, ML] |
| 11 | +bregma = bregma([1, 3, 2]); |
| 12 | +bp = bsxfun(@minus, bp, bregma) * -1 * voxelSize; |
| 13 | + |
| 14 | +% typically can be found in '..\allenCCF\' folder |
| 15 | +tv = readNPY('template_volume_10um.npy'); % grey-scale "background signal intensity" |
| 16 | +av = readNPY('annotation_volume_10um_by_index.npy'); % the number at each pixel labels the area, see note below |
| 17 | +st = loadStructureTree('structure_tree_safe_2017.csv'); % a table of what all the labels mean |
| 18 | + |
| 19 | +%% Normalizing the coordinates to mm and shifting them to be relative to bregma |
| 20 | + |
| 21 | +% rotation the data to have dimensions in the [AP, ML, DV] order for Matlab plotting |
| 22 | +tvPerm = permute(tv, [1, 3, 2]); |
| 23 | +avPerm = permute(av, [1, 3, 2]); |
| 24 | + |
| 25 | + |
| 26 | +[nAP, nML, nDV] = size(tvPerm); |
| 27 | +apAxis = (single(1:nAP) - bregma(1)) * -voxelSize; |
| 28 | +mlAxis = (single(1:nML) - bregma(2)) * -voxelSize; |
| 29 | +dvAxis = (single(1:nDV) - bregma(3)) * -voxelSize; |
| 30 | +[ML, AP, DV] = meshgrid(mlAxis, apAxis, dvAxis); |
| 31 | + |
| 32 | + |
| 33 | +[mlSurf, apSurf] = meshgrid(mlAxis, apAxis); |
| 34 | + |
| 35 | +%% Defining the plane |
| 36 | +% where do you want the plane? |
| 37 | +use3points = false; |
| 38 | +if ~use3points |
| 39 | + % one option is to define a normal to the plane and a single point: |
| 40 | + normal = [0, 1, 1]; % vector normal to the plane (ML, AP, DV) |
| 41 | + intersect = [0, -3, -2]; % a point the plain should go through (ML, AP, DV) |
| 42 | + |
| 43 | +else |
| 44 | + % another option would be to define three points the plane should pass through: |
| 45 | + point1 = [-2, -3, -2]; |
| 46 | + point2 = [2, -3, -2]; |
| 47 | + point3 = [0, -2, -3]; |
| 48 | + |
| 49 | + % and then the normal and the single intersect point can be calculated |
| 50 | + intersect = (point1 + point2 + point3)/3; |
| 51 | + normal = cross(point2 - point1, point3 - point1); |
| 52 | + normal = normal/norm(normal); |
| 53 | + [~, ind] = max(abs(normal)); |
| 54 | + if normal(ind)<0 |
| 55 | + normal = -normal; |
| 56 | + end |
| 57 | +end |
| 58 | + |
| 59 | +% plane equation: |
| 60 | +% ax + by + cz + d = 0 |
| 61 | +% normal = [a, b, c]; intersect = [x0, y0, z0] |
| 62 | +% solution: |
| 63 | +% d = -(ax0 + by0 + cz0); |
| 64 | +% z = (-d - ax - by)/c |
| 65 | +dvSurf = (normal * intersect' - normal(1) * mlSurf - normal(2) * apSurf) / normal(3); |
| 66 | + |
| 67 | +%% Actual plotting is done here |
| 68 | + |
| 69 | +plotExtras = true; % bregma, intersection points, normal |
| 70 | + |
| 71 | +figure; |
| 72 | +hSlice = slice(ML, AP, DV, single(avPerm), mlSurf, apSurf, dvSurf, 'nearest'); |
| 73 | +hSlice.LineStyle = 'none'; |
| 74 | + |
| 75 | +ax = gca; |
| 76 | + |
| 77 | +load allen_ccf_colormap_2017.mat |
| 78 | +colormap(ax, cmap); |
| 79 | +caxis(ax, [1 size(cmap,1)]); |
| 80 | + |
| 81 | +hSlice.AlphaData = ones(size(hSlice.XData)); |
| 82 | +hSlice.AlphaData(hSlice.CData == 1) = 0; |
| 83 | +hSlice.AlphaData(isnan(hSlice.CData)) = 0; |
| 84 | +hSlice.FaceAlpha = 'flat'; |
| 85 | + |
| 86 | +% ax.ZDir = 'reverse'; |
| 87 | +view(240, 20) |
| 88 | + |
| 89 | +xlabel('ML [mm]'); |
| 90 | +ylabel('AP [mm]'); |
| 91 | +zlabel('DV [mm]'); |
| 92 | +axis equal |
| 93 | + |
| 94 | +% add the mesh of the brain surface |
| 95 | +hold on; |
| 96 | +plot3(bp(:,2), bp(:, 1), bp(:,3), 'k'); |
| 97 | + |
| 98 | +xlim([min(mlAxis), max(mlAxis)]); |
| 99 | +ylim([min(apAxis), max(apAxis)]); |
| 100 | +zlim([min(dvAxis), max(dvAxis) + 0.5]); |
| 101 | + |
| 102 | +if plotExtras |
| 103 | + % plot bregma |
| 104 | + plot3(0, 0, 0, 'r.', 'MarkerSize', 30); |
| 105 | + % plot the intersect point (or three points defining the plane) |
| 106 | + if use3points |
| 107 | + plot3(point1(1), point1(2), point1(3), 'b.', 'MarkerSize', 30); |
| 108 | + plot3(point2(1), point2(2), point2(3), 'b.', 'MarkerSize', 30); |
| 109 | + plot3(point3(1), point3(2), point3(3), 'b.', 'MarkerSize', 30); |
| 110 | + else |
| 111 | + plot3(intersect(1), intersect(2), intersect(3), 'k.', 'MarkerSize', 30); |
| 112 | + end |
| 113 | + % plot the normal to the plane |
| 114 | + q = quiver3(intersect(1), intersect(2), intersect(3), normal(1), normal(2), normal(3)); |
| 115 | + q.MaxHeadSize = 10; |
| 116 | + q.LineWidth = 3; |
| 117 | + q.Color = [0 0 1]; |
| 118 | + q.AutoScaleFactor = 3 / norm(normal); |
| 119 | +end |
0 commit comments