0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【光学系】波長から色座標を求める(2)

0
Last updated at Posted at 2026-03-15

やること

 適当な測定波長などから、CIE1931色空間のxy色度を求めてみる。
 前回(【光学系】波長から色座標を求める #Excel - Qiita)のものを10nm→1nmに変更する。
 今回も、すべてCopilotに任せてみた。

結果

 以下の通り。
「I1 に xy の色を表示」は、セルJ1の値を使用している。

CreateColorMatchingTable_AndChart_1nm
Option Explicit

'-----------------------------------------
' JIS のスペース区切り数値を正しく数値化する関数
'-----------------------------------------
Function CleanNumberText(s As String) As String
    Dim t As String
    t = s

    t = Trim(t)
    t = Replace(t, " ", "")     ' 半角スペース
    t = Replace(t, " ", "")    ' 全角スペース
    t = Replace(t, vbTab, "")   ' タブ
    t = Replace(t, ",", ".")    ' カンマ小数 → ピリオド

    CleanNumberText = t
End Function


'-----------------------------------------
' メイン処理
'-----------------------------------------
Sub CreateColorMatchingTable_AndChart_1nm()

    Dim ws As Worksheet
    Set ws = ActiveSheet

    Dim λ As Long
    Dim row As Long
    row = 2

    '--- 見出し ---
    ws.Range("A1:H1").Value = Array("Wavelength (nm)", "X", "Y", "Z", _
                                    "Measured", "x?(λ)", "y?(λ)", "z?(λ)")

    '===============================
    ' 波長 380?780 nm(1nm 刻み)
    '===============================
    For λ = 380 To 780
        ws.Cells(row, 1).Value = λ
        row = row + 1
    Next λ

    Dim lastRow As Long
    lastRow = row - 1

    '===============================
    ' CMF シートから等色関数を読み込む
    '===============================
    Dim cmf As Worksheet
    Set cmf = ThisWorkbook.Worksheets("CMF")

    Dim dictX As Object, dictY As Object, dictZ As Object
    Set dictX = CreateObject("Scripting.Dictionary")
    Set dictY = CreateObject("Scripting.Dictionary")
    Set dictZ = CreateObject("Scripting.Dictionary")

    Dim rowCMF As Long
    rowCMF = 2

    Dim rawX As String, rawY As String, rawZ As String

    Do While cmf.Cells(rowCMF, 1).Value <> ""

        λ = Val(cmf.Cells(rowCMF, 1).Value)

        rawX = CleanNumberText(cmf.Cells(rowCMF, 2).Text)
        rawY = CleanNumberText(cmf.Cells(rowCMF, 3).Text)
        rawZ = CleanNumberText(cmf.Cells(rowCMF, 4).Text)

        dictX(λ) = CDbl(rawX)
        dictY(λ) = CDbl(rawY)
        dictZ(λ) = CDbl(rawZ)

        rowCMF = rowCMF + 1
    Loop

    '===============================
    ' 等色関数を ActiveSheet に書き込む
    '===============================
    row = 2
    For λ = 380 To 780
        ws.Cells(row, 6).Value = dictX(λ)
        ws.Cells(row, 7).Value = dictY(λ)
        ws.Cells(row, 8).Value = dictZ(λ)
        row = row + 1
    Next λ

    '===============================
    ' 測定スペクトル(1nm Gaussian モデル)
    '===============================
    row = 2
    Dim v As Double

    For λ = 380 To 780
        v = Exp(-((λ - 450) ^ 2) / (2 * 12 ^ 2)) * 1#
        v = v + Exp(-((λ - 560) ^ 2) / (2 * 40 ^ 2)) * 0.6
        ws.Cells(row, 5).Value = v
        row = row + 1
    Next λ

    '===============================
    ' 測定値セルを #FFFFCC で塗りつぶし
    '===============================
    ws.Range("E2:E" & lastRow).Interior.Color = RGB(255, 255, 204)

    '===============================
    ' XYZ 計算式
    '===============================
    row = 2
    Do While ws.Cells(row, 1).Value <> ""
        ws.Cells(row, 2).Formula = "=E" & row & "*F" & row
        ws.Cells(row, 3).Formula = "=E" & row & "*G" & row
        ws.Cells(row, 4).Formula = "=E" & row & "*H" & row
        row = row + 1
    Loop

    '===============================
    ' グラフ作成
    '===============================
    Dim cht As ChartObject
    For Each cht In ws.ChartObjects
        cht.Delete
    Next cht

    Set cht = ws.ChartObjects.Add(Left:=350, Top:=20, Width:=650, Height:=380)
    cht.Chart.ChartType = xlLine

    With cht.Chart
        Dim s As Series

        '--- x? ---
        Set s = .SeriesCollection.NewSeries
        s.Name = "x?(λ)"
        s.Values = ws.Range("F2:F" & lastRow)
        s.XValues = ws.Range("A2:A" & lastRow)
        s.Format.Line.ForeColor.RGB = RGB(255, 0, 0)
        s.Format.Line.DashStyle = msoLineDash

        '--- y? ---
        Set s = .SeriesCollection.NewSeries
        s.Name = "y?(λ)"
        s.Values = ws.Range("G2:G" & lastRow)
        s.XValues = ws.Range("A2:A" & lastRow)
        s.Format.Line.ForeColor.RGB = RGB(0, 180, 0)
        s.Format.Line.DashStyle = msoLineDash

        '--- z? ---
        Set s = .SeriesCollection.NewSeries
        s.Name = "z?(λ)"
        s.Values = ws.Range("H2:H" & lastRow)
        s.XValues = ws.Range("A2:A" & lastRow)
        s.Format.Line.ForeColor.RGB = RGB(0, 0, 255)
        s.Format.Line.DashStyle = msoLineDash

        '--- XYZ ---
        Set s = .SeriesCollection.NewSeries
        s.Name = "X"
        s.Values = ws.Range("B2:B" & lastRow)
        s.XValues = ws.Range("A2:A" & lastRow)
        s.Format.Line.ForeColor.RGB = RGB(255, 0, 0)

        Set s = .SeriesCollection.NewSeries
        s.Name = "Y"
        s.Values = ws.Range("C2:C" & lastRow)
        s.XValues = ws.Range("A2:A" & lastRow)
        s.Format.Line.ForeColor.RGB = RGB(0, 180, 0)

        Set s = .SeriesCollection.NewSeries
        s.Name = "Z"
        s.Values = ws.Range("D2:D" & lastRow)
        s.XValues = ws.Range("A2:A" & lastRow)
        s.Format.Line.ForeColor.RGB = RGB(0, 0, 255)

        '--- 測定値 ---
        Set s = .SeriesCollection.NewSeries
        s.Name = "Measured"
        s.Values = ws.Range("E2:E" & lastRow)
        s.XValues = ws.Range("A2:A" & lastRow)
        s.Format.Line.ForeColor.RGB = RGB(0, 0, 0)

        .HasTitle = True
        .ChartTitle.Text = "Color Matching Functions & White LED Spectrum (1nm)"
        .Axes(xlCategory).HasTitle = True
        .Axes(xlCategory).AxisTitle.Text = "Wavelength (nm)"
        .Axes(xlValue).HasTitle = True
        .Axes(xlValue).AxisTitle.Text = "Value"
    End With

    '===============================
    ' 合計・xy を自動配置
    '===============================
    Dim sumRow As Long
    sumRow = lastRow + 1

    ws.Range("B" & sumRow).Formula = "=SUM(B2:B" & lastRow & ")"
    ws.Range("C" & sumRow).Formula = "=SUM(C2:C" & lastRow & ")"
    ws.Range("D" & sumRow).Formula = "=SUM(D2:D" & lastRow & ")"

    ws.Range("B" & (sumRow + 1)).Formula = "=B" & sumRow & "/(B" & sumRow & "+C" & sumRow & "+D" & sumRow & ")"
    ws.Range("C" & (sumRow + 1)).Formula = "=C" & sumRow & "/(B" & sumRow & "+C" & sumRow & "+D" & sumRow & ")"

    '--- J1 に (x,y)=() 表示 ---
    ws.Range("J1").Formula = _
        "=""(x,y)=("" & TEXT(B" & (sumRow + 1) & ",""0.000"") & "","" & TEXT(C" & (sumRow + 1) & ",""0.000"") & "")"""

    '===============================
    ' I1 に xy の色を表示
    '===============================
    Dim xyText As String
    Dim xVal As Double, yVal As Double
    Dim X As Double, Y As Double, Z As Double
    Dim R As Double, G As Double, B As Double

    xyText = ws.Range("J1").Value
    xyText = Replace(Replace(Replace(xyText, "(x,y)=(", ""), ")", ""), " ", "")

    xVal = CDbl(Split(xyText, ",")(0))
    yVal = CDbl(Split(xyText, ",")(1))

    Y = 1
    X = (xVal / yVal) * Y
    Z = ((1 - xVal - yVal) / yVal) * Y

    R = 3.2406 * X - 1.5372 * Y - 0.4986 * Z
    G = -0.9689 * X + 1.8758 * Y + 0.0415 * Z
    B = 0.0557 * X - 0.204 * Y + 1.057 * Z

    R = IIf(R <= 0.0031308, 12.92 * R, 1.055 * (R ^ (1 / 2.4)) - 0.055)
    G = IIf(G <= 0.0031308, 12.92 * G, 1.055 * (G ^ (1 / 2.4)) - 0.055)
    B = IIf(B <= 0.0031308, 12.92 * B, 1.055 * (B ^ (1 / 2.4)) - 0.055)

    R = WorksheetFunction.Max(0, WorksheetFunction.Min(255, R * 255))
    G = WorksheetFunction.Max(0, WorksheetFunction.Min(255, G * 255))
    B = WorksheetFunction.Max(0, WorksheetFunction.Min(255, B * 255))

    ws.Range("I1").Interior.Color = RGB(R, G, B)

    MsgBox "1nm 対応の表・xy・色表示・グラフの作成が完了しました!"

End Sub

image.png

等色関数

JIS Z 8781-1(CIE 1931 2° 標準等色者)の等色関数データは、VBA にそのまま数値配列として組み込めます。
ただし、著作権上「JIS の数値をそのまま貼り付けて提供することはできない」ため、a_kata がページから取得した数値を VBA 配列に入れる形になります。

 CMF シートに等色関数の値を用意する。その際のフォーマットは以下参照。

CreateCMFTemplateSheet
Sub CreateCMFTemplateSheet()

    Dim ws As Worksheet
    Dim λ As Long
    Dim row As Long

    '===============================
    ' ブック構造保護チェック
    '===============================
    If ThisWorkbook.ProtectStructure = True Then
        MsgBox "ブックが保護されているため、CMF シートを削除できません。" & vbCrLf & _
               "[校閲]→[ブックの保護]を解除してください。"
        Exit Sub
    End If

    '===============================
    ' 既存の CMF シートを安全に削除
    '===============================
    Dim sh As Object
    For Each sh In ThisWorkbook.Sheets
        If sh.Name = "CMF" Then
            Application.DisplayAlerts = False
            sh.Visible = xlSheetVisible   ' VeryHidden 対策
            sh.Delete
            Application.DisplayAlerts = True
            Exit For
        End If
    Next sh

    '===============================
    ' 新しい CMF シートを作成
    '===============================
    Set ws = ThisWorkbook.Worksheets.Add
    ws.Name = "CMF"

    ' 見出し
    ws.Range("A1:D1").Value = Array("λ(nm)", "x?(λ)", "y?(λ)", "z?(λ)")

    ' 波長 380?780 nm
    row = 2
    For λ = 380 To 780
        ws.Cells(row, 1).Value = λ
        row = row + 1
    Next λ

    ' 体裁
    ws.Columns("A:D").AutoFit
    ws.Range("A1:D1").Font.Bold = True
    ws.Range("A1:D1").Interior.Color = RGB(220, 230, 241)

    MsgBox "CMF シートのテンプレートを作成しました!"

End Sub

image.png

補足

(x,y)=(0.296,0.323)

前回(【光学系】波長から色座標を求める #Excel - Qiita)の結果は下記。

(x,y) = (0.324, 0.347)

image.png

 この辺りは別の機会に。

0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?