Skip to content

Instantly share code, notes, and snippets.

@hirocarma
Created October 19, 2025 09:54
Show Gist options
  • Save hirocarma/d1f605b8c340f7512f9b0860c827aa5f to your computer and use it in GitHub Desktop.
Save hirocarma/d1f605b8c340f7512f9b0860c827aa5f to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import os
import sys
import cv2
import numpy as np
import colorsys
import matplotlib.pyplot as plt
import math
from scipy import stats
import matplotlib.patches as patches
import collections
def Lab_plt(IMG_DIR, p_title):
files = os.listdir(IMG_DIR)
files = sorted(files)
fps = 24
Lt = []
Ll = []
La = []
Lb = []
Lc = []
if len(files) <= (fps * 120):
ext_parm = fps
time_scale = 1
time_unit = "秒(sec)"
else:
ext_parm = (fps / 3)
time_scale = 60
time_unit = "分(min)"
for i, file in enumerate(files):
if not i % (fps / ext_parm) == 0:
continue
img_path = IMG_DIR + "/" + file
img = cv2.imread(img_path)
lab_img = cv2.cvtColor(img, cv2.COLOR_BGR2Lab)
mean_l = int(np.mean(lab_img[:, :, 0]))
mean_a = int(np.mean(lab_img[:, :, 1]))
mean_b = int(np.mean(lab_img[:, :, 2]))
mean_c = math.sqrt(mean_a**2 + mean_b**2)
Lt.append(i / fps / time_scale)
Ll.append(mean_l)
La.append(mean_a)
Lb.append(mean_b)
Lc.append(mean_c)
##num = fps * int((i / fps / 8))
num = int(len(Lt) / 24)
b = np.ones(num) / num
Ll2 = np.convolve(Ll, b, mode="same")
La2 = np.convolve(La, b, mode="same")
Lb2 = np.convolve(Lb, b, mode="same")
Lc2 = np.convolve(Lc, b, mode="same")
l_mean = np.mean(Ll)
a_mean = np.mean(La)
b_mean = np.mean(Lb)
c_mean = np.mean(Lc)
l_med = np.median(Ll)
a_med = np.median(La)
b_med = np.median(Lb)
c_med = np.median(Lc)
l_mode = stats.mode(Ll, axis=None)[0]
a_mode = stats.mode(La, axis=None)[0]
b_mode = stats.mode(Lb, axis=None)[0]
c_mode = stats.mode(Lc, axis=None)[0]
l_std = np.std(Ll)
a_std = np.std(La)
b_std = np.std(Lb)
c_std = np.std(Lc)
l_max = np.max(Ll)
a_max = np.max(La)
b_max = np.max(Lb)
c_max = np.max(Lc)
l_min = np.min(Ll)
a_min = np.min(La)
b_min = np.min(Lb)
c_min = np.min(Lc)
lc_std_count = np.count_nonzero(
(Ll < l_mean + l_std)
& (Ll > l_mean - l_std)
& (Lc < c_mean + c_std)
& (Lc > c_mean - c_std)
)
lc_std_ratio = (lc_std_count / len(Ll)) * 100
os.mkdir(p_title)
p_fname = p_title + "/" + p_title
STAT_TXTF = p_fname + "stat.txt"
f = open(STAT_TXTF, "w")
f.write("duration:" + str(len(files) / fps / time_scale) + time_unit + "\n")
f.write("l_mean:" + str(l_mean) + "\n")
f.write("a_mean:" + str(a_mean) + "\n")
f.write("b_mean:" + str(b_mean) + "\n")
f.write("c_mean:" + str(c_mean) + "\n")
f.write("l_med:" + str(l_med) + "\n")
f.write("a_med:" + str(a_med) + "\n")
f.write("b_med:" + str(b_med) + "\n")
f.write("c_med:" + str(c_med) + "\n")
f.write("l_mode:" + str(l_mode) + "\n")
f.write("a_mode:" + str(a_mode) + "\n")
f.write("b_mode:" + str(b_mode) + "\n")
f.write("c_mode:" + str(c_mode) + "\n")
f.write("l_std:" + str(l_std) + "\n")
f.write("a_std:" + str(a_std) + "\n")
f.write("b_std:" + str(b_std) + "\n")
f.write("c_std:" + str(c_std) + "\n")
f.write("l_max:" + str(l_max) + "\n")
f.write("a_max:" + str(a_max) + "\n")
f.write("b_max:" + str(b_max) + "\n")
f.write("c_max:" + str(c_max) + "\n")
f.write("l_min:" + str(l_min) + "\n")
f.write("a_min:" + str(a_min) + "\n")
f.write("b_min:" + str(b_min) + "\n")
f.write("c_min:" + str(c_min) + "\n")
f.write("lc_std_count:" + str(lc_std_count) + "\n")
f.write("len(Ll):" + str(len(Ll)) + "\n")
f.write("lc_std_ratio:" + str(lc_std_ratio) + "\n")
f.close()
plt.rcParams["font.family"] = "Noto Sans CJK JP"
# --- plot
fig = plt.figure(
figsize=(16, 8), dpi=100, facecolor="lightgray", tight_layout=False
)
ax = fig.add_subplot(111, fc="w", xlabel=time_unit, ylabel="L*")
ax.set_title(p_title + " L*a*b* / L*(明度)推移")
ax.plot(Lt, Ll, label="L*")
ax.plot(Lt, Ll2, "r", label="L*:Moving average")
ax.axhline(y=l_mean, color="r", linestyle="dashed", linewidth=1)
ax.text(-2, l_mean, "average:" + str(round(l_mean, 1)), ha="right", size=10)
ax.axhline(y=l_mode, color="g", linestyle="dashed", linewidth=1)
ax.text(-2, l_mode, "mode:" + str(round(l_mode, 1)), ha="right", size=10)
# print(Ll2.index(max(Ll2)))
ax.set_ylim(-5, 255)
ax.set_yticks(np.arange(0, 255, step=25))
ax.grid()
ax.legend()
fig.savefig(p_fname + "-Lab-l.png", facecolor=fig.get_facecolor())
# plt.show()
fig1 = plt.figure(
figsize=(16, 8), dpi=100, facecolor="lightgray", tight_layout=False
)
ax1 = fig1.add_subplot(111, fc="w", xlabel=time_unit, ylabel="a*")
ax1.set_title(p_title + " L*a*b* / a*推移")
ax1.plot(Lt, La, label="a*")
ax1.plot(Lt, La2, "r", label="a*:Moving average")
ax1.axhline(y=a_mean, color="r", linestyle="dashed", linewidth=1)
ax1.text(-2, a_mean, "average:" + str(round(a_mean, 1)), ha="right", size=10)
ax1.axhline(y=a_mode, color="g", linestyle="dashed", linewidth=1)
ax1.text(-2, a_mode, "mode:" + str(round(a_mode, 1)), ha="right", size=10)
ax1.set_ylim(-5, 255)
ax1.set_yticks(np.arange(0, 255, step=25))
ax1.grid()
ax1.legend()
fig1.savefig(p_fname + "-Lab-a.png", facecolor=fig.get_facecolor())
# plt.show()
fig2 = plt.figure(
figsize=(16, 8), dpi=100, facecolor="lightgray", tight_layout=False
)
ax2 = fig2.add_subplot(111, fc="w", xlabel=time_unit, ylabel="b*")
ax2.set_title(p_title + " L*a*b* / b*推移")
ax2.plot(Lt, Lb, label="b*")
ax2.plot(Lt, Lb2, "r", label="b*:Moving average")
ax2.axhline(y=b_mean, color="r", linestyle="dashed", linewidth=1)
ax2.text(-2, b_mean, "average:" + str(round(b_mean, 1)), ha="right", size=10)
ax2.axhline(y=b_mode, color="g", linestyle="dashed", linewidth=1)
ax2.text(-2, b_mode, "mode:" + str(round(b_mode, 1)), ha="right", size=10)
ax2.set_ylim(-5, 255)
ax2.grid()
ax2.legend()
fig2.savefig(p_fname + "-Lab-b.png", facecolor=fig.get_facecolor())
# plt.show()
fig3 = plt.figure(
figsize=(16, 8), dpi=100, facecolor="lightgray", tight_layout=False
)
ax3 = fig3.add_subplot(111, fc="w", xlabel=time_unit, ylabel="c*")
ax3.set_title(p_title + " L*a*b* / c*(彩度)推移")
ax3.plot(Lt, Lc, label="c*")
ax3.plot(Lt, Lc2, "r", label="c*:Moving average")
ax3.axhline(y=c_mean, color="r", linestyle="dashed", linewidth=1)
ax3.text(-2, c_mean, "average:" + str(round(c_mean, 1)), ha="right", size=10)
ax3.axhline(y=c_mode, color="g", linestyle="dashed", linewidth=1)
ax3.text(-2, c_mode, "mode:" + str(round(c_mode, 1)), ha="right", size=10)
ax3.set_ylim(-5, 255)
ax3.grid()
ax3.legend()
fig3.savefig(p_fname + "-Lab-c.png", facecolor=fig.get_facecolor())
# plt.show()
# --- scatter(tone)
fig4 = plt.figure(
figsize=(16, 8), dpi=100, facecolor="lightgray", tight_layout=True
)
ax4 = fig4.add_subplot(111, fc="w", xlabel="c*(彩度)", ylabel="L*(明度)")
ax4.set_title(p_title + " L*a*b* トーン:明度x彩度")
ax4.scatter(Lc, Ll, s=1)
ax4.axhline(y=l_mean, color="r", linestyle="dashed", linewidth=1)
ax4.text(145, l_mean, "mean:" + str(round(l_mean, 1)), ha="right", size=10)
ax4.axvline(x=c_mean, color="r", linestyle="dashed", linewidth=1)
ax4.text(c_mean, -32, "mean:" + str(round(c_mean, 1)), ha="center", size=10)
ax4.set_xlim([140, 240])
ax4.set_ylim([-10, 255])
ax4.axhline(y=l_mode, color="g", linestyle="dashed", linewidth=1)
ax4.text(145, l_mode, "mode:" + str(round(l_mode, 1)), ha="right", size=10)
ax4.axvline(x=c_mode, color="g", linestyle="dashed", linewidth=1)
ax4.text(c_mode, -38, "mode:" + str(round(c_mode, 1)), ha="center", size=10)
boxdic = {
"facecolor": "lightgreen",
"edgecolor": "lightgreen",
"alpha": 0.5,
"boxstyle": "Round",
"linewidth": 1,
}
rec = patches.Rectangle(
xy=(c_mean - c_std, l_mean - l_std),
width=c_std * 2,
height=l_std * 2,
ec="red",
fill=False,
)
ax4.text(
c_mean + c_std,
l_mean + l_std,
str(round(lc_std_ratio, 1))
+ "%"
+ " (L* std:"
+ str(round(l_std, 1))
+ " c*std:"
+ str(round(c_std, 1))
+ ")",
ha="left",
size=8,
color="red",
bbox=boxdic,
)
ax4.add_patch(rec)
ax4.grid()
ax4.legend()
fig4.savefig(p_fname + "-lab-tone.png", facecolor=fig.get_facecolor())
# plt.show()
# --- bar
fig5 = plt.figure(
figsize=(16, 8), dpi=100, facecolor="lightgray", tight_layout=False
)
ax5 = fig5.add_subplot(111, fc="w", xlabel="L*", ylabel="出現数")
ax5.set_title(p_title + " L*分布")
c = collections.Counter(Ll)
max_occur = c.most_common()[0][1]
ax5.bar(list(c.keys()), list(c.values()))
ax5.text(l_mode, max_occur, "max:" + str(max_occur), ha="right", size=10)
ax5.axvline(x=l_mean, color="r", linestyle="dashed", linewidth=1)
ax5.text(
l_mean,
max_occur / 16 * -1,
"average:" + str(round(l_mean, 1)),
ha="center",
size=10,
)
ax5.axvline(x=l_mode, color="g", linestyle="dashed", linewidth=1)
ax5.text(
l_mode,
max_occur / 16 * -1,
"mode:" + str(round(l_mode, 1)),
ha="center",
size=10,
)
ax5.set_xlim(-5, 255)
ax5.grid()
ax5.legend()
fig5.savefig(p_fname + "-Lab-l-bar.png", facecolor=fig.get_facecolor())
# plt.show()
fig6 = plt.figure(
figsize=(16, 8), dpi=100, facecolor="lightgray", tight_layout=False
)
ax6 = fig6.add_subplot(111, fc="w", xlabel="c*", ylabel="出現数")
ax6.set_title(p_title + " c*分布")
c = collections.Counter(Lc)
max_occur = c.most_common()[0][1]
ax6.bar(list(c.keys()), list(c.values()))
ax6.text(c_mode, max_occur, "max:" + str(max_occur), ha="right", size=10)
ax6.axvline(x=c_mean, color="r", linestyle="dashed", linewidth=1)
ax6.text(
c_mean,
max_occur / 16 * -1,
"average:" + str(round(c_mean, 1)),
ha="center",
size=10,
)
ax6.axvline(x=c_mode, color="g", linestyle="dashed", linewidth=1)
ax6.text(
c_mode,
max_occur / 16 * -1,
"mode:" + str(round(c_mode, 1)),
ha="center",
size=10,
)
ax6.grid()
ax6.legend()
fig6.savefig(p_fname + "-Lab-c-bar.png", facecolor=fig.get_facecolor())
# plt.show()
# --- scatter(tone-3d)
fig7 = plt.figure(
figsize=(16, 8), dpi=100, facecolor="lightgray", tight_layout=True
)
ax7 = fig7.add_subplot(
111,
fc="w",
xlabel="c*(彩度)",
ylabel="L*(明度)",
zlabel=time_unit,
projection="3d",
)
ct = 0
while ct * 5 < 90:
ax7.view_init(elev=10, azim=ct * 5)
ct += 1
ax7.set_title(p_title + " L*a*b* トーン:明度x彩度x時間")
ax7.scatter(Lc, Ll, Lt, s=1, c="blue")
ax7.grid()
# ax7.legend()
fig7.savefig(
p_fname + "-lab-tone-3d" + str(ct).zfill(3) + ".png",
facecolor=fig.get_facecolor(),
)
if __name__ == "__main__":
IMG_DIR = sys.argv[1]
p_title = sys.argv[2]
Lab_plt(IMG_DIR, p_title)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment