kerzel commited on
Commit
67d93b2
·
1 Parent(s): 3da374f

update versions

Browse files
Files changed (3) hide show
  1. app.py +4 -3
  2. requirements.txt +103 -102
  3. utils.py +82 -108
app.py CHANGED
@@ -139,11 +139,12 @@ with gr.Blocks() as app:
139
  gr.Markdown('The models used in this app are based on the following papers:')
140
  gr.Markdown('Kusche, C., Reclik, T., Freund, M., Al-Samman, T., Kerzel, U., & Korte-Kerzel, S. (2019). Large-area, high-resolution characterisation and classification of damage mechanisms in dual-phase steel using deep learning. PloS one, 14(5), e0216493. [Link](https://doi.org/10.1371/journal.pone.0216493)')
141
  #gr.Markdown('Medghalchi, S., Kusche, C. F., Karimi, E., Kerzel, U., & Korte-Kerzel, S. (2020). Damage analysis in dual-phase steel using deep learning: transfer from uniaxial to biaxial straining conditions by image data augmentation. Jom, 72, 4420-4430. [Link](https://link.springer.com/article/10.1007/s11837-020-04404-0)')
142
- gr.Markdown('Setareh Medghalchi, Ehsan Karimi, Sang-Hyeok Lee, Benjamin Berkels, Ulrich Kerzel, Sandra Korte-Kerzel, Three-dimensional characterisation of deformation-induced damage in dual phase steel using deep learning, Materials & Design, Volume 232, 2023, 112108, ISSN 0264-1275, [link] (https://doi.org/10.1016/j.matdes.2023.112108)')
143
  gr.Markdown('Original data and code, including the network weights, can be found at Zenodo [link](https://zenodo.org/records/8065752)')
144
 
145
- image_input = gr.Image()
146
- with gr.Row():
 
147
  cluster_threshold_input = gr.Number(label='Cluster Threshold', value = 20,
148
  info='Grayscale value at which a pixel is attributed to a potential damage site')
149
  model1_threshold_input = gr.Number(label='Model 1 Threshold', value = 0.7, info='Threshold for the model identifying inclusions')
 
139
  gr.Markdown('The models used in this app are based on the following papers:')
140
  gr.Markdown('Kusche, C., Reclik, T., Freund, M., Al-Samman, T., Kerzel, U., & Korte-Kerzel, S. (2019). Large-area, high-resolution characterisation and classification of damage mechanisms in dual-phase steel using deep learning. PloS one, 14(5), e0216493. [Link](https://doi.org/10.1371/journal.pone.0216493)')
141
  #gr.Markdown('Medghalchi, S., Kusche, C. F., Karimi, E., Kerzel, U., & Korte-Kerzel, S. (2020). Damage analysis in dual-phase steel using deep learning: transfer from uniaxial to biaxial straining conditions by image data augmentation. Jom, 72, 4420-4430. [Link](https://link.springer.com/article/10.1007/s11837-020-04404-0)')
142
+ gr.Markdown('Setareh Medghalchi, Ehsan Karimi, Sang-Hyeok Lee, Benjamin Berkels, Ulrich Kerzel, Sandra Korte-Kerzel, Three-dimensional characterisation of deformation-induced damage in dual phase steel using deep learning, Materials & Design, Volume 232, 2023, 112108, ISSN 0264-1275, [link] (https://doi.org/10.1016/j.matdes.2023.112108')
143
  gr.Markdown('Original data and code, including the network weights, can be found at Zenodo [link](https://zenodo.org/records/8065752)')
144
 
145
+ #image_input = gr.Image(value='data/X4-Aligned_cropped_upperleft_small.png', label='Example SEM Image (DP800 steel)',)
146
+ image_input = gr.Image()
147
+ with gr.Row():
148
  cluster_threshold_input = gr.Number(label='Cluster Threshold', value = 20,
149
  info='Grayscale value at which a pixel is attributed to a potential damage site')
