File size: 8,143 Bytes
69591a9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import streamlit as st


st.set_page_config(
    page_title="DN-AI",
    page_icon="🔬",
    layout="wide",
)

def build_multichannel_loader():

    if (
        st.session_state.get("files_uploaded", None) is None
        or len(st.session_state.files_uploaded) == 0
    ):
        st.session_state["files_uploaded"] = st.file_uploader(
            label="Upload files",
            accept_multiple_files=True,
            type=["czi", "jpeg", "jpg", "png", "tiff", "tif"],
        )
    else:
        st.session_state["files_uploaded"] += st.file_uploader(
            label="Upload files",
            accept_multiple_files=True,
            type=["czi", "jpeg", "jpg", "png", "tiff", "tif"],
        )
    st.write("### Channel interpretation")
    st.markdown("The goal is to obtain an RGB image in the order of <span style='color: red;'>First analog</span>, <span style='color: green;'>Second analog</span>, <span style='color: blue;'>Empty</span>.", unsafe_allow_html=True)
    st.markdown("By default, we assume that the first channel in CZI/TIFF file is <span style='color: green;'>the second analog</span>, (which happens to be the case in Zeiss microscope) " \
    "which means that we swap the order of the two channels for processing.", unsafe_allow_html=True)
    st.write("If this not the intented behavior, please tick the box below:")
    st.session_state["reverse_channels"] = st.checkbox(
        "Reverse the channels interpretation",
        value=False,
    )
    st.warning("Please note that we only swap the channels for raw (CZI, TIFF) files. JPEG and PNG files "\
               "are assumed to be already in the correct order (First analog in red and second analog in green). " \
    )

    st.info("" \
    "The channels order in CZI files does not necessarily match the order in which they are displayed in ImageJ or equivalent. " \
    "Indeed, such viewers will usually look at the metadata of the file to determine the order of the channels, which we don't. " \
    "In doubt, we recommend visualizing the image in ImageJ and compare with our viewer. If the channels appear reversed, tick the option above.")

def build_individual_loader():
   
    cols = st.columns(2)
    with cols[1]:
        st.markdown(f"<h3 style='color: {st.session_state['color2']};'>Second analog</h3>", unsafe_allow_html=True)

        if (
            st.session_state.get("analog_2_files", None) is None
            or len(st.session_state.analog_2_files) == 0
        ):
            st.session_state["analog_2_files"] = st.file_uploader(
                label="Upload second analog file(s)",
                accept_multiple_files=True,
                type=["czi", "jpeg", "jpg", "png", "tiff", "tif"],
            )
        else:
            st.session_state["analog_2_files"] += st.file_uploader(
                label="Upload second analog file(s)",
                accept_multiple_files=True,
                type=["czi", "jpeg", "jpg", "png", "tiff", "tif"],
            )
        
        
    with cols[0]:
        st.markdown(f"<h3 style='color: {st.session_state['color1']};'>First analog</h3>", unsafe_allow_html=True)
        if (
            st.session_state.get("analog_1_files", None) is None
            or len(st.session_state.analog_1_files) == 0
        ):
            st.session_state["analog_1_files"] = st.file_uploader(
                label="Upload first analog file(s)",
                accept_multiple_files=True,
                type=["czi", "jpeg", "jpg", "png", "tiff", "tif"],
            )
        else:
            st.session_state["analog_1_files"] += st.file_uploader(
                label="Upload first analog file(s)",
                accept_multiple_files=True,
                type=["czi", "jpeg", "jpg", "png", "tiff", "tif"],)
    
    analog_1_files=st.session_state.get("analog_1_files", None)
    analog_2_files=st.session_state.get("analog_2_files", None)
    
    # Remove duplicates from the list of files. We loop through the files and keep only the first occurrence of each file_id.
    def remove_duplicates(files):
        seen_ids = set()
        unique_files = []
        for file in files:
            if file and file.name not in seen_ids:
                unique_files.append(file)
                seen_ids.add(file.name)
        return unique_files

    analog_1_files = remove_duplicates(analog_1_files or [])
    analog_2_files = remove_duplicates(analog_2_files or [])
    
    
    if analog_1_files is None and analog_2_files is None:
        return 
    else:
        if len(analog_1_files)>0 and len(analog_2_files)>0 and len(analog_1_files) != len(analog_2_files):
            st.error("Please upload the same number of analogs files.")
            return
    
    # Always make sure we don't have duplicates in the list of files
    
    analog_1_files = sorted(analog_1_files, key=lambda x: x.name)
    analog_2_files = sorted(analog_2_files, key=lambda x: x.name)
    max_size = max(len(analog_1_files), len(analog_2_files))
    # Pad the shorter list with None
    if len(analog_1_files) < max_size:
        analog_1_files += [None] * (max_size - len(analog_1_files))
    if len(analog_2_files) < max_size:
        analog_2_files += [None] * (max_size - len(analog_2_files))

    combined_files = list(zip(analog_1_files, analog_2_files))

    

    if (
        st.session_state.get("files_uploaded", None) is None
        or len(st.session_state.files_uploaded) == 0
    ):
        st.session_state["files_uploaded"] = combined_files
    else:
        st.session_state["files_uploaded"] += combined_files
    


    # If any of the files (analog_1_files or analog_2_files) was included previously in the files_uploaded, 
    # We remove the previous occurence from the files_uploaded list.
    current_ids = set()
    for f in analog_1_files + analog_2_files:
        if f:
            current_ids.add(f.name)

    # Safely filter the list to exclude any files with matching file_ids
    def is_not_duplicate(file):
        if isinstance(file, tuple):
            f1, f2 = file
            if f1 and f2:
                return True
            
            return (f1 is None or f1.name not in current_ids) and (f2 is None or f2.name not in current_ids)
        else:
            return True
        
    st.session_state.files_uploaded = [f for f in st.session_state.files_uploaded if is_not_duplicate(f)]



cols = st.columns(2)
with cols[1]:
    

    st.write("### Pixel size")
    st.session_state["pixel_size"] = st.number_input(
        "Please indicate the pixel size of the image in µm (default: 0.13 µm).",
        value=st.session_state.get("pixel_size", 0.13),
    )
    # In small, lets precise the tehnical details
    st.write(
        "The pixel size is used to convert the pixel coordinates to µm. " \
        "The model is trained on images with a pixel size of 0.26 µm, and the application automatically " \
        "resizes the images to match this pixel size using your provided choice."
    )

    st.write("### Labels color")
    color_choices = st.columns(2)
    with color_choices[0]:
        st.session_state["color1"] = st.color_picker(
            "Select the color for first analog",
            value=st.session_state.get("color1", "#FF0000"),
            help="This color will be used to display the first analog segments.")
    with color_choices[1]:
        st.session_state["color2"] = st.color_picker(
            "Select the color for second analog",
            value=st.session_state.get("color2", "#00FF00"),
            help="This color will be used to display the second analog segments.")

with cols[0]:
    choice = st.segmented_control(
        "Please select the type of images you want to upload:",
        options=["Multichannel", "Individual channel"],
        default="Multichannel",
    )
    if choice == "Individual channel":
        build_individual_loader()
    else:
        build_multichannel_loader()