diff --git a/README.md b/README.md new file mode 100644 index 0000000..21aa486 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +TCC Degradation +----- +印刷色票の経年劣化(退色)の解析 + +### 使用方法 +- 環境構築 +```bash +pip install -r requirements.txt +``` +- 入力ファイル +cm700reader.py を用いて記録したcsvファイルを入力する.経時的に記録したcsvをまとめてフォルダに置いて,データフォルダを指定して実行する. + +- 出力ファイル +解析結果は3つのcsvファイルと2つのグラフプロット(png)に出力される. diff --git a/analysis.py b/analysis.py new file mode 100644 index 0000000..b1fbfdb --- /dev/null +++ b/analysis.py @@ -0,0 +1,185 @@ +import os + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd + +csv_file = "out_all.csv" +stability_file = "out_stability.csv" +degradation_file = "out_degradation.csv" +paper_names = { + 2: "Glossy Pro Platinum", + 3: "Photo Fine-Grained Luster", + 4: "Matte Photo", + 5: "Photo Premium Matte", +} +data_dir = r"\\gabor\Project\内科\舌診\TIAS\開発\カラーチャート\TCC2025-01\退色調査" + + +def make_all_data_csv() -> None: + """Reads all CSV files.""" # noqa: D401 + + print("Combining all data into a single CSV file...") + files = [f for f in os.listdir(data_dir) if f.endswith(".csv")] + all_data = pd.DataFrame() + for i, file in enumerate(files): + file_path = os.path.join(data_dir, file) + paper = int(file[5:6]) + datestr = "2025/" + file[7:9] + "/" + file[9:11] + iter = 0 if file[11:12] == "a" else 1 + # print(f"Reading {file_path} (Paper: {paper}, Date: {datestr}, Iteration: {iter})") + df = pd.read_csv(file_path, encoding="utf-8") + df["tcc"] = df["no"].astype("int") + df["paper"] = paper + df["date"] = datestr + df["iter"] = iter + # df.drop(columns=["no", "X", "Y", "Z"], inplace=True, errors="ignore") + # df.drop(columns=[f"{c:.1f}" for c in range(400, 710, 10)], inplace=True, errors="ignore") + all_data = pd.concat([all_data, df], ignore_index=True) + # Save the combined DataFrame to a CSV file + all_data[["date", "paper", "iter", "tcc", "L*", "a*", "b*"]].to_csv( + csv_file, index=False, encoding="utf-8" + ) + + +def calc_repeat_stability(): + """Calculate repeat stability of color measurements.""" + if not os.path.exists(csv_file): + make_all_data_csv() + + print("Calculating repeat stability...") + df = pd.read_csv(csv_file, encoding="utf-8", parse_dates=["date"]) + + df0 = df[df["iter"] == 0].drop(columns=["iter"]).copy() + df0.columns = ["date", "paper", "tcc", "L0", "a0", "b0"] + df1 = df[df["iter"] == 1].drop(columns=["iter"]).copy() + df1.columns = ["date", "paper", "tcc", "L1", "a1", "b1"] + dfm = pd.merge(df0, df1, on=["date", "paper", "tcc"]) + dfm["dL"] = dfm["L1"] - dfm["L0"] + dfm["da"] = dfm["a1"] - dfm["a0"] + dfm["db"] = dfm["b1"] - dfm["b0"] + dfm["dE"] = np.sqrt( + dfm["dL"] ** 2 + dfm["da"] ** 2 + dfm["db"] ** 2 + ) # Euclidean distance in Lab color space + dfm["meanL"] = (dfm["L1"] + dfm["L0"]) / 2 + dfm["meana"] = (dfm["a1"] + dfm["a0"]) / 2 + dfm["meanb"] = (dfm["b1"] + dfm["b0"]) / 2 + + dfm.to_csv(stability_file, index=False, encoding="utf-8") + + # print("Top 10 largest deltaE values:") + # print(dfm.sort_values("dE", ascending=False).head(10)) + + # deltaE values Histogram + # plt.figure() + # dfm["dE"].hist(bins=30) + # plt.title("deltaE Histogram") + # plt.xlabel("deltaE") + # plt.ylabel("Frequency") + # plt.show() + + +def color_degradation(): + """Analyze color degradation over time.""" + if not os.path.exists(stability_file): + calc_repeat_stability() + + print("Calculating color degradation...") + dfm = pd.read_csv(stability_file, encoding="utf-8", parse_dates=["date"]) + dfm = dfm[["date", "paper", "tcc", "meanL", "meana", "meanb"]] + + dfm["changeL"] = 0.0 + dfm["changea"] = 0.0 + dfm["changeb"] = 0.0 + dfm["changeDE"] = 0.0 + dfm["days"] = 0 + paper_list = dfm["paper"].drop_duplicates().sort_values() + tcc_list = dfm["tcc"].drop_duplicates().sort_values() + dfout = pd.DataFrame() + for paper in paper_list: + paper_data = dfm[dfm["paper"] == paper] + begin_date = paper_data["date"].min() + + for tcc in tcc_list: + tcc_data = paper_data[paper_data["tcc"] == tcc] + begin_lab = ( + tcc_data[tcc_data["date"] == begin_date][["meanL", "meana", "meanb"]] + .iloc[0] + .to_list() + ) + tcc_data.loc[:, "days"] = (tcc_data["date"] - begin_date).dt.days + tcc_data.loc[:, "changeL"] = tcc_data["meanL"] - begin_lab[0] + tcc_data.loc[:, "changea"] = tcc_data["meana"] - begin_lab[1] + tcc_data.loc[:, "changeb"] = tcc_data["meanb"] - begin_lab[2] + tcc_data.loc[:, "changeDE"] = np.sqrt( + tcc_data["changeL"] ** 2 + tcc_data["changea"] ** 2 + tcc_data["changeb"] ** 2 + ) + dfout = pd.concat([dfout, tcc_data], ignore_index=True) + # print(tcc_data.sort_values("date")) + # print("begin_lab", begin_lab) + # break + # break + + dfout = dfout.sort_values(by=["paper", "tcc", "date"]).reset_index(drop=True) + dfout.to_csv(degradation_file, index=False, encoding="utf-8") + + +def visualize(): + """Visualize color degradation over time.""" + + if not os.path.exists(degradation_file): + color_degradation() + + print("Visualizing color degradation...") + df = pd.read_csv(degradation_file, encoding="utf-8", parse_dates=["date"]) + paper_list = df["paper"].drop_duplicates().sort_values() + + fig = plt.figure() + fig.set_size_inches(18, 12) + fig.suptitle("Color Degradation Over Time (each TCC)", fontsize=16) + fig.subplots_adjust(wspace=0.3, hspace=0.4) + fig.subplots_adjust(top=0.9, bottom=0.05, left=0.05, right=0.95) + for i in range(1, 25): + ax = fig.add_subplot(4, 6, i) + ax.set_title(f"TCC {i}") + ax.set_xlabel("Days") + ax.set_ylabel("Change in deltaE") + for paper in paper_list: + paper_data = df[df["paper"] == paper] + if not paper_data.empty: + ax.plot( + paper_data[paper_data["tcc"] == i]["days"], + paper_data[paper_data["tcc"] == i]["changeDE"], + marker="o", + markersize=4, + label=f"Paper {paper}", + ) + ax.set_ylim(0, 7) # Set y-axis limit for better visibility + ax.legend() + fig.savefig("out_degradation_eachTCC.png", dpi=300, bbox_inches="tight") + + paper_mean = df.groupby(["paper", "date"]).mean().reset_index() + fig2 = plt.figure() + fig2.set_size_inches(9, 6) + fig2.suptitle("Color Degradation Over Time (mean TCC)", fontsize=16) + for paper in paper_list: + paper_data = paper_mean[paper_mean["paper"] == paper] + if not paper_data.empty: + plt.plot( + paper_data["days"], + paper_data["changeDE"], + marker="o", + markersize=6, + label=f"Paper {paper} {paper_names[paper]}", + ) + plt.legend(loc="upper left", borderaxespad=0) + plt.xlabel("Days") + plt.ylabel("Change in deltaE") + fig2.savefig("out_degradation_meanTCC.png", dpi=300, bbox_inches="tight") + + # plt.show() + + +if __name__ == "__main__": + visualize() + print("All done.") diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f14647a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,27 @@ +[tool.ruff] +line-length = 100 + +[tool.ruff.format] +docstring-code-format = true + +[tool.ruff.lint] +#select = ["ALL"] +ignore = [ + "D1", # undocumented + "D203", # one blank line before class + "D213", # multi-line summary second line + "TD001", # invalid todo tag + "TD002", # missing todo author + "TD003", # missing todo link + "PD011", # pandas use of dot values +# "ERA001", +] +unfixable = [ + "F401", # unused import + "F841", # unused variable +] + +logger-objects = ["src.library.logger.LOGGER"] + +[tool.ruff.lint.pylint] +max-args = 6 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..7de02f0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +pandas +matplotlib +numpy