150
  model1_threshold_input = gr.Number(label='Model 1 Threshold', value = 0.7, info='Threshold for the model identifying inclusions')
requirements.txt CHANGED
@@ -1,102 +1,103 @@
1
- absl-py==2.1.0 ; python_version >= "3.10" and python_version < "3.12"
2
- aiofiles==23.2.1 ; python_version >= "3.10" and python_version < "3.12"
3
- altair==5.2.0 ; python_version >= "3.10" and python_version < "3.12"
4
- annotated-types==0.6.0 ; python_version >= "3.10" and python_version < "3.12"
5
- anyio==4.3.0 ; python_version >= "3.10" and python_version < "3.12"
6
- astunparse==1.6.3 ; python_version >= "3.10" and python_version < "3.12"
7
- attrs==23.2.0 ; python_version >= "3.10" and python_version < "3.12"
8
- cachetools==5.3.3 ; python_version >= "3.10" and python_version < "3.12"
9
- certifi==2024.2.2 ; python_version >= "3.10" and python_version < "3.12"
10
- charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "3.12"
11
- click==8.1.7 ; python_version >= "3.10" and python_version < "3.12"
12
- colorama==0.4.6 ; python_version >= "3.10" and python_version < "3.12"
13
- contourpy==1.2.0 ; python_version >= "3.10" and python_version < "3.12"
14
- cycler==0.12.1 ; python_version >= "3.10" and python_version < "3.12"
15
- exceptiongroup==1.2.0 ; python_version >= "3.10" and python_version < "3.11"
16
- fastapi==0.110.0 ; python_version >= "3.10" and python_version < "3.12"
17
- ffmpy==0.3.2 ; python_version >= "3.10" and python_version < "3.12"
18
- filelock==3.13.1 ; python_version >= "3.10" and python_version < "3.12"
19
- flatbuffers==24.3.7 ; python_version >= "3.10" and python_version < "3.12"
20
- fonttools==4.50.0 ; python_version >= "3.10" and python_version < "3.12"
21
- fsspec==2024.3.1 ; python_version >= "3.10" and python_version < "3.12"
22
- gast==0.5.4 ; python_version >= "3.10" and python_version < "3.12"
23
- google-auth-oauthlib==1.2.0 ; python_version >= "3.10" and python_version < "3.12"
24
- google-auth==2.29.0 ; python_version >= "3.10" and python_version < "3.12"
25
- google-pasta==0.2.0 ; python_version >= "3.10" and python_version < "3.12"
26
- gradio-client==0.13.0 ; python_version >= "3.10" and python_version < "3.12"
27
- gradio==4.22.0 ; python_version >= "3.10" and python_version < "3.12"
28
- grpcio==1.62.1 ; python_version >= "3.10" and python_version < "3.12"
29
- h11==0.14.0 ; python_version >= "3.10" and python_version < "3.12"
30
- h5py==3.10.0 ; python_version >= "3.10" and python_version < "3.12"
31
- httpcore==1.0.4 ; python_version >= "3.10" and python_version < "3.12"
32
- httpx==0.27.0 ; python_version >= "3.10" and python_version < "3.12"
33
- huggingface-hub==0.21.4 ; python_version >= "3.10" and python_version < "3.12"
34
- idna==3.6 ; python_version >= "3.10" and python_version < "3.12"
35
- imageio==2.34.0 ; python_version >= "3.10" and python_version < "3.12"
36
- importlib-resources==6.4.0 ; python_version >= "3.10" and python_version < "3.12"
37
- jinja2==3.1.3 ; python_version >= "3.10" and python_version < "3.12"
38
- joblib==1.3.2 ; python_version >= "3.10" and python_version < "3.12"
39
- jsonschema-specifications==2023.12.1 ; python_version >= "3.10" and python_version < "3.12"
40
- jsonschema==4.21.1 ; python_version >= "3.10" and python_version < "3.12"
41
- keras==2.15.0 ; python_version >= "3.10" and python_version < "3.12"
42
- kiwisolver==1.4.5 ; python_version >= "3.10" and python_version < "3.12"
43
- libclang==18.1.1 ; python_version >= "3.10" and python_version < "3.12"
44
- markdown-it-py==3.0.0 ; python_version >= "3.10" and python_version < "3.12"
45
- markdown==3.6 ; python_version >= "3.10" and python_version < "3.12"
46
- markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "3.12"
47
- matplotlib==3.8.3 ; python_version >= "3.10" and python_version < "3.12"
48
- mdurl==0.1.2 ; python_version >= "3.10" and python_version < "3.12"
49
- ml-dtypes==0.2.0 ; python_version >= "3.10" and python_version < "3.12"
50
- numpy==1.26.4 ; python_version < "3.12" and python_version >= "3.10"
51
- oauthlib==3.2.2 ; python_version >= "3.10" and python_version < "3.12"
52
- opt-einsum==3.3.0 ; python_version >= "3.10" and python_version < "3.12"
53
- orjson==3.9.15 ; python_version >= "3.10" and python_version < "3.12"
54
- packaging==24.0 ; python_version >= "3.10" and python_version < "3.12"
55
- pandas==2.2.1 ; python_version >= "3.10" and python_version < "3.12"
56
- pillow==10.2.0 ; python_version >= "3.10" and python_version < "3.12"
57
- protobuf==4.25.3 ; python_version >= "3.10" and python_version < "3.12"
58
- pyasn1-modules==0.3.0 ; python_version >= "3.10" and python_version < "3.12"
59
- pyasn1==0.5.1 ; python_version >= "3.10" and python_version < "3.12"
60
- pydantic-core==2.16.3 ; python_version >= "3.10" and python_version < "3.12"
61
- pydantic==2.6.4 ; python_version >= "3.10" and python_version < "3.12"
62
- pydub==0.25.1 ; python_version >= "3.10" and python_version < "3.12"
63
- pygments==2.17.2 ; python_version >= "3.10" and python_version < "3.12"
64
- pyparsing==3.1.2 ; python_version >= "3.10" and python_version < "3.12"
65
- python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "3.12"
66
- python-multipart==0.0.9 ; python_version >= "3.10" and python_version < "3.12"
67
- pytz==2024.1 ; python_version >= "3.10" and python_version < "3.12"
68
- pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "3.12"
69
- referencing==0.34.0 ; python_version >= "3.10" and python_version < "3.12"
70
- requests-oauthlib==1.4.0 ; python_version >= "3.10" and python_version < "3.12"
71
- requests==2.31.0 ; python_version >= "3.10" and python_version < "3.12"
72
- rich==13.7.1 ; python_version >= "3.10" and python_version < "3.12"
73
- rpds-py==0.18.0 ; python_version >= "3.10" and python_version < "3.12"
74
- rsa==4.9 ; python_version >= "3.10" and python_version < "3.12"
75
- ruff==0.3.4 ; python_version >= "3.10" and python_version < "3.12"
76
- scikit-learn==1.4.1.post1 ; python_version >= "3.10" and python_version < "3.12"
77
- scipy==1.12.0 ; python_version >= "3.10" and python_version < "3.12"
78
- semantic-version==2.10.0 ; python_version >= "3.10" and python_version < "3.12"
79
- setuptools==69.2.0 ; python_version >= "3.10" and python_version < "3.12"
80
- shellingham==1.5.4 ; python_version >= "3.10" and python_version < "3.12"
81
- six==1.16.0 ; python_version >= "3.10" and python_version < "3.12"
82
- sniffio==1.3.1 ; python_version >= "3.10" and python_version < "3.12"
83
- starlette==0.36.3 ; python_version >= "3.10" and python_version < "3.12"
84
- tensorboard-data-server==0.7.2 ; python_version >= "3.10" and python_version < "3.12"
85
- tensorboard==2.15.2 ; python_version >= "3.10" and python_version < "3.12"
86
- tensorflow-estimator==2.15.0 ; python_version >= "3.10" and python_version < "3.12"
87
- tensorflow-io-gcs-filesystem==0.36.0 ; python_version >= "3.10" and python_version < "3.12"
88
- tensorflow==2.15.0 ; python_version >= "3.10" and python_version < "3.12"
89
- termcolor==2.4.0 ; python_version >= "3.10" and python_version < "3.12"
90
- threadpoolctl==3.4.0 ; python_version >= "3.10" and python_version < "3.12"
91
- tomlkit==0.12.0 ; python_version >= "3.10" and python_version < "3.12"
92
- toolz==0.12.1 ; python_version >= "3.10" and python_version < "3.12"
93
- tqdm==4.66.2 ; python_version >= "3.10" and python_version < "3.12"
94
- typer[all]==0.9.0 ; python_version >= "3.10" and python_version < "3.12"
95
- typing-extensions==4.10.0 ; python_version >= "3.10" and python_version < "3.12"
96
- tzdata==2024.1 ; python_version >= "3.10" and python_version < "3.12"
97
- urllib3==2.2.1 ; python_version >= "3.10" and python_version < "3.12"
98
- uvicorn==0.29.0 ; python_version >= "3.10" and python_version < "3.12"
99
- websockets==11.0.3 ; python_version >= "3.10" and python_version < "3.12"
100
- werkzeug==3.0.1 ; python_version >= "3.10" and python_version < "3.12"
101
- wheel==0.43.0 ; python_version >= "3.10" and python_version < "3.12"
102
- wrapt==1.14.1 ; python_version >= "3.10" and python_version < "3.12"
 
 
1
+ absl-py==2.3.0 ; python_version >= "3.11"
2
+ aiofiles==24.1.0 ; python_version >= "3.11"
3
+ annotated-types==0.7.0 ; python_version >= "3.11"
4
+ anyio==4.9.0 ; python_version >= "3.11"
5
+ astunparse==1.6.3 ; python_version >= "3.11"
6
+ audioop-lts==0.2.1 ; python_version >= "3.13"
7
+ certifi==2025.6.15 ; python_version >= "3.11"
8
+ charset-normalizer==3.4.2 ; python_version >= "3.11"
9
+ click==8.2.1 ; python_version >= "3.11" and sys_platform != "emscripten"
10
+ colorama==0.4.6 ; python_version >= "3.11" and platform_system == "Windows"
11
+ contourpy==1.3.2 ; python_version >= "3.11"
12
+ cycler==0.12.1 ; python_version >= "3.11"
13
+ fastapi==0.115.13 ; python_version >= "3.11"
14
+ ffmpy==0.6.0 ; python_version >= "3.11"
15
+ filelock==3.18.0 ; python_version >= "3.11"
16
+ flatbuffers==25.2.10 ; python_version >= "3.11"
17
+ fonttools==4.58.4 ; python_version >= "3.11"
18
+ fsspec==2025.5.1 ; python_version >= "3.11"
19
+ gast==0.6.0 ; python_version >= "3.11"
20
+ google-pasta==0.2.0 ; python_version >= "3.11"
21
+ gradio-client==1.10.3 ; python_version >= "3.11"
22
+ gradio==5.34.2 ; python_version >= "3.11"
23
+ groovy==0.1.2 ; python_version >= "3.11"
24
+ grpcio==1.73.0 ; python_version >= "3.11"
25
+ h11==0.16.0 ; python_version >= "3.11"
26
+ h5py==3.14.0 ; python_version >= "3.11"
27
+ hf-xet==1.1.5 ; python_version >= "3.11" and (platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "arm64" or platform_machine == "aarch64")
28
+ httpcore==1.0.9 ; python_version >= "3.11"
29
+ httpx==0.28.1 ; python_version >= "3.11"
30
+ huggingface-hub==0.33.0 ; python_version >= "3.11"
31
+ idna==3.10 ; python_version >= "3.11"
32
+ imageio==2.37.0 ; python_version >= "3.11"
33
+ jinja2==3.1.6 ; python_version >= "3.11"
34
+ joblib==1.5.1 ; python_version >= "3.11"
35
+ keras==3.10.0 ; python_version >= "3.11"
36
+ kiwisolver==1.4.8 ; python_version >= "3.11"
37
+ libclang==18.1.1 ; python_version >= "3.11"
38
+ markdown-it-py==3.0.0 ; python_version >= "3.11"
39
+ markdown==3.8.2 ; python_version >= "3.11"
40
+ markupsafe==3.0.2 ; python_version >= "3.11"
41
+ matplotlib==3.10.3 ; python_version >= "3.11"
42
+ mdurl==0.1.2 ; python_version >= "3.11"
43
+ ml-dtypes==0.5.1 ; python_version >= "3.11"
44
+ namex==0.1.0 ; python_version >= "3.11"
45
+ numpy==2.1.3 ; python_version >= "3.11"
46
+ nvidia-cublas-cu12==12.5.3.2 ; python_version >= "3.11"
47
+ nvidia-cuda-cupti-cu12==12.5.82 ; python_version >= "3.11"
48
+ nvidia-cuda-nvcc-cu12==12.5.82 ; python_version >= "3.11"
49
+ nvidia-cuda-nvrtc-cu12==12.5.82 ; python_version >= "3.11"
50
+ nvidia-cuda-runtime-cu12==12.5.82 ; python_version >= "3.11"
51
+ nvidia-cudnn-cu12==9.3.0.75 ; python_version >= "3.11"
52
+ nvidia-cufft-cu12==11.2.3.61 ; python_version >= "3.11"
53
+ nvidia-curand-cu12==10.3.6.82 ; python_version >= "3.11"
54
+ nvidia-cusolver-cu12==11.6.3.83 ; python_version >= "3.11"
55
+ nvidia-cusparse-cu12==12.5.1.3 ; python_version >= "3.11"
56
+ nvidia-nccl-cu12==2.23.4 ; python_version >= "3.11"
57
+ nvidia-nvjitlink-cu12==12.5.82 ; python_version >= "3.11"
58
+ opt-einsum==3.4.0 ; python_version >= "3.11"
59
+ optree==0.16.0 ; python_version >= "3.11"
60
+ orjson==3.10.18 ; python_version >= "3.11"
61
+ packaging==25.0 ; python_version >= "3.11"
62
+ pandas==2.3.0 ; python_version >= "3.11"
63
+ pillow==11.2.1 ; python_version >= "3.11"
64
+ protobuf==5.29.5 ; python_version >= "3.11"
65
+ pydantic-core==2.33.2 ; python_version >= "3.11"
66
+ pydantic==2.11.7 ; python_version >= "3.11"
67
+ pydub==0.25.1 ; python_version >= "3.11"
68
+ pygments==2.19.2 ; python_version >= "3.11"
69
+ pyparsing==3.2.3 ; python_version >= "3.11"
70
+ python-dateutil==2.9.0.post0 ; python_version >= "3.11"
71
+ python-multipart==0.0.20 ; python_version >= "3.11"
72
+ pytz==2025.2 ; python_version >= "3.11"
73
+ pyyaml==6.0.2 ; python_version >= "3.11"
74
+ requests==2.32.4 ; python_version >= "3.11"
75
+ rich==14.0.0 ; python_version >= "3.11"
76
+ ruff==0.12.0 ; python_version >= "3.11" and sys_platform != "emscripten"
77
+ safehttpx==0.1.6 ; python_version >= "3.11"
78
+ scikit-learn==1.7.0 ; python_version >= "3.11"
79
+ scipy==1.16.0 ; python_version >= "3.11"
80
+ semantic-version==2.10.0 ; python_version >= "3.11"
81
+ setuptools==80.9.0 ; python_version >= "3.11"
82
+ shellingham==1.5.4 ; python_version >= "3.11" and sys_platform != "emscripten"
83
+ six==1.17.0 ; python_version >= "3.11"
84
+ sniffio==1.3.1 ; python_version >= "3.11"
85
+ starlette==0.46.2 ; python_version >= "3.11"
86
+ tensorboard-data-server==0.7.2 ; python_version >= "3.11"
87
+ tensorboard==2.19.0 ; python_version >= "3.11"
88
+ tensorflow-io-gcs-filesystem==0.37.1 ; python_version == "3.11"
89
+ tensorflow==2.19.0 ; python_version >= "3.11"
90
+ termcolor==3.1.0 ; python_version >= "3.11"
91
+ threadpoolctl==3.6.0 ; python_version >= "3.11"
92
+ tomlkit==0.13.3 ; python_version >= "3.11"
93
+ tqdm==4.67.1 ; python_version >= "3.11"
94
+ typer==0.16.0 ; python_version >= "3.11" and sys_platform != "emscripten"
95
+ typing-extensions==4.14.0 ; python_version >= "3.11"
96
+ typing-inspection==0.4.1 ; python_version >= "3.11"
97
+ tzdata==2025.2 ; python_version >= "3.11"
98
+ urllib3==2.5.0 ; python_version >= "3.11"
99
+ uvicorn==0.34.3 ; python_version >= "3.11" and sys_platform != "emscripten"
100
+ websockets==15.0.1 ; python_version >= "3.11"
101
+ werkzeug==3.1.3 ; python_version >= "3.11"
102
+ wheel==0.45.1 ; python_version >= "3.11"
103
+ wrapt==1.17.2 ; python_version >= "3.11"
utils.py CHANGED
@@ -51,133 +51,107 @@ def show_boxes(image : np.ndarray, damage_sites : dict, box_size = [250,250],
51
  """
52
 
53
  _, ax = plt.subplots(1)
54
- fig = plt.imshow(image,cmap='gray')
55
- # do not show axis ticks (indicating pixels)
56
- plt.xticks([])
57
- plt.yticks([])
58
 
59
  for key, label in damage_sites.items():
60
-
61
- position = list([key[0],key[1]])
62
-
63
- # define colours of the rectangles overlaid on the image per damage type
64
- match label:
65
- case 'Inclusion':
66
- edgecolor = 'b'
67
- case 'Interface' :
68
- edgecolor = 'g'
69
- case 'Martensite' :
70
- edgecolor = 'r'
71
- case 'Notch':
72
- edgecolor = 'y'
73
- case 'Shadowing' :
74
- edgecolor = 'm'
75
- case _:
76
- edgecolor = 'k'
77
-
78
-
79
- rectangle = patches.Rectangle((position[1]-box_size[1]/2., position[0]-box_size[0]/2),
80
- box_size[0],box_size[1],
81
- linewidth=1,edgecolor=edgecolor,facecolor='none')
82
- ax.add_patch(rectangle)
83
-
84
-
85
- legend_elements = [Line2D([0], [0], color='b', lw=4, label='Inclusion'),
86
- Line2D([0], [0], color='g', lw=4, label='Interface'),
87
- Line2D([0], [0], color='r', lw=4, label='Martensite'),
88
- Line2D([0], [0], color='y', lw=4, label='Notch'),
89
- Line2D([0], [0], color='m', lw=4, label='Shadow'),
90
- Line2D([0], [0], color='k', lw=4, label='Not Classified')
91
- ]
92
-
93
- ax.legend(handles=legend_elements,bbox_to_anchor=(1.04, 1), loc="upper left")
94
-
95
- if save_image:
96
- plt.savefig(image_path,dpi=1200,bbox_inches='tight' )
97
-
98
- canvas = plt.gca().figure.canvas
99
  canvas.draw()
100
- data = np.frombuffer(canvas.tostring_rgb(), dtype=np.uint8)
101
- image = data.reshape(canvas.get_width_height()[::-1] + (3,))
102
-
103
- plt.show()
104
 
 
 
 
105
 
 
106
 
107
- return image
108
 
109
 
110
  ###
111
  ### cut out small images from panorama, append colour information
112
  ###
113
- def prepare_classifier_input(panorama : np.ndarray, centroids : list, window_size = [250,250]) -> list :
114
- """Create a list of smaller images from the SEM panoramic image.
115
- The neural networks expect images of a given size that are centered around a single damage site candiates.
116
- For each centroid (from the clustering step before), we cut out a smaller image from the panorama of the size
117
- expected by the classfier network.
118
- Since the networks expect colour images, we repeat the gray-scale image 3 times for a given candiate site.
119
-
120
- Args:
121
- panorama (np.ndarray): SEM input image
122
- centroids (list): list of centroids for the damage site candidates
123
- window_size (list, optional): Size of the image expected by the neural network later. Defaults to [250,250].
124
-
125
- Returns:
126
- list: List of "colour" images cut out from the SEM panorama, one per damage site candidate
127
  """
 
 
 
 
128
 
129
- panorama_shape = panorama.shape
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
- # list of the small images cut out from the panorama,
132
- # each of these is then fed into the classfier model
133
  images = []
134
 
135
- for i in range(len(centroids)):
136
- x1 = int(math.floor(centroids[i][0] - window_size[0]/2))
137
- y1 = int(math.floor(centroids[i][1] - window_size[1]/2))
138
- x2 = int(math.floor(centroids[i][0] + window_size[0]/2))
139
- y2 = int(math.floor(centroids[i][1] + window_size[1]/2))
140
-
141
 
142
- ##
143
- ## Catch the cases in which the extract would go
144
- ## over the boundaries of the original image
145
- ##
146
- if x1<0:
147
- x1 = 0
148
- x2 = window_size[0]
149
- if x2>= panorama_shape[0]:
150
- x1 = panorama_shape[0] - window_size[0]
151
- x2 = panorama_shape[0]
152
- if y1<0:
153
- y1 = 0
154
- y2 = window_size[1]
155
- if y2>= panorama_shape[1]:
156
- y1 = panorama_shape[1] - window_size[1]
157
- y2 = panorama_shape[1]
158
-
159
- # we now need to create the image path from the panoramic image that corresponds to the
160
- # centroid, with the size determined by the window_size.
161
- # First, we create an empty container with np.zeros()
162
- tmp_img = np.zeros((window_size[1], window_size[0],1), dtype=float)
163
-
164
- # Then we copy over the patch of the panomaric image.
165
- # The later classfier expects colour images, i.e. 3 colour channels for RGB
166
- # Since we use gray-scale images, we only have one colour information, so we add the image to the first colour channel
167
- tmp_img[:,:,0] = panorama[x1:x2,y1:y2,0]
168
-
169
- # rescale the colour values
170
- tmp_img = tmp_img*2./255. - 1.
171
-
172
- # The classifier expects colour images, i.e. 3 colour channels.
173
- # We "fake" this by repeating the same gray-scale information 3 times, once per colour channel
174
- tmp_img_colour = np.repeat(tmp_img,3, axis=2) #3
175
-
176
- images.append(tmp_img_colour)
177
-
178
 
179
- return images
 
 
180
 
 
 
 
 
 
181
 
182
 
183
 
 
51
  """
52
 
53
  _, ax = plt.subplots(1)
54
+ ax.imshow(image, cmap='gray') # show image on correct axis
55
+ ax.set_xticks([])
56
+ ax.set_yticks([])
 
57
 
58
  for key, label in damage_sites.items():
59
+ position = [key[0], key[1]]
60
+ edgecolor = {
61
+ 'Inclusion': 'b',
62
+ 'Interface': 'g',
63
+ 'Martensite': 'r',
64
+ 'Notch': 'y',
65
+ 'Shadowing': 'm'
66
+ }.get(label, 'k') # default: black
67
+
68
+ rect = patches.Rectangle((position[1] - box_size[1] / 2., position[0] - box_size[0] / 2),
69
+ box_size[1], box_size[0],
70
+ linewidth=1, edgecolor=edgecolor, facecolor='none')
71
+ ax.add_patch(rect)
72
+
73
+ legend_elements = [
74
+ Line2D([0], [0], color='b', lw=4, label='Inclusion'),
75
+ Line2D([0], [0], color='g', lw=4, label='Interface'),
76
+ Line2D([0], [0], color='r', lw=4, label='Martensite'),
77
+ Line2D([0], [0], color='y', lw=4, label='Notch'),
78
+ Line2D([0], [0], color='m', lw=4, label='Shadow'),
79
+ Line2D([0], [0], color='k', lw=4, label='Not Classified')
80
+ ]
81
+ ax.legend(handles=legend_elements, bbox_to_anchor=(1.04, 1), loc="upper left")
82
+
83
+ fig = ax.figure
84
+ fig.tight_layout(pad=0)
85
+
86
+ if save_image and image_path:
87
+ fig.savefig(image_path, dpi=1200, bbox_inches='tight')
88
+
89
+ canvas = fig.canvas
 
 
 
 
 
 
 
 
90
  canvas.draw()
 
 
 
 
91
 
92
+ data = np.frombuffer(canvas.buffer_rgba(), dtype=np.uint8).reshape(
93
+ canvas.get_width_height()[::-1] + (4,))
94
+ data = data[:, :, :3] # RGB only
95
 
96
+ plt.close(fig)
97
 
98
+ return data
99
 
100
 
101
  ###
102
  ### cut out small images from panorama, append colour information
103
  ###
104
+ def prepare_classifier_input(panorama: np.ndarray, centroids: list, window_size=[250, 250]) -> list:
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  """
106
+ Extracts square image patches centered at each given centroid from a grayscale panoramic SEM image.
107
+
108
+ Each extracted patch is resized to the specified window size and converted into a 3-channel (RGB-like)
109
+ normalized image suitable for use with classification neural networks that expect color input.
110
 
111
+ Parameters
112
+ ----------
113
+ panorama : np.ndarray
114
+ Input SEM image. Should be a 2D array (H, W) or a 3D array (H, W, 1) representing grayscale data.
115
+
116
+ centroids : list of [int, int]
117
+ List of (y, x) coordinates marking the centers of regions of interest. These are typically damage sites
118
+ identified in preprocessing (e.g., clustering).
119
+
120
+ window_size : list of int, optional
121
+ Size [height, width] of each extracted image patch. Defaults to [250, 250].
122
+
123
+ Returns
124
+ -------
125
+ list of np.ndarray
126
+ List of extracted and normalized 3-channel image patches, each with shape (height, width, 3). Only
127
+ centroids that allow full window extraction within image bounds are used.
128
+ """
129
+ if panorama.ndim == 2:
130
+ panorama = np.expand_dims(panorama, axis=-1) # (H, W, 1)
131
 
132
+ H, W, _ = panorama.shape
133
+ win_h, win_w = window_size
134
  images = []
135
 
136
+ for (cy, cx) in centroids:
137
+ x1 = int(cx - win_w / 2)
138
+ y1 = int(cy - win_h / 2)
139
+ x2 = x1 + win_w
140
+ y2 = y1 + win_h
 
141
 
142
+ # Skip if patch would go out of bounds
143
+ if x1 < 0 or y1 < 0 or x2 > W or y2 > H:
144
+ continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
+ # Extract and normalize patch
147
+ patch = panorama[y1:y2, x1:x2, 0].astype(np.float32)
148
+ patch = patch * 2. / 255. - 1.
149
 
150
+ # Replicate grayscale channel to simulate RGB
151
+ patch_color = np.repeat(patch[:, :, np.newaxis], 3, axis=2)
152
+ images.append(patch_color)
153
+
154
+ return images
155
 
156
 
157