diff --git a/CardiAP.ipynb b/CardiAP.ipynb index 9ceb054..161d572 100644 --- a/CardiAP.ipynb +++ b/CardiAP.ipynb @@ -58,7 +58,8 @@ "\n", "pd.set_option('display.max_rows', 20)\n", "warnings.filterwarnings(\"ignore\", category=np.VisibleDeprecationWarning) \n", - "warnings.filterwarnings(\"ignore\", category=RuntimeWarning) " + "warnings.filterwarnings(\"ignore\", category=RuntimeWarning)\n", + "uploader = {'value': {}}" ] }, { @@ -150,19 +151,19 @@ "source": [ "def window_open_button(url):\n", " display(Javascript(f'window.open(\"{url.tooltip}\");'))\n", - " \n", + "\n", "def load_cv2_image_from_bytes(bytes_):\n", " return cv2.imdecode(np.frombuffer(bytes_, dtype=np.uint8), cv2.IMREAD_COLOR)\n", "\n", - "def get_uploader_contents(uploader):\n", - " return [uploader.value[file][\"content\"] for file in list(uploader.value)]\n", + "def get_uploader_contents():\n", + " return uploader['value'].values()\n", "\n", - "def get_uploader_filenames(uploader): \n", - " return list(uploader.value.keys())\n", + "def get_uploader_filenames():\n", + " return list(uploader['value'].keys())\n", "\n", "def display_html(html):\n", " display(widgets.HTML(value=html))\n", - " \n", + "\n", "def create_download_link( df, title = \"Download CSV file\", filename = \"data.csv\"):\n", " csv = df.to_csv(sep='\\t')\n", " b64 = base64.b64encode(csv.encode())\n", @@ -170,7 +171,7 @@ " html = '{title}'\n", " html = html.format(payload=payload,title=title,filename=filename)\n", " return HTML(html)\n", - " \n", + "\n", "def create_inttext(description, min = None, max = None):\n", " return widgets.BoundedIntText(\n", " value=0,\n", @@ -179,9 +180,9 @@ " description=description,\n", " disabled=False\n", " )\n", - " \n", + "\n", "def plot_analysis_result_slice(df,slice_number):\n", - " \n", + "\n", " fig, ((ax1, ax2)) = plt.subplots(2, figsize=(20,10))\n", "\n", " ax1.plot(df.loc[slice_number, \"amplitudes\"])\n", @@ -192,8 +193,8 @@ " ax2.plot(df.loc[slice_number, \"intensities\"])\n", " ax2.set_title('Intensities')\n", " ax2.grid()\n", - " \n", - " plt.show() \n", + "\n", + " plt.show()\n", "\n", "def read_progress_img():\n", " animatedGif = \"./assets/progress.gif\"\n", @@ -207,9 +208,9 @@ " width=100,\n", " height=100)\n", "\n", - " \n", + "\n", "def render_image_visualization(analysis_results):\n", - " render_analysis_results_visualization(analysis_results, \n", + " render_analysis_results_visualization(analysis_results,\n", " title = \"Peaks\",\n", " kind = \"image\",\n", " download_filename = \"complete_cell\",\n", @@ -217,48 +218,48 @@ "\n", "\n", "def render_slice_visualization(analysis_results, slice_number):\n", - " render_analysis_results_visualization(analysis_results, \n", + " render_analysis_results_visualization(analysis_results,\n", " title = \"Slice\",\n", " kind = \"slices\",\n", " download_filename = f\"slice_{slice_number}\",\n", " progress = with_progress,\n", - " slice_number = slice_number) \n", - " \n", + " slice_number = slice_number)\n", + "\n", "def render_analysis_results_visualization(analysis_results, title, kind, download_filename, progress, slice_number = 0):\n", " \"\"\"\n", - " Renders analysis results into three sections: \n", + " Renders analysis results into three sections:\n", " - Peaks table\n", " - Table download\n", " - Peaks plot\n", " \"\"\"\n", " def filter_slice(table):\n", " return table[table.slice_number == slice_number].drop(columns = \"slice_number\")\n", - " \n", + "\n", " display_html(f\"

{title} table

\")\n", " table, min_table = build_analysis_results_table(analysis_results, kind = kind)\n", - " \n", + "\n", " table = filter_slice(table)\n", " display(table)\n", - " progress(lambda: display(create_download_link(table, title = f\"Download {title} Table\", filename = f\"{download_filename}.csv\"))) \n", - " \n", + " progress(lambda: display(create_download_link(table, title = f\"Download {title} Table\", filename = f\"{download_filename}.csv\")))\n", + "\n", " min_table = filter_slice(min_table)\n", " display(min_table)\n", - " progress(lambda: display(create_download_link(min_table, title = f\"Download {title} Minimumns Table\", filename = f\"{download_filename}.csv\"))) \n", + " progress(lambda: display(create_download_link(min_table, title = f\"Download {title} Minimumns Table\", filename = f\"{download_filename}.csv\")))\n", "\n", " display_html(f\"

{title} plot

\")\n", - " progress(lambda: plot_analysis_result_slice(analysis_results[kind], slice_number)) \n", - " \n", - " \n", + " progress(lambda: plot_analysis_result_slice(analysis_results[kind], slice_number))\n", + "\n", + "\n", "def display_results(analysis_results, shape):\n", " \"\"\"\n", - " Displays the results into three separate tabs. \n", - " Every print or display will be automatically redirected to it. \n", + " Displays the results into three separate tabs.\n", + " Every print or display will be automatically redirected to it.\n", " \"\"\"\n", - " \n", + "\n", " complete_cell_output = widgets.Output()\n", " slices_general_output = widgets.Output()\n", " slices_detail_output = widgets.Output()\n", - " \n", + "\n", " tab = widgets.Tab()\n", " tab.children = [complete_cell_output, slices_general_output, slices_detail_output]\n", " tab.set_title(0, \"Complete Cell\")\n", @@ -270,21 +271,21 @@ " display_html(f\"

Complete Cell area: {shape}

\")\n", " render_image_visualization(analysis_results)\n", "\n", - " with slices_general_output: \n", + " with slices_general_output:\n", " display_html(\"

Slices General Data

\")\n", " table, min_table = build_analysis_results_table(analysis_results, kind = 'slices')\n", " display(\n", " create_download_link(\n", - " table, \n", - " title = \"Download Slices Table\", \n", - " filename = \"slices.csv\")) \n", + " table,\n", + " title = \"Download Slices Table\",\n", + " filename = \"slices.csv\"))\n", " display(\n", " create_download_link(\n", - " min_table, \n", - " title = \"Download Slices Minimums Table\", \n", - " filename = \"slices_minimums.csv\")) \n", + " min_table,\n", + " title = \"Download Slices Minimums Table\",\n", + " filename = \"slices_minimums.csv\"))\n", "\n", - " with slices_detail_output: \n", + " with slices_detail_output:\n", " display_html(\"

Slices Detail

\")\n", " slice_selector = create_inttext(\"Plot slice: \", min = 0, max = len(analysis_results[\"slices\"]) - 1)\n", " plot_btn = widgets.Button(description=\"Show details\", button_style='primary')\n", @@ -295,23 +296,28 @@ " plot_box.clear_output()\n", " render_slice_visualization(analysis_results, slice_selector.value)\n", "\n", - " plot_btn.on_click(on_button_clicked) \n", + " plot_btn.on_click(on_button_clicked)\n", " display(slice_selector)\n", " display(plot_btn)\n", " display(plot_box)\n", "\n", "def without_progress(code):\n", - " code() \n", - " \n", + " code()\n", + "\n", "def with_progress(code):\n", " progress = create_image(read_progress_img())\n", " display(progress)\n", " code()\n", " progress.close()\n", - " \n", - "def clear_uploader(uploader):\n", - " uploader._counter = 0\n", - " uploader.value.clear()\n", + "\n", + "def clear_uploader():\n", + " global last_updated_number, last_file_number\n", + " last_updated_number = 0\n", + " last_file_number = 0\n", + " uploader['value'].clear()\n", + " file_chooser.reset()\n", + " for f in os.listdir(voila_folder):\n", + " os.remove(os.path.join(voila_folder, f))\n", "\n", "def run_discord_analysis(image):\n", " return discord.analyze_image(image, \\\n", @@ -333,26 +339,25 @@ "def run_cardiap_pipeline(content, shape):\n", " \"\"\"\n", " Loads a cell image from uploaded content bytes\n", - " and runs it against the cardiap analyzer. \n", - " \n", - " This function returns the raw cardiap results dictionary and two pandas dataframes: \n", - " \n", - " - image: the whole cell image analysis results \n", - " - slices: the sliced analysis results \n", - " \n", + " and runs it against the cardiap analyzer.\n", + "\n", + " This function returns the raw cardiap results dictionary and two pandas dataframes:\n", + "\n", + " - image: the whole cell image analysis results\n", + " - slices: the sliced analysis results\n", + "\n", " \"\"\"\n", - " \n", + "\n", " image = load_cv2_image_from_bytes(content)\n", " image = image_data._apply_billateral_filter(image,ksize.value,sigma.value,sigma.value)\n", - " \n", " x_start = int(shape[0])\n", " x_end = x_start + int(shape[2])\n", - " y_start = int(shape[1]) \n", + " y_start = int(shape[1])\n", " y_end = y_start + int(shape[3])\n", - " \n", - " image = image_data.crop_horizontal(image, x_start, x_end) \n", - " image = image_data.crop_vertical(image, y_start, y_end) \n", - " \n", + "\n", + " image = image_data.crop_horizontal(image, x_start, x_end)\n", + " image = image_data.crop_vertical(image, y_start, y_end)\n", + "\n", " raw_results = run_discord_analysis(image)\n", " raw_gradient_results = run_gradient_analysis(image)\n", " return [{\n", @@ -378,25 +383,25 @@ "# result = pd.concat([result,min_peaks], ignore_index=False, axis=1)\n", "\n", " result = result.astype({\n", - " \"amplitudes\":\"float\", \n", + " \"amplitudes\":\"float\",\n", " \"max_peaks_positions\":\"float\",\n", " \"max_peaks_intensities\":\"float\",\n", - " \"times_to_peaks\": \"float\", \n", + " \"times_to_peaks\": \"float\",\n", " \"times_to_half_peaks\": \"float\",\n", " \"tau_s\": \"float\",\n", " })\n", - " \n", + "\n", " min_peaks = min_peaks.astype({\n", " \"min_peaks_positions\":\"float\",\n", " \"min_peaks_intensities\":\"float\"\n", - " }) \n", - " \n", + " })\n", + "\n", " return result, min_peaks\n", "\n", "def build_analysis_results_table(analysis_results, kind):\n", " \"\"\"\n", " Build the final output analysis results table.\n", - " This function works both for building slices table - where you will get a row for each slice and position - \n", + " This function works both for building slices table - where you will get a row for each slice and position -\n", " or and for building image table - where you get a single row for each position\n", " Final tables contains the same columns as raw analysis results, except by min_* columns and amplitudes\n", " \"\"\"\n", @@ -409,61 +414,61 @@ " @results_box.capture()\n", " def on_button_clicked(_button):\n", " \"\"\"\n", - " Runs analysis and displays results. \n", + " Runs analysis and displays results.\n", " It stores them in __last_analysis_results__\n", " for debugging purposes\n", " \"\"\"\n", " global __last_analysis_results__\n", " results_box.clear_output()\n", - " \n", - " children = []\n", - " cells_count = uploader._counter\n", "\n", - " for index, (filename, content) in enumerate(zip(get_uploader_filenames(uploader), get_uploader_contents(uploader))):\n", + " children = []\n", + " cells_count = len(uploader['value'].keys())\n", + " print(f\"Analyzing {cells_count} cells. Please wait...\")\n", + " for index, (filename, content) in enumerate(zip(get_uploader_filenames(), get_uploader_contents())):\n", " shape = crop_results[filename]\n", - " print(f\"Analyzing cell {index + 1} of {cells_count}. Please wait...\")\n", + "\n", "\n", " output = widgets.Output()\n", " children.append(output)\n", "\n", " with output:\n", - " try: \n", + " try:\n", " __last_analysis_results__ = run_cardiap_pipeline(content, shape)[0]\n", " __last_gradient_analysis_results__ = run_cardiap_pipeline(content, shape)[1]\n", " display_results(__last_analysis_results__, shape)\n", - " \n", + "\n", " display_html(f\"

Global Discordance Results

\")\n", " dyss_table = get_global_discordance_results(__last_gradient_analysis_results__)\n", " display(dyss_table)\n", " display(\n", " create_download_link(\n", - " dyss_table, \n", - " title = \"Download Discordance Results\", \n", + " dyss_table,\n", + " title = \"Download Discordance Results\",\n", " filename = \"DI_table.csv\"))\n", - " \n", + "\n", " display_html(f\"

Local AR Results

\")\n", " local_ar_table = calculate_local_AR(build_analysis_results_table(__last_gradient_analysis_results__,kind='slices')[0])\n", " display(local_ar_table)\n", " plot_local_AR(__last_gradient_analysis_results__).show()\n", " display(\n", " create_download_link(\n", - " local_ar_table, \n", - " title = \"Download Local AR Results\", \n", + " local_ar_table,\n", + " title = \"Download Local AR Results\",\n", " filename = \"Local_AR_Results_table.csv\"))\n", - " \n", - " except (discord.PeaksError, discord.TausError) as e: \n", + "\n", + " except (discord.PeaksError, discord.TausError) as e:\n", " display_html(f\"\"\"\n", "

\n", " \n", " Insufficient {e.feature()} data @ {shape}. Please try selecting a different image area or settings\n", "

\n", " \"\"\")\n", - " \n", + "\n", " results_box.clear_output()\n", " results_tab = widgets.Tab()\n", " results_tab.children = children\n", " display(results_tab)\n", - " for index, filename in enumerate(get_uploader_filenames(uploader)):\n", + " for index, filename in enumerate(get_uploader_filenames()):\n", " results_tab.set_title(index, f\"Cell {filename}\")\n", "\n", "\n", @@ -471,7 +476,7 @@ "\n", " smoothing_title = widgets.HTML(\"

Filter settings

\")\n", " smoothing_vbox = widgets.VBox([smoothing_title, ksize, sigma], layout=box_layout)\n", - " \n", + "\n", " settings_title = widgets.HTML(\"

Analysis settings

\")\n", " settings_vbox = widgets.VBox([settings_title, slice_width, min_dist_between_maxs, calibration, analyze_btn], layout=box_layout)\n", "\n", @@ -486,18 +491,174 @@ "metadata": {}, "outputs": [], "source": [ - "uploader = widgets.FileUpload(accept='.tif', multiple=True)\n", + "import glob\n", + "import tempfile\n", + "from ipyfilechooser import FileChooser\n", + "import tifffile\n", + "import os\n", + "\n", + "# General variables\n", + "global generation_process_tab, actions_vbox, file_name, file_extension, selected_file\n", + "selection_box = widgets.Output()\n", + "analysis_box = widgets.Output()\n", + "crop_box = widgets.Output()\n", + "\n", + "file_chooser = FileChooser()\n", + "\n", + "voila_folder = glob.glob(f\"{tempfile.gettempdir()}/{'voila'}*\")[0]\n", + "last_updated_number = 0\n", + "last_file_number = 0\n", + "extension_to_generate = \".jpeg\"\n", + "\n", + "# General Layouts\n", + "\n", + "box_layout = Layout(display='flex',\n", + " flex_flow='column',\n", + " align_items='stretch',\n", + " width='50%',\n", + " margin='0px 10px 10px 20px',\n", + " padding=' 2px 5px 0 5px',\n", + " justify_content='space-between')\n", + "\n", + "btn_layout = Layout(display='flex',\n", + " flex_flow='row',\n", + " align_items='stretch',\n", + " width='50%',\n", + " margin='0px 10px 5px 20px',\n", + " padding='2px 4% 0 1%',\n", + " justify_content='flex-start')\n", + "\n", + "box_upload_layout = Layout(display='flex',\n", + " flex_flow='flex-wrap',\n", + " width='50%',\n", + " margin='0px 10px 5px 20px',\n", + " padding='2px 4% 0 1%',\n", + " justify_contentPeaksError='space-between')\n", + "\n", + "# Selection File Section\n", + "\n", + "html_text_upload = \"

Select your file to initialize the analysis

\"\n", + "header_text_upload = widgets.HTML(value=html_text_upload)\n", + "upload_vbox = widgets.VBox([header_text_upload, file_chooser], layout=box_upload_layout)\n", + "\n", + "# Pre-crop Control Section\n", + "\n", + "start_btn = widgets.Button(description=\"Start\", button_style='primary', icon = 'fa-play')\n", + "clear_btn = widgets.Button(description=\"Clear\", button_style='danger', icon = 'fa-trash', button_color = 'salmon')\n", + "\n", + "def display_the_pre_crop_controls_section():\n", + " global actions_vbox\n", + " actions_vbox = widgets.VBox([start_btn, clear_btn], layout=btn_layout)\n", + " display(actions_vbox)\n", + "\n", + "# Image Generation Confirmation Section\n", + "\n", + "generation_process_box_layout = box_layout\n", + "generation_process_box_layout.width = '450px'\n", + "generation_process_btn_layout = Layout(display='flex', flex_flow='row', margin= 'auto')\n", + "generation_process_content_question = widgets.Label(value=\"Are you sure you want to continue with the process?\")\n", + "generation_process_content_recommendation = widgets.Label(value=\"It is recommended to have at least twice the size of the original file.\")\n", + "generation_process_content_top_section = widgets.VBox([generation_process_content_question, generation_process_content_recommendation])\n", + "generation_process_confirm_btn = widgets.Button(description=\"Confirm\", button_style='primary', icon = 'fa-play', button_color= 'forestgreen')\n", + "generation_process_cancel_btn = widgets.Button(description=\"Cancel\", button_style='danger', icon = 'fa-ban', button_color= 'salmon')\n", + "generation_process_content_bottom_section = widgets.VBox([generation_process_confirm_btn, generation_process_cancel_btn], layout=generation_process_btn_layout)\n", + "\n", + "@selection_box.capture()\n", + "def display_the_generation_process_section(_change):\n", + " global generation_process_tab, file_name, file_extension, selected_file\n", + " selected_file = file_chooser.selected\n", + " file_name, file_extension = os.path.splitext(file_chooser.selected_filename)\n", + " generation_process_content = [widgets.VBox([generation_process_content_top_section, generation_process_content_bottom_section])]\n", + " generation_process_tab = widgets.Tab(children=generation_process_content, layout=generation_process_box_layout)\n", + " generation_process_tab.set_title(0, \"Generation Process\")\n", + " if not is_image(file_extension):\n", + " display(generation_process_tab)\n", + " else:\n", + " selecting_and_generating_temp_images(_)\n", + "\n", + "file_chooser.register_callback(callback=display_the_generation_process_section)\n", + "\n", + "def clear_the_generation_process_section(_button):\n", + " generation_process_tab.close()\n", + " actions_vbox.close()\n", + " clear_uploader()\n", + "\n", + "generation_process_cancel_btn.on_click(clear_the_generation_process_section)\n", + "\n", + "def is_image(file_extension):\n", + " image_extension = [\".jpeg\",\".jpg\",\".png\",\".svg\",\".tif\"]\n", + " return file_extension in image_extension\n", + "\n", + "def is_video(file_extension):\n", + " video_extension = [\".mp4\",\".avi\",\".flv\",\".3gpp\",\".mkv\",\".mks\", \".mov\"]\n", + " return file_extension in video_extension\n", + "\n", + "def is_slm(file_extension):\n", + " return file_extension == \".lsm\"\n", + "\n", + "@selection_box.capture()\n", + "def selecting_and_generating_temp_images(_button):\n", + " it_was_valid = True\n", + "\n", + " if is_image(file_extension):\n", + " image_extractor(selected_file, file_name)\n", + " elif is_video(file_extension):\n", + " video_frame_extractor(selected_file, file_name)\n", + " elif is_slm(file_extension):\n", + " lsm_frame_extractor(selected_file, file_name)\n", + " else:\n", + " it_was_valid = False\n", + " clear_the_generation_process_section(_)\n", + " print(f\"Error: The selected file does not have a valid extension {file_extension}\")\n", + "\n", + " if it_was_valid:\n", + " generation_process_tab.close()\n", + " display_the_pre_crop_controls_section()\n", + "\n", + "generation_process_confirm_btn.on_click(selecting_and_generating_temp_images)\n", + "\n", + "def save_temp_file(frame, selected_file_name, temp_folder):\n", + " global last_file_number\n", + " full_file_name = f\"{selected_file_name}_{last_file_number}.jpeg\"\n", + " generated_path = os.path.join(temp_folder, full_file_name)\n", + " rows, columns, = frame.shape\n", + " max_size = max(rows, columns)\n", + " square_matrix = np.zeros((max_size, max_size), dtype=np.uint8)\n", + " square_matrix[:rows, :columns] = frame\n", + " cv2.imwrite(generated_path, square_matrix)\n", + " last_file_number += 1\n", + "\n", + "def image_extractor(image_file, selected_file_name):\n", + " save_temp_file(cv2.cvtColor(cv2.imread(image_file), cv2.COLOR_BGR2GRAY), selected_file_name, voila_folder)\n", + "\n", + "def video_frame_extractor(video_file, selected_file_name):\n", + " capture = cv2.VideoCapture(video_file)\n", + " success, frame = capture.read()\n", + "\n", + " while success:\n", + " grayscale_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n", + " save_temp_file(grayscale_frame, selected_file_name, voila_folder)\n", + " success, frame = capture.read()\n", + "\n", + " capture.release()\n", + "\n", + "def lsm_frame_extractor(lsm_file, selected_file_name):\n", + " lsm_data = tifffile.imread(lsm_file)\n", + "\n", + " for _, frame in enumerate(lsm_data):\n", + " frame_normalized = frame / np.max(frame)\n", + " frame_uint8 = (frame_normalized * 255).astype(np.uint8)\n", + " save_temp_file(frame_uint8, selected_file_name, voila_folder)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", - "def on_uploader_changed(_uploader):\n", - " \"\"\"\n", - " Override uploader._counter to \n", - " always be in sync with actual uploaded values. \n", - " \n", - " This is most probably a widgets bug\n", - " \"\"\"\n", - " uploader._counter = len(uploader.value)\n", - " \n", - "uploader.observe(on_uploader_changed, 'value')\n", "\n", "ksize = widgets.IntText(\n", " value=0,\n", @@ -529,17 +690,7 @@ " disabled=False\n", ")\n", "\n", - "html_text_upload = \"

Upload your image to initialize the analysis

\"\n", - "header_text_upload = widgets.HTML(value=html_text_upload)\n", - "\n", - "box_upload = Layout(display='flex',\n", - " flex_flow='flex-wrap',\n", - " width='50%',\n", - " margin='0px 10px 5px 20px',\n", - " padding='2px 4% 0 1%',\n", - " justify_contentPeaksError='space-between')\n", "\n", - "upload_vbox = widgets.VBox([header_text_upload, uploader], layout=box_upload)\n", "\n", "box_layout = Layout(display='flex',\n", " flex_flow='column',\n", @@ -549,24 +700,6 @@ " padding=' 2px 5px 0 5px',\n", " justify_content='space-between')\n", "\n", - "btn_layout = Layout(display='flex',\n", - " flex_flow='row',\n", - " align_items='stretch',\n", - " width='50%',\n", - " margin='0px 10px 5px 20px',\n", - " padding='2px 4% 0 1%',\n", - " justify_content='flex-start')\n", - "\n", - "\n", - "start_btn = widgets.Button(description=\"Start\", button_style='primary', icon = 'fa-play')\n", - "clear_btn = widgets.Button(description=\"Clear\", button_style='danger', icon = 'fa-trash')\n", - "\n", - "clear_btn.style.button_color = 'salmon'\n", - "actions_vbox = widgets.VBox([clear_btn, start_btn], layout=btn_layout)\n", - "\n", - "crop_box = widgets.Output()\n", - "analysis_box = widgets.Output()\n", - "\n", "@crop_box.capture()\n", "def on_start_button_clicked(_button):\n", " \"\"\"\n", @@ -576,28 +709,68 @@ " \"\"\"\n", " global __last_crop_results__\n", " __last_crop_results__ = {}\n", - " contents = get_uploader_contents(uploader)\n", + " contents = get_uploader_contents()\n", + " names = uploader['value'].keys()\n", " clear_job_boxes()\n", - " \n", + "\n", " @analysis_box.capture()\n", " def callback(image_name, shape):\n", - " __last_crop_results__.update({image_name: shape.size})\n", " if len(contents) == len(__last_crop_results__):\n", " analysis_box.clear_output()\n", " render_results_box(__last_crop_results__)\n", - " \n", - " if uploader._counter == 0:\n", - " print(\"Please upload an image first\")\n", + "\n", + " if last_file_number == 0:\n", + " print(\"Error: To start the analysis phase, select a file first\")\n", + " elif is_video(file_extension) or is_slm(file_extension):\n", + " def upload_images_to_memory(base_file_name, temp_folder, format_file):\n", + " global last_updated_number\n", + " limit = last_updated_number + 10\n", + " generated_names = tuple()\n", + " while (last_file_number != last_updated_number) and (limit != last_updated_number) :\n", + " full_file_name = f\"{base_file_name}_{last_updated_number}\"\n", + " generated_path = os.path.join(temp_folder, full_file_name + format_file)\n", + " with open(generated_path, 'rb') as image_file:\n", + " uploader['value'][full_file_name] = image_file.read()\n", + " generated_names = generated_names + (full_file_name,)\n", + " last_updated_number += 1\n", + "\n", + " return generated_names\n", + "\n", + " def change_selection(change):\n", + " selected_value = change['new']\n", + " image_preview.value = uploader['value'][selected_value]\n", + "\n", + " def more_items_dropdown(_button):\n", + " new_values = upload_images_to_memory(file_name, voila_folder, extension_to_generate)\n", + " dropdown_images.options = dropdown_images.options + new_values\n", + " dropdown_images.value = new_values[0]\n", + " image_preview.value = uploader['value'][dropdown_images.value]\n", + "\n", + " image_preview = widgets.Image()\n", + " dropdown_images = widgets.Dropdown()\n", + " more_items_dropdown(_)\n", + " select_btn = widgets.Button(description=\"Select\", button_style='primary', icon = 'fa-check')\n", + " more_image_btn = widgets.Button(description=\"More Images\", button_style='primary', icon = 'fa-plus', style={'button_color': 'forestgreen'})\n", + " dropdown_vbox = widgets.VBox([dropdown_images, image_preview], layout=box_upload_layout)\n", + " dropdown_buttons = widgets.VBox([select_btn, more_image_btn], layout=btn_layout)\n", + " display(dropdown_vbox)\n", + " display(dropdown_buttons)\n", + "\n", + " more_image_btn.on_click(more_items_dropdown)\n", + " dropdown_images.observe(change_selection, names='value')\n", + "\n", " else:\n", - " images_buffers = [np.array(Image.open(io.BytesIO(buffer))) for buffer in contents] \n", - " display(crop(images_buffers, image_name_list = get_uploader_filenames(uploader), continuous_update = False, optimize = False, callback = callback))\n", - " \n", - "start_btn.on_click(on_start_button_clicked)\n", - " \n", + " full_file_name = f\"{file_name}\"\n", + " generated_path = os.path.join(voila_folder, full_file_name + extension_to_generate)\n", + " with open(generated_path, 'rb') as image_file:\n", + " uploader['value'][full_file_name] = image_file.read()\n", + "\n", "def on_clear_button_clicked(_button):\n", - " clear_uploader(uploader)\n", + " actions_vbox.close()\n", + " clear_uploader()\n", " clear_job_boxes()\n", "\n", + "start_btn.on_click(on_start_button_clicked)\n", "clear_btn.on_click(on_clear_button_clicked)" ] }, @@ -722,8 +895,7 @@ " athors_section_title, \n", " athors_section_description, \n", " citations_section_title, \n", - " citations_section_description, Runing_section], layout=layouts_intro)\n", - "\n" + " citations_section_description, Runing_section], layout=layouts_intro)" ] }, { @@ -822,7 +994,7 @@ "display(nav_bar_vbox)\n", "display(main_section_vbox)\n", "display(upload_vbox)\n", - "display(actions_vbox)\n", + "display(selection_box)\n", "display(crop_box)\n", "display(analysis_box)" ] diff --git a/requirements.txt b/requirements.txt index f4a41bd..998b52e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,5 @@ ipython==7.21.0 seaborn==0.12.2 matplotlib==3.6.3 interactivecrop==0.0.10 +tifffile==2023.7.10 +ipyfilechooser==0.6.0 \ No newline at end of file