diff --git a/.gitignore b/.gitignore index 8367495..b6c9b5b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ venv/ __pycache__/ -spectrum.csv +*.csv +*.xlsx +!cmf.csv +!d65.csv +!色差と平均算出.xlsx diff --git a/cm700reader.py b/cm700reader.py index ccd6697..3edf3e3 100644 --- a/cm700reader.py +++ b/cm700reader.py @@ -1,85 +1,251 @@ +import csv import sys +import time +import winsound import numpy as np import serial import serial.tools.list_ports +from scipy.interpolate import interp1d import config -# デバイス名でCOMポート番号を検索 -def find_port(device_str): - """ - Find the serial port from the device name. +class CM700D: + def initialize(self): + if not self.open_port(): + return False - Parameters - ---------- - device_str : str - Device name string. + self.wl = np.linspace(400, 700, 31) + self.cmf = self.read_spectrum_csv("cmf.csv") + # print(self.cmf) + self.d65 = self.read_spectrum_csv("d65.csv") + # print(self.d65) + self.K = 100.0 / (self.d65[:, 0] @ self.cmf[:, 1]) + self.XYZw = ((self.d65.T @ self.cmf) * self.K)[0] + print("White point of D65 = ", self.XYZw) - Returns - ------- - str - Found serial port name or empty string if not found. - """ - ports = list(serial.tools.list_ports.comports()) - found_list = list(filter(lambda x: device_str in x.description, ports)) - if len(found_list) == 0: - return "" - return found_list[0].device + return True + def read_spectrum_csv(self, filename): + # csv読み込み + with open(filename, newline="") as f: + csvreader = csv.reader(f) + data_org = np.array([[float(val) for val in row] for row in csvreader]) + wl_org = data_org[:, 0] -# コマンド送受信 -def send_command(ser, command): - ser.write((command + "\r\n").encode()) - data = ser.read(1024) - recv_items = [x.strip() for x in data.decode().split(",")] - if recv_items[0] != config.CODE_OK: - print(f"コマンド{command}に失敗しました") - sys.exit() - return recv_items + # return wl_org, data[:, 1:] + data = np.zeros([len(self.wl), data_org.shape[-1] - 1]) + for i in range(data.shape[-1]): + resampler = interp1d(wl_org, data_org[:, 1 + i], kind="linear") + data[:, i] = resampler(self.wl) + return data + + # デバイス名でCOMポート番号を検索 + def find_port(self, device_str): + ports = list(serial.tools.list_ports.comports()) + found_list = list(filter(lambda x: device_str in x.description, ports)) + if len(found_list) == 0: + return "" + return found_list[0].device + + # COMポートを開く + def open_port(self): + port = self.find_port(config.DEVICE_NAME) + if port == "": + print(f"シリアルデバイス {config.DEVICE_NAME} が見つかりません") + return False + self.ser = serial.Serial(port, config.BAUD_RATE, timeout=config.TIMEOUT) + if not self.ser.is_open: + print(f"COMポート{port}を開くことができませんでした") + return False + print(f"CM-700dと接続しました ({port})") + return True + + # コマンド送受信 + def send_command(self, command, validate=True): + self.ser.write((command + "\r\n").encode()) + data = self.ser.read(1024) + recv_items = [x.strip() for x in data.decode().split(",")] + if recv_items[0] != config.CODE_OK and validate: + print(f"コマンド{command}に失敗しました {recv_items[0]}") + return recv_items + + # COMポートを閉じる + def close_port(self): + self.ser.close() + + def get_num_samples(self): + recv = self.send_command("STR") + self.num_samples = int(recv[5]) + print(f"本体保存サンプル数は{self.num_samples}個です") + + def read_all_spectrum(self): + self.get_num_samples() + self.read_spectrum(1, self.num_samples) + + def read_partial_spectrum(self): + self.get_num_samples() + start_no = int(input("開始サンプル番号>")) + end_no = int(input("終了サンプル番号>")) + if end_no > self.num_samples: + end_no = self.num_samples + self.read_spectrum(start_no, end_no) + + def read_spectrum(self, start_no, end_no): + # 基本データ受信 + recv = self.send_command("IDR") + wavelen = range(int(recv[5]), int(recv[6]) + 1, int(recv[7])) + + spectrum = [] + num_read = end_no - start_no + 1 + for i in range(num_read): + idx = i + start_no + print("\r", "%3d/%3d" % (i + 1, num_read), f" Reading {idx}", end="") + recv = self.send_command( + f"SDR,{idx},{config.MEAS_TYPE_DICT[config.MEAS_TYPE]}" + ) + data = np.asarray(recv[1:], dtype=np.float32) / 10000.0 + spectrum.append([idx] + data.tolist()) + print(" done") + + # CSVファイルに保存 + if len(spectrum) > 0: + filename = input("csv保存ファイル名(未記入で保存しない) >") + if len(filename) > 0: + header_line = "no," + (",".join(map(str, wavelen))) + np.savetxt( + filename, + spectrum, + delimiter=",", + header=header_line, + comments="", + fmt="%.4f", + ) + print(f"CSVファイル {filename} に保存しました") + + def save_csv(self): + # CSVファイルに保存 + if len(self.data) > 0: + filename = input("csv保存ファイル名(未記入で保存しない) >") + if len(filename) > 0: + header_line = "no,X,Y,Z,L*,a*,b*," + (",".join(map(str, self.wl))) + np.savetxt( + filename, + self.data, + delimiter=",", + header=header_line, + comments="", + fmt="%.4f", + ) + print(f"CSVファイル {filename} に保存しました") + + # 手動計測 + def manual_measurement(self): + # 測定条件 + recv = self.send_command("CPR") + print("測定条件:", recv) + + self.data = [] + count = 1 + while True: + winsound.Beep(1000, 100) + ret = input(f"No. {count}: ENTERで計測('q'で終了)") + if ret == "q": + break + self.measurement(count) + count += 1 + + self.save_csv() + + # インターバル計測 + def interval_measurement(self): + # 測定条件 + recv = self.send_command("CPR") + print("測定条件:", recv) + + num_samples = int(input("測定回数>")) + interval = float(input("間隔(秒)>")) + + for i in range(num_samples): + print("\r", "%3d/%3d" % (i + 1, num_samples), end="") + self.measurement(i + 1) + time.sleep(interval) + + self.save_csv() + + # 測定 + def measurement(self, count): + print("測定中...", end="") + recv = self.send_command("MES,1") + repeat = 0 + while True: + time.sleep(0.5) + recv = self.send_command("MDR,2", validate=False) + if recv[0] == config.CODE_OK: + break + if repeat > 10: + print("timeout") + return + repeat += 1 + print("done") + + spectrum = np.asarray(recv[1:], dtype=np.float32) / 10000.0 + XYZ = (((self.d65.T * spectrum) @ self.cmf) * self.K)[0] + # print("XYZ: ", XYZ) + lab = self.xyz_to_lab(XYZ) + print("Lab: ", lab) + # print("X %s, Y %s, Z %s" % (XYZcc24[0], XYZcc24[1], XYZcc24[2])) + + # color = [self.send_command(f"COR,2,1,4,{i}")[1] for i in range(1, 9)] + # print("X %s, Y %s, Z %s" % (color[0], color[1], color[2])) + # print("L* %s, a* %s, b* %s" % (color[5], color[6], color[7])) + + self.data.append([count] + XYZ.tolist() + lab + spectrum.tolist()) + + def xyz_to_lab(self, xyz): + x, y, z = xyz + xw, yw, zw = self.XYZw + fx = self.f(x / xw) + fy = self.f(y / yw) + fz = self.f(z / zw) + return [ + float((116.0 * fy - 16.0)), + float(500.0 * (fx - fy)), + float(200.0 * (fy - fz)), + ] + + def f(self, t): + if t > (6.0 / 29.0) ** 3.0: + return t ** (1.0 / 3.0) + else: + return (841.0 / 108.0) * t + (4.0 / 29.0) # メイン if __name__ == "__main__": - # COMポートを開く - port = find_port(config.DEVICE_NAME) - if port == "": - print(f"COM port of {config.DEVICE_NAME} not found") + cm700d = CM700D() + + if not cm700d.initialize(): sys.exit() - ser = serial.Serial(port, config.BAUD_RATE, timeout=config.TIMEOUT) - if not ser.is_open: - print(f"COMポート{port}を開くことができませんでした") - sys.exit() - print(f"COMポート{port}が開きました") - # 基本データ受信 - recv = send_command(ser, "IDR") - wavelen = range(int(recv[5]), int(recv[6]) + 1, int(recv[7])) + while True: + print("\r\n----- CM700Reader 操作メニュー -----") + print("1. 全ての本体データを取得") + print("2. 一部の本体データを取得") + print("3. 手動計測") + print("4. インターバル計測") + print("0. 終了") + n = input("選択>") + if n == "1": + cm700d.read_all_spectrum() + elif n == "2": + cm700d.read_partial_spectrum() + elif n == "3": + cm700d.manual_measurement() + elif n == "4": + cm700d.interval_measurement() + else: + break - recv = send_command(ser, "STR") - num_samples = int(recv[5]) - print(f"本体にあるサンプル数は{num_samples}個です") - - # 測定データ受信 - spectrum = [] - for i in range(num_samples): - recv = send_command(ser, f"SDR,{i+1},{config.MEAS_TYPE_DICT[config.MEAS_TYPE]}") - spectrum.append(recv[1:]) - print(".", end="") - print("done") - - # COMポートを閉じる - ser.close() - - # CSVファイルに保存 - spetrum_array = np.asarray(spectrum, dtype=np.float32) / 10000.0 - header_line = ",".join(map(str, wavelen)) - np.savetxt( - config.SAVE_FILE, - spetrum_array, - delimiter=",", - header=header_line, - comments="", - fmt="%.4f", - ) + cm700d.close_port() diff --git a/cmf.csv b/cmf.csv new file mode 100644 index 0000000..06a11be --- /dev/null +++ b/cmf.csv @@ -0,0 +1,95 @@ +360,0.0001299,0.000003917,0.0006061 +365,0.0002321,0.000006965,0.001086 +370,0.0004149,0.00001239,0.001946 +375,0.0007416,0.00002202,0.003486 +380,0.001368,0.000039,0.006450001 +385,0.002236,0.000064,0.01054999 +390,0.004243,0.00012,0.02005001 +395,0.00765,0.000217,0.03621 +400,0.01431,0.000396,0.06785001 +405,0.02319,0.00064,0.1102 +410,0.04351,0.00121,0.2074 +415,0.07763,0.00218,0.3713 +420,0.13438,0.004,0.6456 +425,0.21477,0.0073,1.0390501 +430,0.2839,0.0116,1.3856 +435,0.3285,0.01684,1.62296 +440,0.34828,0.023,1.74706 +445,0.34806,0.0298,1.7826 +450,0.3362,0.038,1.77211 +455,0.3187,0.048,1.7441 +460,0.2908,0.06,1.6692 +465,0.2511,0.0739,1.5281 +470,0.19536,0.09098,1.28764 +475,0.1421,0.1126,1.0419 +480,0.09564,0.13902,0.8129501 +485,0.05795001,0.1693,0.6162 +490,0.03201,0.20802,0.46518 +495,0.0147,0.2586,0.3533 +500,0.0049,0.323,0.272 +505,0.0024,0.4073,0.2123 +510,0.0093,0.503,0.1582 +515,0.0291,0.6082,0.1117 +520,0.06327,0.71,0.07824999 +525,0.1096,0.7932,0.05725001 +530,0.1655,0.862,0.04216 +535,0.2257499,0.9148501,0.02984 +540,0.2904,0.954,0.0203 +545,0.3597,0.9803,0.0134 +550,0.4334499,0.9949501,0.008749999 +555,0.5120501,1,0.005749999 +560,0.5945,0.995,0.0039 +565,0.6784,0.9786,0.002749999 +570,0.7621,0.952,0.0021 +575,0.8425,0.9154,0.0018 +580,0.9163,0.87,0.001650001 +585,0.9786,0.8163,0.0014 +590,1.0263,0.757,0.0011 +595,1.0567,0.6949,0.001 +600,1.0622,0.631,0.0008 +605,1.0456,0.5668,0.0006 +610,1.0026,0.503,0.00034 +615,0.9384,0.4412,0.00024 +620,0.8544499,0.381,0.00019 +625,0.7514,0.321,0.0001 +630,0.6424,0.265,5E-05 +635,0.5419,0.217,0.00003 +640,0.4479,0.175,0.00002 +645,0.3608,0.1382,0.00001 +650,0.2835,0.107,0 +655,0.2187,0.0816,0 +660,0.1649,0.061,0 +665,0.1212,0.04458,0 +670,0.0874,0.032,0 +675,0.0636,0.0232,0 +680,0.04677,0.017,0 +685,0.0329,0.01192,0 +690,0.0227,0.00821,0 +695,0.01584,0.005723,0 +700,0.01135916,0.004102,0 +705,0.008110916,0.002929,0 +710,0.005790346,0.002091,0 +715,0.004106457,0.001484,0 +720,0.002899327,0.001047,0 +725,0.00204919,0.00074,0 +730,0.001439971,0.00052,0 +735,0.000999949,0.0003611,0 +740,0.000690079,0.0002492,0 +745,0.000476021,0.0001719,0 +750,0.000332301,0.00012,0 +755,0.000234826,0.0000848,0 +760,0.000166151,0.00006,0 +765,0.000117413,0.0000424,0 +770,8.30753E-05,0.00003,0 +775,5.87065E-05,0.0000212,0 +780,4.15099E-05,0.00001499,0 +785,2.93533E-05,0.0000106,0 +790,2.06738E-05,7.4657E-06,0 +795,1.45598E-05,5.2578E-06,0 +800,1.0254E-05,3.7029E-06,0 +805,7.22146E-06,2.6078E-06,0 +810,5.08587E-06,1.8366E-06,0 +815,3.58165E-06,1.2934E-06,0 +820,2.52253E-06,9.1093E-07,0 +825,1.77651E-06,6.4153E-07,0 +830,1.25114E-06,4.5181E-07,0 diff --git a/d65.csv b/d65.csv new file mode 100644 index 0000000..61b6317 --- /dev/null +++ b/d65.csv @@ -0,0 +1,107 @@ +300,0.0341 +305,1.6643 +310,3.2945 +315,11.7652 +320,20.236 +325,28.6447 +330,37.0535 +335,38.5011 +340,39.9488 +345,42.4302 +350,44.9117 +355,45.775 +360,46.6383 +365,49.3637 +370,52.0891 +375,51.0323 +380,49.9755 +385,52.3118 +390,54.6482 +395,68.7015 +400,82.7549 +405,87.1204 +410,91.486 +415,92.4589 +420,93.4318 +425,90.057 +430,86.6823 +435,95.7736 +440,104.865 +445,110.936 +450,117.008 +455,117.41 +460,117.812 +465,116.336 +470,114.861 +475,115.392 +480,115.923 +485,112.367 +490,108.811 +495,109.082 +500,109.354 +505,108.578 +510,107.802 +515,106.296 +520,104.79 +525,106.239 +530,107.689 +535,106.047 +540,104.405 +545,104.225 +550,104.046 +555,102.023 +560,100 +565,98.1671 +570,96.3342 +575,96.0611 +580,95.788 +585,92.2368 +590,88.6856 +595,89.3459 +600,90.0062 +605,89.8026 +610,89.5991 +615,88.6489 +620,87.6987 +625,85.4936 +630,83.2886 +635,83.4939 +640,83.6992 +645,81.863 +650,80.0268 +655,80.1207 +660,80.2146 +665,81.2462 +670,82.2778 +675,80.281 +680,78.2842 +685,74.0027 +690,69.7213 +695,70.6652 +700,71.6091 +705,72.979 +710,74.349 +715,67.9765 +720,61.604 +725,65.7448 +730,69.8856 +735,72.4863 +740,75.087 +745,69.3398 +750,63.5927 +755,55.0054 +760,46.4182 +765,56.6118 +770,66.8054 +775,65.0941 +780,63.3828 +785,63.8434 +790,64.304 +795,61.8779 +800,59.4519 +805,55.7054 +810,51.959 +815,54.6998 +820,57.4406 +825,58.8765 +830,60.3125 diff --git a/requirements.txt b/requirements.txt index f6c1a1f..8f132a8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ pyserial +numpy diff --git "a/\350\211\262\345\267\256\343\201\250\345\271\263\345\235\207\347\256\227\345\207\272.xlsx" "b/\350\211\262\345\267\256\343\201\250\345\271\263\345\235\207\347\256\227\345\207\272.xlsx" new file mode 100644 index 0000000..d2bd074 --- /dev/null +++ "b/\350\211\262\345\267\256\343\201\250\345\271\263\345\235\207\347\256\227\345\207\272.xlsx" Binary files differ