mirror of
https://github.com/c-sooyoung/lemon-sandbox.git
synced 2026-11-16 04:07:59 +09:00
finding grain boundaries by fourier peak finding
This commit is contained in:
1 parent
53d30f714e
commit
d0c8d8723a
2 files changed
+1309
No files matched your search
@@ -0,0 +1,634 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "a7e52d53",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import numpy as np\n",
|
||||
"from matplotlib import pyplot as plt, colormaps\n",
|
||||
"import tifffile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "74171f8c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"['f_410_1_obj_phase_roi_Niter100.tiff',\n",
|
||||
" 'f_410_2_obj_phase_roi_Niter100.tiff',\n",
|
||||
" 'f_410_3_obj_phase_roi_Niter100.tiff',\n",
|
||||
" 'f_410_4_obj_phase_roi_Niter100.tiff',\n",
|
||||
" 'f_420_1_obj_phase_roi_Niter120.tiff',\n",
|
||||
" 'f_420_2_obj_phase_roi_Niter120.tiff',\n",
|
||||
" 'f_420_3_obj_phase_roi_Niter120.tiff',\n",
|
||||
" 'f_420_4_obj_phase_roi_Niter120.tiff',\n",
|
||||
" 'f_430_1_obj_phase_roi_Niter80.tiff',\n",
|
||||
" 'f_430_2_obj_phase_roi_Niter80.tiff',\n",
|
||||
" 'f_430_3_obj_phase_roi_Niter80.tiff',\n",
|
||||
" 'f_430_4_obj_phase_roi_Niter80.tiff',\n",
|
||||
" 'f_450_1_obj_phase_roi_Niter90.tiff',\n",
|
||||
" 'f_450_2_obj_phase_roi_Niter90.tiff',\n",
|
||||
" 'f_450_3_obj_phase_roi_Niter90.tiff',\n",
|
||||
" 'f_450_4_obj_phase_roi_Niter90.tiff',\n",
|
||||
" 'f_471_1_obj_phase_roi_Niter50.tiff',\n",
|
||||
" 'f_471_2_obj_phase_roi_Niter50.tiff',\n",
|
||||
" 'f_471_3_obj_phase_roi_Niter50.tiff',\n",
|
||||
" 'f_471_4_obj_phase_roi_Niter50.tiff',\n",
|
||||
" 'f_471_5_obj_phase_roi_Niter230.tiff',\n",
|
||||
" 'f_471_6_obj_phase_roi_Niter230.tiff',\n",
|
||||
" 'f_471_7_obj_phase_roi_Niter230.tiff',\n",
|
||||
" 'f_472_1_obj_phase_roi_Niter50.tiff',\n",
|
||||
" 'f_472_2_obj_phase_roi_Niter50.tiff',\n",
|
||||
" 'f_472_3_obj_phase_roi_Niter50.tiff',\n",
|
||||
" 'f_472_4_obj_phase_roi_Niter50.tiff']"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"basedir = \"/home/swim/shared/Si_project/260707_BCAT_tif_file\"\n",
|
||||
"os.listdir(basedir)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "80e55aa7",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Shape : (30, 379, 379)\n",
|
||||
"Dtype : uint8\n",
|
||||
"H × W : 30 × 379\n",
|
||||
"Pixel Size : 3.07 A/px\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"tiff = 'f_430_2_obj_phase_roi_Niter80.tiff'\n",
|
||||
"image = tifffile.imread(os.path.join(basedir, tiff))\n",
|
||||
"\n",
|
||||
"roi_A = 92\n",
|
||||
"A_per_px = roi_A / image.shape[0] # A/pixel\n",
|
||||
"Si_distance_px = 1.358 / A_per_px\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(f\"Shape : {image.shape}\")\n",
|
||||
"print(f\"Dtype : {image.dtype}\")\n",
|
||||
"print(f\"H × W : {image.shape[0]} × {image.shape[1]}\")\n",
|
||||
"print(f\"Pixel Size : {A_per_px:.2f} A/px\")\n",
|
||||
"\n",
|
||||
"# fig, ax = plt.subplots(figsize=(7, 7))\n",
|
||||
"# ax.imshow(image[image.shape[0] // 2], cmap='gray')\n",
|
||||
"# ax.set_title(f\"Raw Image ({image.shape[0]} × {image.shape[1]} px)\")\n",
|
||||
"# ax.axis('on') # 픽셀 좌표 눈금 표시\n",
|
||||
"# plt.tight_layout()\n",
|
||||
"# plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "b6ac9727",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"(np.float64(-0.5), np.float64(378.5), np.float64(378.5), np.float64(-0.5))"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 600x300 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig, axs = plt.subplots(1, 2, figsize=(6, 3))\n",
|
||||
"ax1, ax2 = axs\n",
|
||||
"\n",
|
||||
"layer = image[3]\n",
|
||||
"\n",
|
||||
"ax1.imshow(layer)\n",
|
||||
"ax1.axis('off')\n",
|
||||
"\n",
|
||||
"ax2.imshow(np.log1p(abs(np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(layer))))))\n",
|
||||
"ax2.axis('off')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "si110-grid-fit",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABiUAAAGbCAYAAACrnJPxAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsnXeYHVX9/1/Tbt9esimkQAi9Sgu9hRqKCIIiTaQIIigoRSBUhVgBQZAvGmmCgqCoSBPQH80gSu+QQEKy2exm660zc35/zH6Gc3c3ySZS9byeZ59kZ+fOnDlz5py570+zlFIKg8FgMBgMBoPBYDAYDAaDwWAwGAyGDxn7426AwWAwGAwGg8FgMBgMBoPBYDAYDIb/DYxRwmAwGAwGg8FgMBgMBoPBYDAYDAbDR4IxShgMBoPBYDAYDAaDwWAwGAwGg8Fg+EgwRgmDwWAwGAwGg8FgMBgMBoPBYDAYDB8JxihhMBgMBoPBYDAYDAaDwWAwGAwGg+EjwRglDAaDwWAwGAwGg8FgMBgMBoPBYDB8JBijhMFgMBgMBoPBYDAYDAaDwWAwGAyGjwRjlDAYDAaDwWAwGAwGg8FgMBgMBoPB8JFgjBIGg8FgMBgMBoPBYDAYDAaDwWAwGD4SjFHCYDAYDIZPGHPmzMGyrBF/zjjjDObNm4dlWcyZMyf+zOOPP84FF1xAd3f3sONdc801Vft+kFiWxQUXXLDCfUZq7/K44IILsCzrg2nccpD+nTdv3kr3feqpp/jsZz/LxIkTSSaTjBkzhunTp3P66adX7bfzzjuz8847r/R4+r38wQ9+UPW3c889l5kzZzJ+/Hgsy+Loo48e8RgvvvgiJ510EtOnTyebzWJZFo888shyz3nbbbex6aabkkqlGDduHKeddhr9/f1V+9x9991VbXv66adXei3/KZ+0cWEwGAwGg8FgMBgMho8GY5QwGAwGg+ETyi9/+UueeOKJqp+vf/3rjB07lieeeIJ999033vfxxx/nwgsv/MiNEqNhpPZ+GvjTn/7EtttuS29vL7Nnz+b+++/niiuuYLvttuP222+v2veaa67hmmuuGdVxjz32WJ544gkOP/zwqu0//vGP6ezsZP/99yeRSCz3808//TR33303jY2N7Lbbbis81y233MIXvvAFttxyS+69915mzZrFnDlzOOigg6r222mnnXjiiSc499xzR3UNHwSf1nFhMBgMBoPBYDAYDIb/DPfjboDBYDAYDIaR2XDDDdliiy1G/Ns222zzEbdm9Ukmk5+q9gqzZ89mypQp3Hfffbju+69Mhx12GLNnz67ad/311x/1cSdMmDBif/T19WHbkb/ITTfdtNzPH3HEERx11FEA3HHHHdxzzz0j7hcEAd/61rfYY489uP766wHYZZddqKmp4fDDD+fee+9l7733BqChoYFtttmGV155ZdTXsboEQYDv+5/acWEwGAwGg8FgMBgMhv8MEylhMBgMBsOnjKFpby644AK+9a1vATBlypQ4Bc8jjzzC5MmTefHFF3n00Ufj7ZMnT46P1dvbyxlnnMGUKVNIJBKMHz+e0047jYGBgapz9vb2ctxxx9HU1EQul2OvvfbitddeW632Cn/605/YdNNNSSaTTJkyZVg6I0EpxTXXXMOmm25KOp2moaGBgw8+mLfeeqtqvwceeIADDjiACRMmkEqlmDp1KieccAJLly4dVTuH0tnZSXNzc5VBQhDjgTDa9E0rYugx/9P9nnzySRYtWsQxxxxTtf2QQw4hl8tx1113rXIbda6//nqmTZtGMplk/fXX59Zbb+Xoo4+uGl9y72fPns0ll1zClClTSCaTPPzww//xuDAYDAaDwWAwGAwGw6cTEylhMBgMBsMnFPEo1xlJIP/KV75CV1cXV111Fb/73e8YO3YsEHnv33XXXRx88MHU1dXF6YWSySQA+XyenXbaiQULFnDOOeew8cYb8+KLL3L++efz/PPP8+CDD2JZFkopDjzwQB5//HHOP/98ttxySx577LHYy351eOihhzjggAOYPn06t912G0EQMHv2bNrb24fte8IJJzBnzhy+/vWvc/nll9PV1cVFF13Etttuy7PPPsuYMWMAePPNN5k+fTpf+cpXqKurY968efzoRz9i++235/nnn8fzvFVq4/Tp0/m///s/vv71r3P44Yez+eabr/IxPk5eeOEFADbeeOOq7Z7nse6668Z/Xx1+/vOfc8IJJ/C5z32OH//4x/T09HDhhRdSKpVG3P/KK69k2rRp/OAHP6C2tpa11157xP1WZVwYDAaDwWAwGAwGg+HTiTFKGAwGg8HwCWWk1DaVSmXYtgkTJjBx4kQANttssypP9c0224x0Ok1tbe2w41155ZU899xzPPXUU3GaqN12243x48dz8MEH85e//IW9996b++67j4cffpgrrriCr3/96wDMmDGDRCLBd77zndW6tu985zuMGTOGBx54gFQqBcCee+5Z1XaIvP2vv/56fvjDH/LNb34z3r7DDjswbdo0fvSjH3H55ZcDcOKJJ8Z/V0qx7bbbsvPOOzNp0iTuvfde9t9//1Vq42WXXcYrr7zCVVddxVVXXYXneWy55Zbst99+fO1rXyOXy63WtX9UdHZ2AtDY2Djsb42NjaMq9D0SYRgya9Ystt56a+644454+/bbb8/UqVMZN27csM+kUinuu+++KqPOSOcf7bgwGAwGg8FgMBgMBsOnF5O+yWAwGAyGTyg33ngjc+fOrfoZKVJidfnjH//IhhtuyKabborv+/HPnnvuGad/Anj44YcBhhVm/uIXv7ha5x0YGGDu3LkcdNBBsfAMUFNTw3777TesjZZl8aUvfamqjW1tbWyyySZxGwGWLFnCiSeeyBprrIHruniex6RJkwB4+eWXV7mdTU1N/P3vf2fu3LlcdtllHHDAAbz22mucffbZbLTRRqudFuqjxrKsVdq+Ml599VUWL17M5z//+artEydOZLvtthvxM/vvv/9Ko0xWZVwYDAaDwWAwGAwGg+HTi4mUMBgMBoPhE8p666233ELXHwTt7e288cYbyxWLRXTv7OzEdV2ampqq/t7W1rZa5122bBlhGI74+aHb2tvbUUrFKZqGsuaaawKR9/4ee+zBe++9x3nnncdGG21ENpslDEO22WYbCoXCarUVYIsttojvQ6VS4cwzz+THP/4xs2fPHlbw+pOE3K/Ozs5h/dfV1TViBMVokAiMke7JmDFjePvtt4dtl5RiK2JVxoXBYDAYDAaDwWAwGD69GKOEwWAwGAz/ozQ3N5NOp/nFL36x3L9DJG77vk9nZ2eVYWLx4sWrdd6GhgYsyxrx80O3NTc3Y1kWf//73+NaGDqy7YUXXuDZZ59lzpw5HHXUUfHf33jjjdVq4/LwPI9Zs2bx4x//+D+qyfBRsNFGGwHw/PPPs/7668fbfd/nlVde4Qtf+MJqHVfGwEh1HpY3JkYTlbEq48JgMBgMBoPBYDAYDJ9eTPomg8FgMBj+CxBxfqSIgGQyOeL2mTNn8uabb9LU1BRHA+g/ksd/l112AeCWW26p+vytt966Wm3NZrNstdVW/O53v6NYLMbb+/r6uOeee4a1USnFwoULR2yjCO8ieg81XFx33XWr1UaARYsWjbhdUkGNVDvhk8TWW2/N2LFjmTNnTtX2O+64g/7+fg466KDVOu4666xDW1sbv/nNb6q2v/POOzz++OOr29xVGhcGg8FgMBgMBoPBYPj0YiIlDAaDwWD4L0DE+SuuuIKjjjoKz/NYZ511qKmpYaONNuK2227j9ttvZ8011ySVSrHRRhtx2mmnceedd7LjjjvyjW98g4033pgwDHnnnXe4//77Of3009l6663ZY4892HHHHfn2t7/NwMAAW2yxBY899hg33XTTarf34osvZq+99mLGjBmcfvrpBEHA5ZdfTjabpaurK95vu+224/jjj+eYY47h6aefZscddySbzbJo0SL+3//7f2y00UZ89atfZd1112WttdbirLPOQilFY2Mj99xzDw888MBqt3HPPfdkwoQJ7Lfffqy77rqEYci///1vfvjDH5LL5Tj11FNX+9gj8eijj9LR0QFAEATMnz8/LiS900470dLSAkA+n+fPf/4zEBUCl88uXbqUbDbL3nvvDYDjOMyePZsjjjiCE044gS984Qu8/vrrfPvb32bGjBnstddeq9VO27a58MILOeGEEzj44IP58pe/THd3NxdeeCFjx47Ftlff52W048JgMBgMBoPBYDAYDJ9ejFHCYDAYDIb/AnbeeWfOPvtsfvWrX3H99dcThiEPP/wwO++8MxdeeCGLFi3iuOOOo6+vj0mTJjFv3jyy2Sx///vfueyyy/j5z3/O22+/TTqdZuLEiey+++5xpIRt2/zhD3/gm9/8JrNnz6ZcLrPddtvx5z//mXXXXXe12jtjxgzuvvtuzj33XA499FDa2to46aSTKBQKXHjhhVX7XnfddWyzzTZcd911XHPNNYRhyLhx49huu+3YaqutgCit0j333MOpp57KCSecgOu67L777jz44INMnDhxtdp47rnn8vvf/54f//jHLFq0iFKpxNixY9l99905++yzWW+99VbruMtj1qxZPProo/HvjzzySFWx8Z133hmICnofcsghVZ+94IILAOJ7K3zpS1/CcRwuu+wy5syZQ2NjI0ceeSSXXnrpf9TW448/HsuymD17Np/97GeZPHkyZ511Fr///e955513Vvu4qzIuDAaDwWAwGAwGg8Hw6cRSSqmPuxEGg8FgMBgM/wtYlsV5553H+eefj+M4o6q18FGglCIIAm688UaOPfZY5s6du8pF1ru7u5k2bRoHHnggP//5zz+klhoMBoPBYDAYDAaD4dOOqSlhMBgMBoPB8BFy8cUX43keP/zhDz/upsT8/ve/x/M8jj322FHtv3jxYk455RR+97vf8eijj3LjjTeyyy670NfX94GntTIYDAaLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1600x400 with 4 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Match the FFT to an ideal diamond-cubic Si [110] diffraction grid.\n",
|
||||
"# For zone axis [110], h + k = 0. The supplied fcc/diamond extinction\n",
|
||||
"# rules leave: (h, -h, l), with h and l both odd, or both even with l = 4n.\n",
|
||||
"layer = image[3].astype(float)\n",
|
||||
"height, width = layer.shape\n",
|
||||
"A_per_px_xy = roi_A / height\n",
|
||||
"d_004_A = 1.358 # given above; for Si, d_004 = a / 4\n",
|
||||
"a_si_A = 4 * d_004_A\n",
|
||||
"\n",
|
||||
"fft_shifted = np.fft.fftshift(np.fft.fft2(layer))\n",
|
||||
"spectrum = np.log1p(np.abs(fft_shifted))\n",
|
||||
"centre_y, centre_x = (np.asarray(layer.shape) - 1) / 2\n",
|
||||
"yy, xx = np.ogrid[:height, :width]\n",
|
||||
"radius_px = np.hypot(xx - centre_x, yy - centre_y)\n",
|
||||
"\n",
|
||||
"# Detect candidate Bragg maxima once. Keep only the strongest candidates so\n",
|
||||
"# the rotation/scale fit is driven by diffraction peaks rather than background.\n",
|
||||
"neighbourhood = 3\n",
|
||||
"local_maximum = spectrum.copy()\n",
|
||||
"for dy in range(-neighbourhood, neighbourhood + 1):\n",
|
||||
" for dx in range(-neighbourhood, neighbourhood + 1):\n",
|
||||
" local_maximum = np.maximum(local_maximum, np.roll(np.roll(spectrum, dy, 0), dx, 1))\n",
|
||||
"candidate_pixels = np.argwhere((spectrum == local_maximum) & (radius_px > 8))\n",
|
||||
"candidate_strength = spectrum[candidate_pixels[:, 0], candidate_pixels[:, 1]]\n",
|
||||
"strongest = np.argsort(candidate_strength)[-min(600, len(candidate_pixels)):]\n",
|
||||
"candidate_pixels = candidate_pixels[strongest]\n",
|
||||
"candidate_strength = candidate_strength[strongest]\n",
|
||||
"\n",
|
||||
"# Build all allowed reciprocal-lattice points in the [110] zone. Coordinates\n",
|
||||
"# are expressed along [1 -1 0] (horizontal) and [001] (vertical).\n",
|
||||
"grid_hkls, grid_xy = [], []\n",
|
||||
"base_scale_px = width * A_per_px_xy / a_si_A # pixels per reciprocal 1/a\n",
|
||||
"for h in range(-12, 13):\n",
|
||||
" for l in range(-12, 13):\n",
|
||||
" if h == 0 and l == 0:\n",
|
||||
" continue\n",
|
||||
" all_odd = (h % 2 != 0) and (l % 2 != 0)\n",
|
||||
" diamond_even = (h % 2 == 0) and (l % 2 == 0) and (l % 4 == 0)\n",
|
||||
" if all_odd or diamond_even:\n",
|
||||
" grid_hkls.append((h, -h, l))\n",
|
||||
" grid_xy.append((np.sqrt(2) * h * base_scale_px, l * base_scale_px))\n",
|
||||
"grid_hkls = np.asarray(grid_hkls)\n",
|
||||
"grid_xy = np.asarray(grid_xy)\n",
|
||||
"\n",
|
||||
"match_tolerance_px = 4.5\n",
|
||||
"def projected_grid(angle_deg, scale_factor):\n",
|
||||
" angle = np.deg2rad(angle_deg)\n",
|
||||
" rotation = np.array([[np.cos(angle), -np.sin(angle)],\n",
|
||||
" [np.sin(angle), np.cos(angle)]])\n",
|
||||
" xy = scale_factor * grid_xy @ rotation.T\n",
|
||||
" pixels = np.column_stack((centre_y + xy[:, 1], centre_x + xy[:, 0]))\n",
|
||||
" valid = ((pixels[:, 0] >= 4) & (pixels[:, 0] < height - 4)\n",
|
||||
" & (pixels[:, 1] >= 4) & (pixels[:, 1] < width - 4))\n",
|
||||
" return grid_hkls[valid], pixels[valid]\n",
|
||||
"\n",
|
||||
"def grid_score(angle_deg, scale_factor):\n",
|
||||
" _, targets = projected_grid(angle_deg, scale_factor)\n",
|
||||
" distance2 = ((targets[:, None, :] - candidate_pixels[None, :, :]) ** 2).sum(axis=2)\n",
|
||||
" nearest = np.argmin(distance2, axis=1)\n",
|
||||
" # Gaussian distance weighting rewards agreement with many allowed spots.\n",
|
||||
" return np.sum(candidate_strength[nearest] * np.exp(-distance2[np.arange(len(targets)), nearest]\n",
|
||||
" / (2 * match_tolerance_px ** 2)))\n",
|
||||
"\n",
|
||||
"# Fit detector rotation and a small scale correction to the measured FFT.\n",
|
||||
"best_score, best_angle, best_scale = -np.inf, None, None\n",
|
||||
"for scale in np.linspace(0.94, 1.06, 7):\n",
|
||||
" for angle in np.arange(0, 180, 2):\n",
|
||||
" score = grid_score(angle, scale)\n",
|
||||
" if score > best_score:\n",
|
||||
" best_score, best_angle, best_scale = score, angle, scale\n",
|
||||
"for scale in np.linspace(best_scale - 0.015, best_scale + 0.015, 7):\n",
|
||||
" for angle in np.linspace(best_angle - 2, best_angle + 2, 17):\n",
|
||||
" score = grid_score(angle, scale)\n",
|
||||
" if score > best_score:\n",
|
||||
" best_score, best_angle, best_scale = score, angle, scale\n",
|
||||
"\n",
|
||||
"# Retain only observed candidate peaks that are close to allowed, fitted-grid sites.\n",
|
||||
"fitted_hkls, fitted_pixels = projected_grid(best_angle, best_scale)\n",
|
||||
"distance2 = ((fitted_pixels[:, None, :] - candidate_pixels[None, :, :]) ** 2).sum(axis=2)\n",
|
||||
"nearest = np.argmin(distance2, axis=1)\n",
|
||||
"matched = []\n",
|
||||
"used_candidates = set()\n",
|
||||
"for hkl, distance, candidate_index in zip(fitted_hkls, distance2[np.arange(len(fitted_pixels)), nearest], nearest):\n",
|
||||
" if distance <= match_tolerance_px ** 2 and int(candidate_index) not in used_candidates:\n",
|
||||
" matched.append((hkl, candidate_pixels[candidate_index]))\n",
|
||||
" used_candidates.add(int(candidate_index))\n",
|
||||
"if not matched:\n",
|
||||
" raise RuntimeError('The fitted Si [110] grid did not match any FFT candidates.')\n",
|
||||
"\n",
|
||||
"mask_radius_px = 6\n",
|
||||
"si110_grid_mask = np.zeros(layer.shape, dtype=bool)\n",
|
||||
"for _, (y, x) in matched:\n",
|
||||
" si110_grid_mask |= (xx - x) ** 2 + (yy - y) ** 2 <= mask_radius_px ** 2\n",
|
||||
"si110_grid_fft = fft_shifted * si110_grid_mask\n",
|
||||
"si110_grid_image = np.fft.ifft2(np.fft.ifftshift(si110_grid_fft)).real\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 4, figsize=(16, 4), constrained_layout=True)\n",
|
||||
"axes[0].imshow(layer, cmap='gray'); axes[0].set_title('Input layer')\n",
|
||||
"axes[1].imshow(spectrum, cmap='magma')\n",
|
||||
"axes[1].set_title(f'Fitted ideal Si [110] grid\\nrotation={best_angle:.2f}°, scale={best_scale:.3f}')\n",
|
||||
"axes[2].imshow(np.log1p(np.abs(si110_grid_fft)), cmap='magma', vmin=0, vmax=spectrum.max())\n",
|
||||
"axes[2].set_title(f'Matched allowed peaks ({len(matched)})')\n",
|
||||
"axes[3].imshow(si110_grid_image, cmap='gray'); axes[3].set_title('Grid-matched inverse FFT')\n",
|
||||
"for hkl, pixel in zip(fitted_hkls, fitted_pixels):\n",
|
||||
" axes[1].plot(pixel[1], pixel[0], 'w+', ms=4, mew=0.7, alpha=0.45)\n",
|
||||
"for hkl, (y, x) in matched:\n",
|
||||
" axes[1].plot(x, y, 'co', ms=6, mfc='none', mew=1.2)\n",
|
||||
"for ax in axes:\n",
|
||||
" ax.axis('off')\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "e928013c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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mRVt2XfffStSVknKqNNPP32Dv/f4448DfkRFOZ/61KfYeuutefTRRyu2t7S08KlPfapi2/bbb8+KFSsqjrntttuyww47VOx39NFHb+TM/0F9fT1PPfUUS5cu5dJLL+WQQw7hzTff5Dvf+Q4zZsygp6dnTMf5uJFolbFufy/eeOMNOjs7+exnP1uxvb29nd1222293zn44IPfM8okk8mwdOlSDj/8cKLRaLA9lUpx0EEHva+2ajQajUaj0Wg0Go1m86CNEhqNRqPRbGZuuukmli5dymOPPcapp57Ka6+9xlFHHRV83tvbC/wjhVI5bW1teJ5Hf3//Rn9jeHiY3XffnSVLlnDxxRfzxBNPsHTpUu68804Acrnce7azq6sLpRTNzc3Ytl3x99xzzwVCubS3paVl1DHWt21d9thjD+666y4cx+H4449n/PjxbLfddtx6660VbXnppZdGtSOVSqGUCtrS3d2NZVkb/d336l/5XKivrx+1XyQSqejD3t7e933+5ey0005861vf4ne/+x1r1qzhrLPOYvny5aOKXf+zIX20bt8B9PX1UVdX976OK8eTNGHlrG8brP+6rkt/fz+e522Wa6bRaDQajUaj0Wg0ms2Lrimh0Wg0Gs1mZuuttw6KW++55564rssvf/lLbr/9do488shA4O3o6Bj13TVr1mCaJrW1tRv9jccee4w1a9bwxBNPBNERAAMDA2NuZ0NDA4Zh8NRTTxGJREZ9LtukvZ2dnaP26ezsrChGvCEOOeQQDjnkEAqFAs899xyXXHIJRx99NJMmTWL27Nk0NDQQi8W47rrrNthWgMbGRlzXpbOzc4PidHn/jh8/vuKzNWvWVNSTGCv19fUbPP/3i23bLFy4kCuvvPID1WT4KJgxYwYA//d//xfUNAFwHIfXX3+9wui2Kci1Wl+dhw317ViiMmprazEMY7NfM41Go9FoNBqNRqPRfHB0pIRGo9FoNB8yixYtora2lvPOOw/P85g2bRrjxo3jlltuQSkV7JfJZLjjjjuYPXs28Xgc+IdhYN3IBxFm1zUm/M///M+o39/QMRYsWIBSinfffZeddtpp1J8I0bvssgvRaJSbb7654vvPPvtsRYqjsRCJRJgzZw6XXXYZAH/961+Dtrz99tvU19evty1i+Nh///0B+NnPfrbB39hrr70A+PWvf12xfenSpbz22mvMmzdvk9oMvnHplVde4cUXX6zYfsstt4zp++szQME/0my1tbVtcps+SmbNmkVrays33HBDxfbbb7+d4eFhDj/88Pd13GnTptHS0sJvf/vbiu0rV67k2Weffb/NJZFI8KlPfYo777yTfD4fbE+n09xzzz3v+7gajUaj0Wg0Go1Go/ng6EgJjUaLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1600x400 with 4 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Second-dominant Si [110] grain. Run the preceding grid-fit cell first.\n",
|
||||
"# Keep the first grain's calibrated grid scale fixed; search only its rotation.\n",
|
||||
"# Remove every candidate close to the first orientation's full ideal grid.\n",
|
||||
"first_grid_pixels = fitted_pixels\n",
|
||||
"distance2_to_first = ((candidate_pixels[:, None, :] - first_grid_pixels[None, :, :]) ** 2).sum(axis=2)\n",
|
||||
"keep_residual = distance2_to_first.min(axis=1) > (2 * match_tolerance_px) ** 2\n",
|
||||
"second_candidate_pixels = candidate_pixels[keep_residual]\n",
|
||||
"second_candidate_strength = candidate_strength[keep_residual]\n",
|
||||
"if len(second_candidate_pixels) == 0:\n",
|
||||
" raise RuntimeError('No FFT candidates remain after excluding the first grid.')\n",
|
||||
"\n",
|
||||
"second_scale = best_scale\n",
|
||||
"def second_grid_score(angle_deg):\n",
|
||||
" _, targets = projected_grid(angle_deg, second_scale)\n",
|
||||
" distance2 = ((targets[:, None, :] - second_candidate_pixels[None, :, :]) ** 2).sum(axis=2)\n",
|
||||
" nearest = np.argmin(distance2, axis=1)\n",
|
||||
" nearest_distance2 = distance2[np.arange(len(targets)), nearest]\n",
|
||||
" matches = nearest_distance2 <= match_tolerance_px ** 2\n",
|
||||
" return np.sum(second_candidate_strength[nearest[matches]]\n",
|
||||
" * (1 - nearest_distance2[matches] / match_tolerance_px ** 2))\n",
|
||||
"\n",
|
||||
"# Coarse-to-fine rotation-only fit of the strongest remaining Si [110] grid.\n",
|
||||
"second_score, second_angle = -np.inf, None\n",
|
||||
"for angle in np.arange(0, 180, 1):\n",
|
||||
" score = second_grid_score(angle)\n",
|
||||
" if score > second_score:\n",
|
||||
" second_score, second_angle = score, angle\n",
|
||||
"for angle in np.linspace(second_angle - 1, second_angle + 1, 41):\n",
|
||||
" score = second_grid_score(angle)\n",
|
||||
" if score > second_score:\n",
|
||||
" second_score, second_angle = score, angle\n",
|
||||
"\n",
|
||||
"second_hkls, second_grid_pixels = projected_grid(second_angle, second_scale)\n",
|
||||
"relative_rotation = (second_angle - best_angle + 90) % 180 - 90\n",
|
||||
"distance2 = ((second_grid_pixels[:, None, :] - second_candidate_pixels[None, :, :]) ** 2).sum(axis=2)\n",
|
||||
"nearest = np.argmin(distance2, axis=1)\n",
|
||||
"second_matched, used_candidates = [], set()\n",
|
||||
"for hkl, distance, candidate_index in zip(second_hkls, distance2[np.arange(len(second_grid_pixels)), nearest], nearest):\n",
|
||||
" if distance <= match_tolerance_px ** 2 and int(candidate_index) not in used_candidates:\n",
|
||||
" second_matched.append((hkl, second_candidate_pixels[candidate_index]))\n",
|
||||
" used_candidates.add(int(candidate_index))\n",
|
||||
"if not second_matched:\n",
|
||||
" raise RuntimeError('No second Si [110] grid peaks matched the residual FFT.')\n",
|
||||
"\n",
|
||||
"# Pass every allowed peak in the fitted second-grain grid, including weak sites\n",
|
||||
"# that were not strong enough to be used as orientation-matching candidates.\n",
|
||||
"second_mask = np.zeros(layer.shape, dtype=bool)\n",
|
||||
"for y, x in second_grid_pixels:\n",
|
||||
" second_mask |= (xx - x) ** 2 + (yy - y) ** 2 <= mask_radius_px ** 2\n",
|
||||
"second_fft = fft_shifted * second_mask\n",
|
||||
"second_grain_image = np.fft.ifft2(np.fft.ifftshift(second_fft)).real\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 4, figsize=(16, 4), constrained_layout=True)\n",
|
||||
"axes[0].imshow(layer, cmap='gray'); axes[0].set_title('Input layer')\n",
|
||||
"axes[1].imshow(spectrum, cmap='magma')\n",
|
||||
"axes[1].set_title(f'Rotated second Si [110] grid\\nΔrotation={relative_rotation:.2f}°')\n",
|
||||
"axes[2].imshow(np.log1p(np.abs(second_fft)), cmap='magma', vmin=0, vmax=spectrum.max())\n",
|
||||
"axes[2].set_title(f'All allowed second-grid peaks ({len(second_grid_pixels)})')\n",
|
||||
"axes[3].imshow(second_grain_image, cmap='gray'); axes[3].set_title('Second-grain inverse FFT')\n",
|
||||
"for pixel in first_grid_pixels:\n",
|
||||
" axes[1].plot(pixel[1], pixel[0], 'w+', ms=3, mew=0.5, alpha=0.18)\n",
|
||||
"for pixel in second_grid_pixels:\n",
|
||||
" axes[1].plot(pixel[1], pixel[0], 'y+', ms=4, mew=0.8, alpha=0.5)\n",
|
||||
"for _, (y, x) in second_matched:\n",
|
||||
" axes[1].plot(x, y, 'co', ms=6, mfc='none', mew=1.2)\n",
|
||||
"for ax in axes:\n",
|
||||
" ax.axis('off')\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"id": "52b69c9b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABxMAAAHhCAYAAAClRpDpAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsnWeYU9XWgN+UyUymN5hKHWlSRToiTaSLerFhAbtYUK9YsFHkimLv5do+L6hYsAAiFhBRuvQqbYABZmB6n0nZ34+dk0yYyUmmJaDnfZ48MMlOzjrn7LPXXmvttbZOCCHQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQOA19oAXQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NA4M9GCiRoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGjWiBRM1NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDRqRAsmamhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGho1IgWTNTQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0KgRLZiooaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaFRI1owUUNDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDo0a0YKKGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhkaNaMFEDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ2NGtGCiX9D1q5dyxVXXEFSUhImk4nExETGjx/PmjVravU7M2bMQKfT1UmGX3/9FZ1Ox6+//lqn7/vKoEGDGDRokE9tW7ZsyaRJkxpVHo26c/z4cWbMmMGWLVsCLUqtSU9PR6fT8fzzzwdaFA0NjQbio48+QqfT1fiaOnWq87n/6KOPGuyYb775ZoP+ni/4QzeuXr2aGTNmkJ+fX+ff+P7775kxY0aNn/3d9LvS9zZu3Oi17aRJk2jZsmXjC6WhofG3ZN26dVx22WU0b96c4OBgEhIS6Nu3Lw888ECgRWsQ/KkfdDqdRz3VUKjpQl/55JNPePnll2v8zB/n8HehNn4IDY2zgaq2T01+PCEE55xzDjqdrtH6vr/8Ktrz6zun69HG9tsdOHCA4ODgWvuv/U19/OUa/qe+fhaLxUJaWprH+dM/DS2Y+Dfjtddeo3///mRkZDB37lx+/vlnnn/+eY4dO8YFF1zA66+/7vNv3XLLLXUewLt3786aNWvo3r17nb6v8c/j+PHjzJw586wMJmpoaPx9+fDDD1mzZo3ba8qUKSQlJbFmzRpGjx7dYMcKRDDx66+/5oknnmjUY6xevZqZM2fWO5g4c+bMGj/zxzloaGho/N1YsmQJ/fr1o7CwkLlz5/Ljjz/yyiuv0L9/fxYsWBBo8c461qxZwy233NKox1DThb6iFkz0xzloaGic2URERPD+++9Xe3/lypUcOHCAiIiIAEilEShOt7Ma2283depUhg0bRt++fRvl9zX+mdTXzxIUFMSTTz7JrFmzyMnJaTjBzlKMgRZAo+H4448/uO+++xg1ahRff/01RqPr9l599dVcdtll3HvvvZx33nn079/f4++UlpYSGhpKamoqqampdZIlMjKSPn361Om7/1TKysowm82BFsPv2Gw2rFZroMXQ0NDQqJFOnTrRo0ePGj/zRc8pOvVMQ9E55513XqBFqTd/h3PQ0NDQ8Ddz586lVatWLFu2rJrdOHfu3ABKdvYghKC8vByz2fy3sH3/DufgjTN1XqahcaZw1VVXMX/+fN544w0iIyOd77///vv07duXwsLCAEqn4W/8aWft3r2bb775hh9++MFvx6wtmg7553LNNdfw73//m3feeYdHH3000OIEFC0z8W/EnDlz0Ol0vPXWW24GIYDRaOTNN99Ep9PxzDPPON9XUrM3bdrE+PHjiYmJIS0tze2zqlRUVPDAAw+QmJhIaGgoF154IX/++We11PeaypxOmjSJ8PBw9u/fz6hRowgPD6dZs2Y88MADVFRUuB1n5syZ9O7dm9jYWCIjI+nevTvvv/8+QogGulpQXl7OAw88QLdu3YiKiiI2Npa+ffvy7bffurUbOnQo7du3r3ZspcxD1ayUyspKZs+eTfv27QkODqZJkybceOONnDp1yu27LVu2ZMyYMSxcuJDzzjuPkJAQ1VWmmzdvZsyYMTRt2pTg4GCSk5MZPXo0GRkZAKrl9k4vV6Pc182bN3P55ZcTGRlJVFQU1113nUc5v/76a7p06UJISAitW7fm1VdfrXacI0eOcN111zll7NChAy+88AJ2u93ZRpFz7ty5zJ49m1atWhEcHMyKFSvo2bMnADfeeKOzvIZamR2lDMfy5cu59dZbiYuLIzIykhtuuIGSkhIyMzO58soriY6OJikpialTp2KxWNx+w9d+tnz5cgYNGkRcXBxms5nmzZvzr3/9i9LSUo/yWSwWJk6cSHh4OIsXL/bYTkND4+ykpnFXTacePHiQq6++muTkZGcpuaFDhzpXdbZs2ZKdO3eycuVK5xjorXxleXk506ZNo1WrVphMJlJSUrjrrruqZQCq6ZyaSsAVFhYydepUt9+97777KCkpcWun0+m4++67+d///keHDh0IDQ2la9eubmPejBkzePDBBwFo1apVtfJJCxYs4OKLLyYpKQmz2UyHDh145JFH3I41adIk3njjDecxlVd6errHc6iNTnr++ed58cUXadWqFeHh4fTt25e1a9eqXnt/kJeXx4033khsbCxhYWGMHTuWgwcPqn6nNvMBgH379jFhwgS366Rcaw0Njb83OTk5xMfHV7MbAfT66m6CBQsW0LdvX8LCwggPD2f48OFs3ry5Wrt169YxduxY4uLiCAkJIS0tjfvuu8+tze+//87QoUOJiIggNDSUfv36sWTJErc2ylx/xYoVTJ48mfj4eOLi4rj88ss5fvy4W1uLxcJDDz3ktFEvuOAC1q9f7/O1yM3N5c477yQlJQWTyUTr1q157LHHqtmoit57++236dChA8HBwfzf//2f87PTx9jMzExuv/12UlNTMZlMtGrVipkzZ7otpPRVF3nThW+88QYXXnghTZs2JSwsjM6dOzN37lw3+2fQoEEsWbKEw4cPu/1G1fM7/Rx27NjBuHHjiImJISQkhG7dujnPWUGx/T/99FMee+wxkpOTiYyM5KKLLmLv3r0+34eGRm1eJoTgzTffpFu3bpjNZmJiYhg/fnw1PSuEYO7cubRo0YKQkBC6d+/O0qVLA3E6Ghp+4ZprrgHg008/db5XUFDAV199xU033VTjd/ztV/HX82u323nttdecx4mOjqZPnz589913bm3mzp3r9AE2bdqUG264wemrUxg0aBCdOnVizZo19OvXD7PZTMuWLfnwww8BWS2ge/fuhIaG0rlz52oBtdr48XyVyZufEdztrF9//dWr327jxo1ccsklxMbGEhISwnnnncfnn3/u0/V+6623SExMZNiwYdU+++CDD+jatSshISHExsZy2WWXsXv3bufnL7/8Mjqdjv3791f77sMPP4zJZCI7O9v53s8//8zQoUOJjIwkNDSU/v3788svv7h9T02H1IQvdi24fOM7d+5k6NChhIWF0aRJE+6++27VZ6ExUGTZs2cPw4cPJywsjKSkJGfcYO3atVxwwQWEhYXRtm3bavr/1KlT3HnnnZx77rmEh4fTtGlThgwZwqpVq6odKyMjg/HjxxMREUF0dDTXXnstGzZsqNF29aUf+TpPVPOz+BoXADCZTFx11VW8++67DRqbOBvRMhP/JthsNlasWEGPHj08ZhM2a9aM888/n+XLl2Oz2TAYDM7PLr/8cq6++mruuOOOagNdVW688UYWLFjAQw89xJAhQ9i1axeXXXaZz6uTLBYLl1xyCTfffDMPPPAAv/32G0899RRRUVE8+eSTznbp6encfvvtNG/eHJAD2D333MOxY8fc2tWHiooKcnNzmTp1KikpKVRWVvLzzz9z+eWX8+GHH3LDDTcAcO+99zJu3Dh++eUXLrroIuf3ly5dyoEDB5yBNbvdzrhx41i1ahUPPfQQ/fr14/Dhw0yfPp1BgwaxceNGt8zDTZs2sXv3bh5//HFatWpFWFhYjXKWlJQwbNgwWrVqxRtvvEFCQgKZmZmsWLGCoqKiOp//ZZddxpVXXskdd9zBzp07eeKJJ9i1axfr1q0jKCjI2W7Lli3cd999zJgxg8TERObPn8+9995LZWUlU6dOBaQC6devH5WVlTz11FO0bNmSxYsXM3XqVA4cOMCbb77pduxXX32Vtm3b8vzzzxMZGUlCQgIffvghN954I48//rgzQOtLZuwtt9zC5ZdfzmeffcbmzZt59NFHsVqt7N27l8svv5zbbruNn3/+mWeffZbk5GT+/e9/O7/rSz9LT09n9OjRDBgwgA8++IDo6GiOHTvGDz/8QGVlZY2rkvLz87n88svZvXs3K1eu5Pzzz6/l3dHQ0DhTqCl7uibHa1Vq0qmjRo3CZrMxd+5cmjdvTnZ2NqtXr3YG/r7++mvGjx9PVFSUc8wMDg72eAwhBJdeeim//PIL06ZNY8CAAWzbto3p06c7y7FW/b6vOqe0tJSBAweSkZHBo48+SpcuXdi5cydPPvkk27dv5+eff3ZzPC5ZsoQNGzYwa9YswsPDmTt3Lpdddhl79+6ldevW3HLLLeTm5vLaa6+xcOFCkpKSADj33HMBGcwaNWoU9913H2FhYezZs4dnn32W9evXs3z5cgCeeOIJSkpK+PLLL93Kryu/dTq11UlvvPEG7du3d5Z9e+KJJxg1ahSHDh0iKirK4z1obG6++WaGDRvGJ598wtGjR3n88ccZNGgQ27ZtIzo6ut6/v2vXLvr160fz5s154YUXSExMZNmyZUyZMoXs7GymT59e/5PQ0NA4Y+nbty/vvfceU6ZM4dprr6V79+5uNkBVnn76aR5//HHnXL2yspLnnnuOAQMGsH79eueYvmzLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1800x500 with 4 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Composite of the two fitted Si [110] grain reconstructions.\n",
|
||||
"# Run the first-grid and second-grid cells before this cell.\n",
|
||||
"def display_strength(filtered_image):\n",
|
||||
" amplitude = np.abs(filtered_image)\n",
|
||||
" low, high = np.percentile(amplitude, (1, 99.5))\n",
|
||||
" if high == low:\n",
|
||||
" return np.zeros_like(amplitude)\n",
|
||||
" return np.clip((amplitude - low) / (high - low), 0, 1)\n",
|
||||
"\n",
|
||||
"first_blue = display_strength(si110_grid_image)\n",
|
||||
"second_red = display_strength(second_grain_image)\n",
|
||||
"\n",
|
||||
"# Use the original layer as a real-space support mask. Pixels below this\n",
|
||||
"# contrast level cannot receive Fourier-filtered color.\n",
|
||||
"mask_low, mask_high = np.percentile(layer, (5, 95))\n",
|
||||
"support_threshold = 0.5 # increase to reject more low-signal pixels\n",
|
||||
"if mask_high == mask_low:\n",
|
||||
" original_mask = np.ones(layer.shape, dtype=bool)\n",
|
||||
"else:\n",
|
||||
" original_support = np.clip((layer - mask_low) / (mask_high - mask_low), 0, 1)\n",
|
||||
" original_mask = original_support >= support_threshold\n",
|
||||
"\n",
|
||||
"composite = np.zeros((*layer.shape, 3))\n",
|
||||
"composite[..., 0] = second_red # second orientation: red\n",
|
||||
"composite[..., 1] = first_blue # first orientation: blue\n",
|
||||
"composite *= original_mask[..., None]\n",
|
||||
"\n",
|
||||
"first_rgb = np.zeros_like(composite)\n",
|
||||
"first_rgb[..., 1] = first_blue\n",
|
||||
"first_rgb *= original_mask[..., None]\n",
|
||||
"second_rgb = np.zeros_like(composite)\n",
|
||||
"second_rgb[..., 0] = second_red\n",
|
||||
"second_rgb *= original_mask[..., None]\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 4, figsize=(18, 5), constrained_layout=True)\n",
|
||||
"axes[0].imshow(original_mask, cmap='gray'); axes[0].set_title('Original-layer support mask')\n",
|
||||
"axes[1].imshow(first_rgb); axes[1].set_title('First orientation — blue')\n",
|
||||
"axes[2].imshow(second_rgb); axes[2].set_title('Second orientation — red')\n",
|
||||
"axes[3].imshow(composite); axes[3].set_title('Masked composite (overlap = magenta)')\n",
|
||||
"for ax in axes:\n",
|
||||
" ax.axis('off')\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "216b020a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"id": "25609e99",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Saved (32, 379, 379, 3) RGB stack to /home/swim/sandbox/silicon-grain-boundaries/colored.tiff\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAeEAAAH2CAYAAABHmTQtAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsnXecXNV5v587vW3vXaveGyDRhRC9d2Njg+3EODiOSeIkduK4l7jgOAlOwHZibAPGmN6RBEJCQkK9d2l7b9P7zD2/P85ISLBzZ3ZnNSP7N8/nMzY7Onfn7Mzc857zlu+rCCEEefLkyZMnT56so8v1BPLkyZMnT57/X8kb4Tx58uTJkydH5I1wnjx58uTJkyPyRjhPnjx58uTJEXkjnCdPnjx58uSIvBHOkydPnjx5ckTeCOfJkydPnjw5Im+E8+TJkydPnhyRN8J58uTJkydPjsgb4TwfYc+ePXzmM5+hubkZi8WCw+Fg8eLF/PjHP2ZkZGTMv+/Tn/40kyZNmviJZkBbWxuKovCb3/wmK6/38MMPM3XqVEwmE4qi4HK5svK6ZyPf+ta3UBQl19MYN//6r//KDTfcQF1dHYqi8OlPfzrpWCEEjz32GEuWLMFut1NYWMjixYt56aWXsjfhPGc1eSOc5zR+9atfcc4557B161b+8R//kTfffJMXXniBO++8k0cffZS/+Iu/yPUU/+TYtWsXX/rSl1i+fDlr1qxh06ZNFBQU5HpaecbJz372M4aHh7npppswmUyaYx944AEeeOABVqxYwcsvv8wzzzzDJz7xCQKBQJZmm+dsx5DrCeQ5e9i0aRMPPPAAV155JS+++CJms/nkv1155ZV8+ctf5s0338zhDCXBYBCr1ZrT17dYLGmf5vbv3w/A5z73OZYsWTIhcwgEAthstgn5XXlOJ9V76/V60enk+eXxxx9POu7FF1/kF7/4BU8//TR33XXXyeevvvrqiZtsnj958ifhPCf5wQ9+gKIo/PKXvzzNAJ/AZDJx0003nfxZVVV+/OMfM3PmTMxmM5WVldx77710dXWlfK1QKMQ///M/09zcjMlkoq6ujr/+67/+iJt20qRJ3HDDDTz//PMsWrQIi8XCt7/9bQD6+vr4/Oc/T319PSaTiebmZr797W8Ti8VO+x09PT3cddddFBQUUFRUxMc+9jH6+vrSek9+85vfoCgKq1at4rOf/SwVFRXYbDbC4TAATz/9NBdccAF2ux2Hw8HVV1/Nzp07T15/2WWX8clPfhKApUuXfsR9+dZbb7FixQoKCwux2WxcdNFFvP3226fN4YT7dseOHdxxxx2UlJQwZcoUQLo7/+d//oeFCxditVopKSnhjjvuoKWl5bTfcdlllzF37ly2bt3KJZdcgs1mY/Lkyfzwhz9EVdXTxrpcLr785S8zefLkk5/rddddx6FDh06OiUQifO973zv52VdUVPCZz3yGwcHBtN7XD/P0009z1VVXUVNTg9VqZdasWXz1q1/F7/efHPP444+jKAqbNm36yPXf+c53MBqN9PT0TNh7m4wTBjgV//mf/8mkSZNOM8B58nwEkSePECIWiwmbzSaWLl2a9jX333+/AMQXv/hF8eabb4pHH31UVFRUiIaGBjE4OHhy3H333SeamppO/qyqqrj66quFwWAQX//618WqVavEQw89JOx2u1i0aJEIhUInxzY1NYmamhoxefJk8etf/1q88847YsuWLaK3t1c0NDSIpqYm8Ytf/EK89dZb4rvf/a4wm83i05/+9MnrA4GAmDVrligqKhIPP/ywWLlypfjSl74kGhsbBSAee+wxzb/xscceE4Coq6sT999/v3jjjTfEs88+K2KxmPj+978vFEURn/3sZ8Wrr74qnn/+eXHBBRcIu90u9u/fL4QQYv/+/eJf//VfT77Wpk2bxLFjx4QQQjz++ONCURRxyy23iOeff1688sor4oYbbhB6vV689dZbJ+fwzW9+UwCiqalJfOUrXxGrV68WL774ohBCiM997nPCaDSKL3/5y+LNN98Uv//978XMmTNFVVWV6OvrO/k7li1bJsrKysS0adPEo48+KlavXi2+8IUvCED89re/PTnO4/GIOXPmCLvdLr7zne+IlStXiueee048+OCDYs2aNUIIIeLxuLjmmmuE3W4X3/72t8Xq1avF//7v/4q6ujoxe/ZsEQgENN/TE3/PqXz3u98VP/vZz8Rrr70m1q5dKx599FHR3Nwsli9ffnJMOBwW1dXV4p577jnt2mg0Kmpra8Wdd9558rmJeG/TwW63i/vuu+8jz0ejUWE2m8Wtt94qfvrTn4rGxkah0+lEc3Oz+MlPfiJUVU37NfL8eZM3wnmEEEL09fUJQNx9991pjT948KAAxBe+8IXTnt+8ebMAxL/8y7+cfO7DRvjNN98UgPjxj3982rVPP/20AMQvf/nLk881NTUJvV4vDh8+fNrYz3/+88LhcIj29vbTnn/ooYcEcNIIPvLIIwIQL7300mnjPve5z43JCN97772nPd/R0SEMBoP4m7/5m9Oe93q9orq6Wtx1110f+R1bt249+Zzf7xelpaXixhtvPO36eDwuFixYIJYsWXLyuROG4hvf+MZpYzdt2iQA8dOf/vS05zs7O4XVahX/9E//dPK5ZcuWCUBs3rz5tLGzZ88WV1999cmfv/Od7whArF69Oul78tRTTwlAPPfcc6c9v3XrVgGI//mf/0l67al/TzJUVRXRaFSsW7dOAGL37t2nXWsymUR/f//J5058b9atWyeEmJj3Nl2SGeHe3l4BiMLCQlFfXy9++9vfirffflv81V/91Ufujzz/f5N3R+cZF++88w7ARzJDlyxZwqxZsz7i9juVNWvWjHrtnXfeid1u/8i18+fPZ/r06ac99+qrr7J8+XJqa2uJxWInH9deey0A69atOznPgoKC09zoAJ/4xCfS+0MT3H777af9vHLlSmKxGPfee+9pr2+xWFi2bBlr167V/H0bN25kZGSE++6777TrVVXlmmuuYevWrae5Ykebw6uvvoqiKHzyk5887XdUV1ezYMGCj8yhurr6IzHp+fPn097efvLnN954g+nTp3PFFVcknfurr75KcXExN95442mvu3DhQqqrq1P+7aPR0tLCJz7xCaqrq9Hr9RiNRpYtWwbAwYMHT4574IEHAJlAeIKf//znzJs3j0svvRSYmPc2U064+D0eD8888wz33nsvl19+OY888gi33HIL//7v/47P55vQ18zzp0k+MSsPAOXl5dhsNlpbW9MaPzw8DEBNTc1H/q22tva0hX20aw0GAxUVFac9rygK1dXVJ3/3CUZ7jf7+fl555RWMRuOorzE0NHTytaqqqj7y79XV1UnnNxofnkN/fz8A55133qjjU8UNT1x/xx13JB0zMjKC3W7XnIMQYtS/D2Dy5Mmn/VxWVvaRMWazmWAwePLnwcFBGhsbU87d5XIlzQw+8d6ni8/n45JLLsFisfC9732P6dOnY7PZ6Ozs5LbbbjttflVVVXzsYx/jF7/4BV/96lfZv38/69ev5xe/+MVp84PM3ttMKSkpQVEUCgoKOP/880/7t2uvvZYXX3yRAwcOTFiiXp4/XfJGOA8Aer2eFStW8MYbb9DV1UV9fb3m+BMLem9v70fG9vT0UF5ernltLBZjcHDwNEMshKCvr+8jhm20LOTy8nLmz5/P97///VFfo7a29uRrbdmy5SP/nm5iVrI5nPj7nn32WZqamsb0u069/uGHH/7IIn2CDxvX0eagKArr168fNZFutOdSUVFRkTKxrry8nLKysqSZ8mMtv1qzZg09PT2sXbv25OkXSFpL/eCDD/L444/z0ksv8eabb1JcXMw999xz2vwgs/c2U6xWK9OmTRv1eyaEANJP8Mrz503eCOc5yT//8z/z+uuv87nPfY6XXnrpIyedaDTKm2++yY033sjll18OwBNPPHGa0dy6dSsHDx7ka1/7WtLXWbFiBT/+8Y954okn+Lu/+7uTzz/33HP4/X5WrFiRcq433HADr7/+OlOmTKGkpCTpuOXLl/PHP/6Rl19++TSX9O9///uUr6HF1VdfjcFg4Pjx4+NyZV500UUUFxdz4MABvvjFL45rDjfccAM//OEP6e7unrAM3GuvvZZvfOMbrFmz5uRnPNrr/uEPfyAej7N06dKMX/OEAfzwpuHU0+2pnHPOOVx44YX86Ec/Yt++fdx///2nnWon4r2dCG6//Xb+7d/+jY0bN3LhhReefP7111/H4XAwZ86cnM0tz9lD3gjnOckFF1zAI488whe+8AXOOeccHnjgAebMmUM0GmXnzp388pe/ZO7cudx4443MmDGD+++/n4cffhidTse1115LW1sbX//612loaDjNuH6YK6+8kquvvpqvfOUreDweLrroIvbs2cM3v/lNFi1axKc+9amUc/3Od77D6tWrufDCC/nSl77EjBkzCIVCtLW18frrr/Poo49SX1/Pvffey89+9jPuvfdevv/97zNt2jRef/11Vq5cmdF7NWnSJL7zne/wta99jZaWFq655hpKSkro7+9ny5Yt2O32k6VUo+FwOHj44Ye57777GBkZ4Y477qCyspLBwUF2797N4OAgjzzyiOYcLrroIu6//34+85nPsG3bNi699FLsdju9vb1s2LCBefPmnYyhpsvf/u3f8vTTT3PzzTfz1a9+lSVLlhAMBlm3bh033HADy5cv5+677+bJJ5/kuuuu48EHH2TJkiUYjUa6urp45513uPnmm7n11lvTfs0LL7yQkpIS/uqv/opvfvObGI1GnnzySXbv3p30mgcffJCPfexjKIrCF77whdP+bSLeWy3WrVt3shQrHo/T3t7Os88+C8CyZctOenf+4R/+gSeffJI777yT7373u9TX1/Pss8/y8ssv89BDD+W01j3PWUSOE8PynIXs2rVL3HfffaKxsVGYTKaTpUPf+MY3xMDAwMlLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 600x600 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Color the complete TIFF stack using the two orientations fitted on the reference layer.\n",
|
||||
"# Run the first-grid and second-grid cells before this cell.\n",
|
||||
"volume = image.astype(float)\n",
|
||||
"\n",
|
||||
"# Fixed reciprocal-space masks from the reference layer are applied to every TIFF layer.\n",
|
||||
"fft_volume = np.fft.fftshift(np.fft.fft2(volume, axes=(-2, -1)), axes=(-2, -1))\n",
|
||||
"first_volume = np.fft.ifft2(\n",
|
||||
" np.fft.ifftshift(fft_volume * si110_grid_mask[None, :, :], axes=(-2, -1)), axes=(-2, -1)\n",
|
||||
").real\n",
|
||||
"second_volume = np.fft.ifft2(\n",
|
||||
" np.fft.ifftshift(fft_volume * second_mask[None, :, :], axes=(-2, -1)), axes=(-2, -1)\n",
|
||||
").real\n",
|
||||
"\n",
|
||||
"def normalize_volume(filtered_volume):\n",
|
||||
" amplitude = np.abs(filtered_volume)\n",
|
||||
" low, high = np.percentile(amplitude, (1, 99.5))\n",
|
||||
" if high == low:\n",
|
||||
" return np.zeros_like(amplitude)\n",
|
||||
" return np.clip((amplitude - low) / (high - low), 0, 1)\n",
|
||||
"\n",
|
||||
"first_blue_volume = normalize_volume(first_volume)\n",
|
||||
"second_red_volume = normalize_volume(second_volume)\n",
|
||||
"\n",
|
||||
"# Build an original-image support mask per layer to suppress Fourier ringing.\n",
|
||||
"stack_support_threshold = globals().get('support_threshold', 0.5)\n",
|
||||
"support_volume = np.zeros(volume.shape, dtype=bool)\n",
|
||||
"for index, original_layer in enumerate(volume):\n",
|
||||
" low, high = np.percentile(original_layer, (5, 95))\n",
|
||||
" if high == low:\n",
|
||||
" support_volume[index] = True\n",
|
||||
" else:\n",
|
||||
" scaled = np.clip((original_layer - low) / (high - low), 0, 1)\n",
|
||||
" support_volume[index] = scaled >= stack_support_threshold\n",
|
||||
"\n",
|
||||
"colored_stack = np.zeros((*volume.shape, 3), dtype=np.uint8)\n",
|
||||
"colored_stack[..., 0] = np.round(255 * second_red_volume * support_volume).astype(np.uint8) # second: red\n",
|
||||
"colored_stack[..., 1] = np.round(255 * first_blue_volume * support_volume).astype(np.uint8) # first: blue\n",
|
||||
"\n",
|
||||
"output_path = os.path.abspath('colored.tiff')\n",
|
||||
"tifffile.imwrite(output_path, colored_stack, photometric='rgb', metadata={'axes': 'ZYXS'})\n",
|
||||
"print(f'Saved {colored_stack.shape} RGB stack to {output_path}')\n",
|
||||
"\n",
|
||||
"reference_index = image.shape[0] // 2\n",
|
||||
"plt.figure(figsize=(6, 6))\n",
|
||||
"plt.imshow(colored_stack[reference_index])\n",
|
||||
"plt.title(f'Colored reference layer {reference_index}')\n",
|
||||
"plt.axis('off')\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 70,
|
||||
"id": "colored-alpha-stack",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Saved (32, 379, 379, 3) RGBA stack to /home/swim/sandbox/silicon-grain-boundaries/colored_alpha.tiff\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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H/zgB/zRH/0Rra2tRCIRVq9ezV/91V+VvOvtb387X/3qV/U75ae3t/eMfejv7+fNb34zTU1NhEIhVq9ezZe+9CVs29bXyHfXF7/4Rb785S+zePFiKioquOiii3jyySfPag6GhoZ497vfTWdnJ8FgkLa2Nm6++eaS9fRS2vKFL3yBz33ucyxatIhIJMLll1/OkSNHyOfz/NVf/RVtbW1UV1dz4403MjY2VtIWmed77rmHDRs2EA6HWbJkCf/0T/90WrvPpk3w4vLEfNn0xebqbOW6Mv4wUbaAl4FlWTz88MOcd955Z7Rad3Z2snnzZrZv345lWfh8Pv231772tbzhDW/gf/yP/3Hal5YX73jHO/jBD37ARz7yEa688koOHjzIjTfeyNzc3Fm1M5/Pc8MNN/Cud72LD33oQzz22GP87d/+LdXV1XziE5/Q1/X29vKe97yHrq4uQMW1/9mf/RlDQ0Ml1/0mOJt3/Pmf/zl33nkn3/ve97j11lv1vQcPHuThhx/WBzfAe97zHr797W/zgQ98gM997nNMTU1xxx13sHXrVvbt20dzc7O+dnh4mDe/+c185CMf4R/+4R8wzd9cj/b973+f9773vfzZn/0ZX/ziFzFNk2PHjnHw4EF9zcjICFu2bME0TT7xiU+wdOlSdu7cyd/93d/R29vLt771LUBZG175yldy6tQpPvOZz7BixQruvfdeXv/6159VW6ampgD45Cc/SUtLC4lEgnvuuYfLL7+chx56SCsUzqbNZ8Jvukb+z//5P3R3d/OVr3wF27b5/Oc/zzXXXMOjjz7KRRddVHLtTTfdxOtf/3re9a538dxzz/HRj34UgDvvvFNfc/z4cW655RYtBO7bt4+///u/59ChQyXXlVFGGWX8ujh58iRAiWX64YcfplAocMMNN7zk5zmOo5WvmUyG3bt385WvfIVt27axePHikmsHBwf5xS9+wU033URjYyNve9vb+Lu/+zsee+wxLrvsshd9z2te8xoeeughPvrRj3LJJZewf/9+PvnJT2oX+FAopK/fs2cPPT09/PVf/zWLFy8mFost+NxUKsVll13G4OAgH/vYx9iwYQMHDhzgE5/4BM899xy//OUvSwwJ9957L7t37+aOO+6goqKCz3/+89x4440cPnyYJUuWcOuttzI1NcX//t//mx/96Ee0trYCsGbNGgCOHj3Ktddey+23304sFuPQoUN87nOfY9euXWzfvh2Av/mbvyGZTHL33XeXhPHJs+ZjfHycrVu3ksvl+Nu//VsWLVrEz372Mz784Q9z/Phxvva1r5Vc/9WvfpVVq1bxla98Rb/v2muv5eTJk1p5shCGhoY4//zzyefzeqwmJyd54IEHmJ6eprm5+ddqy4YNG/jqV7/KzMwMH/rQh3j1q1/NBRdcQCAQ4M4776Svr48Pf/jD3HrrrfzkJz8puX/v3r3cfvvtfOpTn6KlpYXvfve7/Pmf/zm5XI4Pf/jDL2l8fh154sXm6qXIdWX8AcIp4w8eIyMjDuC84Q1veMHrXv/61zuAMzo66jiO43zyk590AOcTn/jEadfK3wQHDhxwAOcv//IvS677j//4Dwdw3va2t+nPHn74YQdwHn74Yf3Z2972Ngdw/vM//7Pk/muvvdZZuXLlGdtsWZaTz+edO+64w6mvr3ds29Z/u+yyy5zLLrvsBft8Nte92DvOOeeckutvu+02p6qqyonH447jOM7OnTsdwPnSl75Uct3AwIATiUScj3zkIyXPA5yHHnroRdv9Qm1/29ve5nR3d+vf3//+9zs1NTUv+Kz3vOc9TkVFhdPX11fy+Re/+EUHcA4cOOA4juN8/etfdwDnv//7v0uu+9M//VMHcL71rW+dVdsFhULByefzzite8QrnxhtvfEltPhu8lDVy8uRJB3Da2tqcdDqtP5+bm3Pq6uqcV77ylfoz2QOf//znS9733ve+1wmHwyXvWag93/nOdxyfz+dMTU39xn0so4wy/nDwrW99ywGcJ5980snn8048Hnd+/vOfOy0tLc6ll17q5PN5fe1nP/tZB3B+/vOfn/acfD5f8uNFd3e3A5z2s2XLFmd4ePi0Z91xxx0l7zlx4oRjGIbzlre85UX78/Of/3zBs/QHP/iBAzj/8i//UtIun8/nHD58+LTndHd3l8gan/nMZxzTNJ3du3eXXHf33Xc7gHPffffpzwCnubnZmZub05+NjIw4pmk6n/nMZ/RnX/jCFxzAOXny5Av2ybZtJ5/PO48++qgDOPv27dN/e9/73uecSTyf34e/+qu/cgDnqaeeKrnutttucwzD0OMg313r1693CoWCvm7Xrl0O4PzHf/zHC7b3ne98pxMIBJyDBw+e8ZqX2paNGzc6lmXp677yla84gHPDDTeU3H/77bc7gDM7O1syDoZhOHv37i259qqrrnKqqqqcZDL5ktp0NvLEQrLpmebqpch1ZfxhouyCXsZZw3Fdxea7lt90000veu+jjz4KwOte97qSz2+++ebTXN7PBMMwePWrX13y2YYNG+jr6yv5bPv27bzyla+kuroan89HIBDgE5/4BJOTk6e5Mf2Line truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1000x500 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# RGBA version: use the original TIFF intensity as continuous alpha, not a cutoff mask.\n",
|
||||
"# Run the two orientation-filter cells first. Output: ./colored_alpha.tiff\n",
|
||||
"volume = image.astype(float)\n",
|
||||
"fft_volume = np.fft.fftshift(np.fft.fft2(volume, axes=(-2, -1)), axes=(-2, -1))\n",
|
||||
"first_volume = np.fft.ifft2(\n",
|
||||
" np.fft.ifftshift(fft_volume * si110_grid_mask[None, :, :], axes=(-2, -1)), axes=(-2, -1)\n",
|
||||
").real\n",
|
||||
"second_volume = np.fft.ifft2(\n",
|
||||
" np.fft.ifftshift(fft_volume * second_mask[None, :, :], axes=(-2, -1)), axes=(-2, -1)\n",
|
||||
").real\n",
|
||||
"\n",
|
||||
"def normalize_for_display(values, percentiles=(1, 99.5)):\n",
|
||||
" low, high = np.percentile(values, percentiles)\n",
|
||||
" if high == low:\n",
|
||||
" return np.zeros_like(values)\n",
|
||||
" return np.clip((values - low) / (high - low), 0, 1)\n",
|
||||
"\n",
|
||||
"# RGB encodes filtered orientation strength; alpha continuously follows original intensity.\n",
|
||||
"first_blue_volume = normalize_for_display(np.abs(first_volume))\n",
|
||||
"second_red_volume = normalize_for_display(np.abs(second_volume))\n",
|
||||
"original_alpha = beta.cdf(normalize_for_display(volume), 3, 8)\n",
|
||||
"\n",
|
||||
"colored_alpha_stack = np.zeros((*volume.shape, 3), dtype=np.uint8)\n",
|
||||
"colored_alpha_stack[..., 0] = np.round(255 * (second_red_volume * (original_alpha))).astype(np.uint8) # second: red\n",
|
||||
"colored_alpha_stack[..., 1] = np.round(255 * (first_blue_volume * (original_alpha))).astype(np.uint8) # first: blue\n",
|
||||
"# colored_alpha_stack[..., 2] = np.ones_like(original_alpha) * 255\n",
|
||||
"# colored_alpha_stack[..., 3] = np.round(255 * (original_alpha)).astype(np.uint8) # original: alpha\n",
|
||||
"\n",
|
||||
"output_path = os.path.abspath('colored_alpha.tiff')\n",
|
||||
"tifffile.imwrite(\n",
|
||||
" output_path, colored_alpha_stack, photometric='rgb', extrasamples='unassalpha',\n",
|
||||
" metadata={'axes': 'ZYXS'},\n",
|
||||
")\n",
|
||||
"print(f'Saved {colored_alpha_stack.shape} RGBA stack to {output_path}')\n",
|
||||
"\n",
|
||||
"reference_index = image.shape[0] // 2\n",
|
||||
"fig, axes = plt.subplots(1, 2, figsize=(10, 5), constrained_layout=True)\n",
|
||||
"axes[0].imshow(original_alpha[reference_index], cmap='gray', vmin=0, vmax=1)\n",
|
||||
"axes[0].set_title('Original layer used as alpha')\n",
|
||||
"axes[1].imshow(colored_alpha_stack[reference_index])\n",
|
||||
"axes[1].set_title('RGBA orientation composite')\n",
|
||||
"for ax in axes:\n",
|
||||
" ax.axis('off')\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 69,
|
||||
"id": "05c7b076",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[<matplotlib.lines.Line2D at 0x7f03c9cd2270>]"
|
||||
]
|
||||
},
|
||||
"execution_count": 69,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 640x480 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from scipy.stats import beta\n",
|
||||
"\n",
|
||||
"x = np.linspace(0, 1)\n",
|
||||
"\n",
|
||||
"plt.plot(x, beta.cdf(x, 4, 8))"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "lemon",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in new issue
Block a user