import os
import pandas as pd
import re
import cv2
import numpy as np
import matplotlib.pyplot as plt
[docs]
def graph_distance():
"""
Generates a plot of the distance of individuals over time.
Reads data from an Excel file, processes it, and saves the plot as a PNG image.
"""
file_path = "output/data/distance.xlsx"
data = pd.read_excel(file_path)
data = data.fillna(0)
individus = data.iloc[:, 0]
intensites = data.iloc[:, 1:]
threshold = 0
for i, individu in enumerate(individus):
y = intensites.iloc[i]
x = intensites.columns
y_masked = np.where(y == threshold, np.nan, y)
plt.plot(x, y_masked, label=individu)
step = 5
plt.xticks(intensites.columns[::step], rotation=45)
plt.xlabel("Temps")
plt.ylabel("distance")
plt.title("Courbes de distance des individus au cours du temps")
plt.savefig("output/plot/courbes_distance_individus.png", format="png")
plt.close()
[docs]
def distance_to_right_edge(image_path):
"""
Calculate the distance from the center of the largest contour in an image to the right edge of the image.
Parameters:
image_path (str): Path to the input image.
Returns:
int: Distance from the center of the largest contour to the right edge of the image.
Raises:
ValueError: If the image cannot be loaded or if no contours are found.
"""
image = cv2.imread(image_path)
if image is None:
raise ValueError("L'image n'a pas pu être chargée.")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not contours:
return 0
contour = contours[0]
M = cv2.moments(contour)
if M["m00"] == 0:
raise ValueError(
"Le moment du contour est zéro, le centre ne peut pas être calculé."
)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
image_width = image.shape[1]
distance = image_width - cX
return distance
[docs]
def distance(n):
"""
This function calculates the distance of each segmented macrophage to the right edge of the image.
It processes images in the specified folder, extracts the distance for each segmented macrophage,
and saves the results in an Excel file.
Parameters:
n (int): The number of segmented macrophages to process.
Returns:
str: The path to the output Excel file containing the distance data.
"""
base_folder = "output/list_track"
output_file = "output/data/distance.xlsx"
if not output_file.endswith(".xlsx"):
raise ValueError("Output file must have an .xlsx extension")
folders = [
d
for d in os.listdir(base_folder)
if os.path.isdir(os.path.join(base_folder, d)) and d.startswith("macrophage_")
]
folders.sort(key=lambda x: int(re.findall(r"\d+", x)[0]))
results = []
for folder in folders:
folder_path = os.path.join(base_folder, folder)
folder_result = {"Time": folder}
print(folder_path)
for a in range(0, n):
found = False
for file in os.listdir(folder_path):
if re.match(rf"{a}_\d+\.png", file):
found = True
input = os.path.join(folder_path, file)
x = distance_to_right_edge(input)
folder_result[f"{a}"] = x
break
if not found:
folder_result[f"{a}"] = "NA"
results.append(folder_result)
df = pd.DataFrame(results)
# Replace the 0 values (if merge) by the mean of the 5 previous and the 5 next values of the row they belong to
for i in range(len(df)):
for j in range(1, len(df.columns)):
if df.iloc[i, j] == 0:
# idx of the row
# list of the 5 previous in the same row (i)
prev = df.iloc[i, j - 5 : j].tolist()
# list of the 5 next in the same row (i)
next_ = df.iloc[i, j + 1 : j + 6].tolist()
mean_value = int((sum(prev) + sum(next_)) / (len(prev) + len(next_)))
df.iloc[i, j] = mean_value
df.to_excel(output_file, index=False, engine="openpyxl")
print(f"Report saved to {output_file}")
graph_distance()
return output_file