레이블이 coding인 게시물을 표시합니다. 모든 게시물 표시
레이블이 coding인 게시물을 표시합니다. 모든 게시물 표시

2025년 11월 29일 토요일

c++에서 decltype(...)의 용도

 예전에 c언어에서 함수를 매개변수로 사용하기 위한 함수 타입을 추출하기 위해서 다음과 같은 작업을 수행해 왔다.


위와 같이 typedef로 함수 타입을 일일히 적시해 주어야 한다. 이러한 주어진 표현식(변수, 함수 등..)의 정확한 타입을 추출해서 컴파일 시점에 알려주는 기능이 decltype()이다.



2023년 9월 10일 일요일

C++ value 용어 해설(lvalue, glvalue, xvalue, rvalue, prvalue)

원문: - New Value Terminology - Bjarne Stroustrup [https://www.stroustrup.com/terminology.pdf])

# C++ value terminology 

## lvalue

- 역사적으로 lvalue은 대입 표현식(A = B)의 왼쪽에 위치하곤 하기 때문에 left-value의 의미 불립니다. lvalue는 객체나 함수를 지칭하도록 의도되었습니다. 예를 들면, E가 포인터 형태의 표현식일때, *E는 E가 가르키는 객체나 함수를 가르키는 lvalue 표현식입니다. 다른 예로, 반환값의 타입이 lvalue인 함수를 호출한 결과는 lvalue 입니다.

## xvalue

- eXpiring value(만료값)로써, 일반적으로 수명이 거의 끝나가는 객체를 참조하기도 하는데, 예를 들어 리소스를 이동할 수 있도록 수명이 다한 객체를 참조하기도 합니다. xvalue는 rvalue 참조와 관련된 특정 종류의 표현식의 결과입니다. 예를 들면, 반환 유형이 rvalue 참조인 함수를 호출한 결과는 xvalue입니다.

## glvalue

- generalized lvalue(일반 lvalue)로써, lvalue 또는 xvalue를 의미합니다.

## rvalue

- 역사적으로 대입표현식의 오른쪽에 나타날 수 있기 때문에 right value의 의미로 불립니다. rvalue는 xvalue이기도 하고, 임시 객체 혹은 그 하위 객체, 객체와 연관되지 않는 값을 의미합니다.

## prvalue

- pure rvalue(순수 rvalue)로써, xvalue가 아닌 rvalue를 의미합니다. 예를 들면, 반환 유형이 참조가 아닌 함수를 호출한 결과는 prvalue입니다.

## 모델

- i : 구분성이 있는 - 즉, 주소, 포인터, 사용자가 두 사본이 동일한지 여부를 확인할 수 있습니다.

- m : 이동되어질 수 있는 - 즉, 정해지지 않았지만 유효한 상태에서 "복사"의 원본으로 보내는 것이 허용됩니다.

- iM : 구분성이 있으며, 이동되어질 수 없습니다.

- im : 구분성이 있으며, 이동되어질 수 있습니다.(예: lvalue를 rvalue 참조로 타입변환한 결과)

- Im : 구분성이 없으며, 이동되어질 수 있습니다.

iM   im   Im
    \ /    \ /
      i    m

왼쪽의 두 점("iM"과 "i"로 표시된)은 형식을 구분하는 사람들이 "lvalue"이라고 부르는 것이고, 오른쪽의 두 점("m"과 "Im"으로 표시된)은 형식을 구분하는 사람들이 "rvalue"이라고 부르는 것입니다.
즉, W의 왼쪽 "다리"는 "lvalue"와 관련된 이름을 가져야 하고, W의 오른쪽 "다리"는 "rvalue"와 관련된 이름을 가져야 합니다.

저는 표준 라이브러리 문구에서 "rvalue"가 "m"(일반화)을 의미한다는 사실을 발견했고, 표준 라이브러리의 기대와 텍스트를 보존하려면 W의 오른쪽 하단 지점을 "rvalue"로 명명해야 한다고 생각했습니다.

lvalue       xvalue      prvalue
         \        /     \         /
     iM \      /  im  \      / Im
           \    /          \    /
            \  / i          \  / m
             \/              \/
       glvalue        rvalue

W의 왼쪽 위 점은 "lvalue"이고 오른쪽 아래 점은 "rvalue"입니다. 왼쪽 하단 점은 이동이 가능한 고전적인 lvalue의 일반화입니다. 따라서 "generalized lvalue"입니다. 우리는 이것을 "glvalue"라고 명명했습니다. W의 오른쪽 위 점은 오른쪽 아래 점보다 덜 일반적입니다(지금은 예전과 마찬가지로 "rvalue"라고 부릅니다). 이 지점은 (소멸자를 제외하고는) 다시 참조할 수 없기 때문에 이동할 수 있는 객체의 원래 순수한 개념을 나타냅니다. 저는 "generalized lvalue"와 대조되는 "specialized rvalue"라는 표현이 마음에 들었지만 "prvalue"로 축약된 "pure rvalue"를 사용하였습니다.(그리고 아마도 당연한 결과일 것입니다). 따라서 W의 왼쪽 다리는 "lvalue"와 "glvalue"이고 오른쪽 다리는 "prvalue"와 "rvalue"입니다. 덧붙여서, 모든 값은 glvalue 또는 prvalue 중 하나이지만 둘 다는 아닙니다.

2022년 7월 27일 수요일

인공지능+영상처리+OceanOptics USB2000+Flir Camera 를 위한 시스템 설정

# 작업 시스템

윈도우즈 11, 64bits

# 설치 소프트웨어

## Python 3.8.xx

64bit 버전으로 설치하고, 현 시점에 최신 버전은 3.10이지만, 인공지능을 위한 tensorflow가 지원하는 최신 버전인 3.9.13버전이고 Spinnaker라는 Camera 소프트웨어는 3.8.xx버전을 지원한다.

### pip(Python Install Package) 설치

설치하고 가장 먼저해야할 작은 pip(Python Install Package)를 업그레이드 하는 것이다.

PS D:\python -m pip install --upgrade pip

그럼 tensorflow를 설치할 수 있는 환경이 조성되었다.

### tensorflow 와 tensorflow-cpu 설치 

PS D:\python -m pip install tensorflow

설치된 tensorflow를 확인해보자.

PS D:\> python

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32

Type "help", "copyright", "credits" or "license" for more information.

>>> import tensorflow as tf

2022-07-27 11:53:34.911913: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'cudart64_110.dll'; dlerror: cudart64_110.dll not found

2022-07-27 11:53:34.912570: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.

>>> quit()

CUDA 런타임 라이브러리가 없다고 에러를 발생시킨다. 그래서 cpu전용 구동할 수 있는 tensorflow-cpu를 추가 설치한다.

PS D:\> python -m pip install tensorflow-cpu

다시, 설치된 tensorflow의 버전을 확인해 보자.

PS D:\> python

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32

Type "help", "copyright", "credits" or "license" for more information.

>>> import tensorflow as tf

>>> tf.__version__

'2.9.1'

>>> quit()

### PySide6 설치

PS D:\> python -m pip install PySide6

설치된 버전 확인한다.

PS D:\> python

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32

Type "help", "copyright", "credits" or "license" for more information.

>>> import PySide6

>>> PySide6.__version__

'6.3.1'

>>> quit()

### OpenCV 설치

PS D:\> python -m pip install opencv-python

설치된 버전 확인한다.

PS D:\> python

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32

Type "help", "copyright", "credits" or "license" for more information.

>>> import cv2

>>> cv2.__version__

'4.6.0'

>>> quit()

## Visual Studio Code 설치

아래의 사이트를 방문해서 해당 시스템에 알맞은 설치파일을 다운로드 받는다.

https://code.visualstudio.com/download

설치 후 PySide6 예제를 코딩하고 실행해 본다.


## FLIR 카메라를 위한 환경 설정

과거의 Point Gray사의 카메라를 사용하기 위해서 현재는 FLIR로 합병된 Spinnaker SDK를 설치해야한다.

SpinnakerSDK_FULL_2.7.0.128.x64.exe 파일을 다운로드하고 설치한다.

그리고,  Python 에서 카메라를 운용하기 위해서 spinnaker_python-2.7.0.128-cp38-cp38-win_amd64.zip 파일도 다운로드하고, 다음의 명령어로 설치한다.

PS D:\> python -m pip install .\spinnaker_python-2.7.0.128-cp38-cp38-win_amd64.whl

그리고 설치확인한다.


import os
import PySpin
import sys

if __name__ == '__main__':
    # Retrieve singleton reference to system object
    system = PySpin.System.GetInstance()

    # Get current library version
    version = system.GetLibraryVersion()
    print('Library version: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build))

    # Retrieve list of cameras from the system
    cam_list = system.GetCameras()

    num_cameras = cam_list.GetSize()

    print('Number of cameras detected: %d' % num_cameras)


## Ocean Optics의 USB 4000을 위한 환경 설정

사전설치 사항으로 SpectraSuite가 설치되어 WinUSB 드라이버가 작동하고 있어야 한다.

그렇지 않다면, libusb-win32를 설치하고 수작업으로 드라이버를 설정하고 설치해야 한다.

아직은 seabreeze가 libusb-1.0을 지원하고 있지는 않는 것 같아. 위의 방법이 유일한 것 같다.

그럼 python에서 usb4000을 운용할 seabreeze를 설치한다.

PS D:\> python -m pip install seabreeze

설치된 버전을 확인한다.

PS D:\> python

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32

Type "help", "copyright", "credits" or "license" for more information.

>>> import seabreeze

>>> seabreeze.use('cseabreeze')

>>> from seabreeze.spectrometers import list_devices, Spectrometer

>>>  devices = list_devices()

  File "<stdin>", line 1

    devices = list_devices()

IndentationError: unexpected indent

>>> devices = list_devices()

>>> devices

[<SeaBreezeDevice USB4000:USB4U30285>]

설치는 잘 된 것 같다. 



2019년 2월 12일 화요일

When CUDA_ERROR_UNKNOWN comes up to call cuInit,

The detailed error messge is

(venv) user@LifeNTech:~/Workspace/deep_neural_network$ python test_keras.py Using TensorFlow backend. Epoch 1/5 2019-02-11 17:45:26.303774: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA 2019-02-11 17:45:26.315447: E tensorflow/stream_executor/cuda/cuda_driver.cc:397] failed call to cuInit: CUDA_ERROR_UNKNOWN 2019-02-11 17:45:26.315530: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:163] retrieving CUDA diagnostic information for host: LifeNTech 2019-02-11 17:45:26.315552: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:170] hostname: LifeNTech 2019-02-11 17:45:26.315635: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:194] libcuda reported version is: 390.87.0 2019-02-11 17:45:26.315687: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:198] kernel reported version is: 390.87.0 2019-02-11 17:45:26.315695: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:305] kernel version seems to match DSO: 390.87.0 

This thing  might be helpful.
# nvidia-modprobe -u


2019년 1월 24일 목요일

Install log of tensorflow-gpu on Debian (buster)

1. Install nvidia driver
# apt install nvidia-driver

1.1. Driver check
# nvidia-smi
Thu Jan 24 15:06:13 2019 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 390.87 Driver Version: 390.87 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 GeForce GTX 105... Off | 00000000:01:00.0 On | N/A | | 45% 30C P8 N/A / 75W | 220MiB / 4038MiB | 0% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | 0 872 G /usr/lib/xorg/Xorg 135MiB | | 0 13044 G /usr/lib/firefox-esr/firefox-esr 1MiB | | 0 13275 G /usr/lib/firefox-esr/firefox-esr 79MiB | | 0 14283 G /usr/lib/firefox-esr/firefox-esr 1MiB | +-----------------------------------------------------------------------------+

1.2. Install cuda toolkit
# apt install nvidia-cuda-toolkit
# cudafe++ -v
cudafe: NVIDIA (R) Cuda Language Front End Portions Copyright (c) 2005-2018 NVIDIA Corporation Portions Copyright (c) 1988-2016 Edison Design Group Inc. Based on Edison Design Group C/C++ Front End, version 4.14 (Jun 12 2018 23:07:12) Cuda compilation tools, release 9.2, V9.2.148
# nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2018 NVIDIA Corporation Built on Tue_Jun_12_23:07:04_CDT_2018 Cuda compilation tools, release 9.2, V9.2.148

2. Install Python3.6
2.1. Check default python in Debian 10(buster)
# apt policy python3
python3: Installed: 3.7.1-3 Candidate: 3.7.1-3 Version table: *** 3.7.1-3 500 500 http://debian-archive.trafficmanager.net/debian testing/main amd64 Packages 100 /var/lib/dpkg/status

2.2. Install packages of python3.6 and virtualenv
 # apt install python3.6 virtualenv

3. build the private console with python3.6
$ virtualenv --system-site-packages -p python3.6 ./venv
$ source ./venv/bin/activate
(venv) $ pip install --upgrade pip
(venv) $ pip install tensorflow-gpu

4. (TODO) Check tensorflow-gpu

(venv) $ python
Python 3.6.8 (default, Jan 3 2019, 03:42:36) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import tensorflow as tf Traceback (most recent call last): File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/pywrap_tensorflow.py", line 58, in from tensorflow.python.pywrap_tensorflow_internal import * File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/pywrap_tensorflow_internal.py", line 28, in _pywrap_tensorflow_internal = swig_import_helper() File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/pywrap_tensorflow_internal.py", line 24, in swig_import_helper _mod = imp.load_module('_pywrap_tensorflow_internal', fp, pathname, description) File "/home/user/Workspace/deep_neural_network/venv/lib/python3.6/imp.py", line 243, in load_module return load_dynamic(name, filename, file) File "/home/user/Workspace/deep_neural_network/venv/lib/python3.6/imp.py", line 343, in load_dynamic return _load(spec) ImportError: libcublas.so.9.0: cannot open shared object file: No such file or directory During handling of the above exception, another exception occurred: Traceback (most recent call last): File "", line 1, in File "/usr/local/lib/python3.6/dist-packages/tensorflow/__init__.py", line 22, in from tensorflow.python import pywrap_tensorflow # pylint: disable=unused-import File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/__init__.py", line 49, in from tensorflow.python import pywrap_tensorflow File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/pywrap_tensorflow.py", line 74, in raise ImportError(msg) ImportError: Traceback (most recent call last): File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/pywrap_tensorflow.py", line 58, in from tensorflow.python.pywrap_tensorflow_internal import * File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/pywrap_tensorflow_internal.py", line 28, in _pywrap_tensorflow_internal = swig_import_helper() File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/pywrap_tensorflow_internal.py", line 24, in swig_import_helper _mod = imp.load_module('_pywrap_tensorflow_internal', fp, pathname, description) File "/home/user/Workspace/deep_neural_network/venv/lib/python3.6/imp.py", line 243, in load_module return load_dynamic(name, filename, file) File "/home/user/Workspace/deep_neural_network/venv/lib/python3.6/imp.py", line 343, in load_dynamic return _load(spec) ImportError: libcublas.so.9.0: cannot open shared object file: No such file or directory Failed to load the native TensorFlow runtime. See https://www.tensorflow.org/install/install_sources#common_installation_problems for some common reasons and solutions. Include the entire stack trace above this error message when asking for help.

4.1. Fix the absence of libcublas.so.9.0

Have to do lots of works to install dependencies related to libcublas.so.9.0.
Please see my next post about installation of nvidia-cuda-toolkit.

P.S.
# prompt : root privilage
$ prompt : user prifilage

2018년 4월 11일 수요일

How to use USB4000 Spectrometer in Linux system (Debian)

There are two kinds of tools that cooperate USB4000 under GNU Debian distribution.
The first one is that C/C++ interface comes from OceanOptics Official, and the other is that the Python package was made as Open Source contribution.


1. Preliminary


The first thing to do before tools installation is to configure the system allowing any one to access the USB4000 without root premission.


1.1. Download SeaBreeze (i.e. OceanOptics Official tool for linux system).

https://sourceforge.net/projects/seabreeze/?source=typ_redirect





1.2. Extract *.zip file and copy the rules file into system.


With root permission,


# cp seabreeze-3.0.11/SeaBreeze/os-support/linux/10-oceanoptics.rules /etc/dev/rules.d/


1.3.  Plugin USB4000 and verify the connection.
 

You can see the USB4000 with Vendor ID: 0x2457 and Product ID: 0x1022.


2. OceanOptics' Offical Tool (i.e. SeaBreeze)


The tool contains C/C++ api, utilities and test codes.



2.1. Register the library path.


Before the compilation, load library path has to be registered.


# cd ~/seabreeze-3.0.11/SeaBreeze

#  export LD_LIBRARY_PATH="$PWD/lib"


2.2. Compilation with some errors and modification.


Once compiling the SeaBreeze, many errors are poped out that is actually kinds of warnings for c++11 deprecation.


This kinds of erros could be removed by comment out '-Werror' option.




2.3. Install dependencies.


# apt install libusb-dev, ....


2.4. Complete compilation.


# make


2.5. Execution of test code.

# ./test/seabreeze_test_posix




3. Open Sourced Toolkit (linux drivers for usb spectrometers)

This tool is open source tool that supports several usb spectrometers (i.e. avantes, hamamatsu, and OceanOptics). That is basically written by Python script, and internally using Kernel interface or Libusb. In otherwords, it do not requires any kinds of additional kernel driver.

3.1. Download python package.


Click Download Snapshot.

3.2. Install dependencies.

# pip install numpy, matlibplot, pyusb

3.3. Modification for visualizing live graph.

#!/usr/bin/env python3 -w

# python module to communicate with an Ocena Optics USB spectrometer
#
# Copyright (C) Wolfgang Schoenfeld (wolfgang.schoenfeld@hzg.de) and
#               Carsten Frank       (carsten.frank@hzg.de)
#
#       This program is free software; you can redistribute it and/or
#       modify it under the terms of the GNU General Public License as
#       published by the Free Software Foundation, version 2.
#
# This module is suitable to control a Avantes USB spectrometer. The following
# types are supported:
# - USB 4000
# - probably USB 2000

# C H A N G E S #
# 28. 07. 2012 Carsten Frank
# - created based on the Hamamatsu code
# - also based on the documentation given in the USB4000-OEM_Data-Sheet.pdf
#   which is publicly available (http://www.oceanoem.com/).

from __future__ import print_function

import os
import os.path
import re
import time
import sys
import numpy as np
import multiprocessing
import ctypes
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
#import cv2

#sys.path.append('/home/carsten/Programme/python/FiaSia')
#sys.path.append('/home/carsten/Programme/python')
#from findUSBserialDevice import getDeviceFileFromAddress, testAddress

import usb.core, usb.util

USB_USBSPEC_VENDOR_ID = 0x2457
USB_USBSPEC_PRODUCT_ID_USB4000 = 0x1022
USB_USBSPEC_PRODUCT_ID_USB650 = 0x1014   # not working, kept for future use
PIXEL_COUNT_USB4000 = 3840

class USB4000: ## GUI OoUSB4000 ## Adds this device to the spectrometers listed in the GUI
    '''Connect to a Ocean Optics mini spectrometer via USB. '''

    # device name should be either the USB-address or the serial numer
    def __init__(self, deviceName = None):
        # the device name would be the 'device' in the "/dev/" folder (linux)
        self.deviceName   = None
        self.serialNumber = None

        # Only needed for pyUSB. Checks if the configuration was already set.
        self.configurationSet = False

        # self.usedInterface is set in findAllConnectedSpectrometers
        # self.usedInterface equals None if no device is found
        devNotFound = True

        # If no spectrometer is foud this function complains and exits!
        self.specs = self._findAllConnectedSpectrometers()

        if self.usedInterface == 'pyusb':
                if  deviceName == None:
                        # use the 'first' spectrometer
                        self.serialNumber = self.specs.keys()[0]
                        self.deviceName   = None
                        self.basePath     = None
                        devNotFound = False
                else:
                        # only the serial number would be delivered as device name in this context (pyusb)
                        if self.specs.has_key(deviceName):
                                self.serialNumber = key
                                self.deviceName   = None
                                self.basePath     = None
                                devNotFound       = False

        elif self.usedInterface == 'kernel':
                if  deviceName == None:
                        # use random device (if more than one device is attached)
                        self.serialNumber = self.specs.keys()[0]
                        self.deviceName = self.specs[self.serialNumber][0]
                        self.basePath = os.path.join("/sys/bus/usb/drivers/usbhspec/", self.specs[self.serialNumber][1])
                        devNotFound = False
                else:
                        # if it is an valid usb address like '8-2:1.0'
                        if testAddress(deviceName):
                                for key, value in self.specs.iteritems():
                                        if value[1] == deviceName:
                                                self.deviceName = value[0]
                                                self.basePath = os.path.join("/sys/bus/usb/drivers/usbhspec/", value[1])
                                                devNotFound = False
                                                break
                        else:
                                for key, value in self.specs.iteritems():
                                        if value[0] == deviceName:
                                                self.deviceName = value[0]
                                                self.basePath = os.path.join("/sys/bus/usb/drivers/usbhspec/", value[1])
                                                devNotFound = False
                                                break
                                        if key == deviceName:
                                                self.deviceName = value[0]
                                                self.basePath = os.path.join("/sys/bus/usb/drivers/usbhspec/", value[1])
                                                devNotFound = False
                                                break

        if devNotFound == True:
                print('Device %s not found! Exiting ...'%(deviceName))
                sys.exit()

        if self.usedInterface == 'kernel':
                #: First calibration coefficient of the spectrometer. Pixel counting starts at 1!
                self.startWavelength = float(file(os.path.join(self.basePath,"a0")).read())
                #: Second calibration coefficient.
                self.firstKoeff      = float(file(os.path.join(self.basePath,"a1")).read())
                #: Third calibration coefficient.
                self.secondKoeff     = float(file(os.path.join(self.basePath,"a2")).read())
                #: Fourth calibration coefficient.
                self.thirdKoeff      = float(file(os.path.join(self.basePath,"a3")).read())
                #: Fifth calibration coefficient.
                self.fourthKoeff     = float(file(os.path.join(self.basePath,"a4")).read())
                #: Guess what!
                self.fifthKoeff      = float(file(os.path.join(self.basePath,"a5")).read())
                self.deviceName = file(os.path.join(self.basePath,"device_name")).read().strip()
                self.sensorName = file(os.path.join(self.basePath,"sensor_name")).read().strip()

                self.devicePath = "/dev/%s" % (self.deviceName)
        else: # self.usedInterface == 'pyusb'
                # we do know the serialNumber!

                value = self.specs[self.serialNumber]
                dev = value[3]

                # create endpoints

                cfg = dev.get_active_configuration()
                interface_number = cfg[(0,0)].bInterfaceNumber
                alternate_setting = usb.control.get_interface(dev, interface_number)
                intf = usb.util.find_descriptor(cfg, bInterfaceNumber = interface_number,bAlternateSetting = alternate_setting)

                self.ep1Out = usb.util.find_descriptor(intf, custom_match = lambda e: e.bEndpointAddress == 0x01)
                self.ep1In  = usb.util.find_descriptor(intf, custom_match = lambda e: e.bEndpointAddress == 0x81)
                self.ep2    = usb.util.find_descriptor(intf, custom_match = lambda e: e.bEndpointAddress == 0x82)
                self.ep6    = usb.util.find_descriptor(intf, custom_match = lambda e: e.bEndpointAddress == 0x86)

                #: Get start wavelength
                self.startWavelength = self._query(0x01, "num")
                #: Second calibration coefficient.
                self.firstKoeff      = self._query(0x02, "num")
                #: Third calibration coefficient.
                self.secondKoeff     = self._query(0x03, "num")
                #: Fourth calibration coefficient.
                self.thirdKoeff      = self._query(0x04, "num")
                #: Fifth calibration coefficient.
                self.fourthKoeff     = 0.0
                #: Guess what!
                self.fifthKoeff      = 0.0
                self.sensorName = ''

                self.deviceName = dev


        # Default
        self.pixelOffset = 0
        # S10420-1006/-1106 CCD image sensor see documentation (Device structure)
        if (self.sensorName == "S10420-1106") or (self.sensorName == "S10420-1006"):
                self.pixelOffset = 10
                print("Sensor '%s' means pixel offset of %d" % (self.sensorName, self.pixelOffset))
        elif (self.sensorName.find("S8377") > -1) or (self.sensorName.find("S8378") > -1):
                self.pixelOffset = 0
                print("Sensor '%s' means pixel offset of %d" % (self.sensorName, self.pixelOffset))



        # gereate wavelength array
        self.wlArr = np.zeros(PIXEL_COUNT_USB4000)
        for pix in range(PIXEL_COUNT_USB4000):
                self.wlArr[pix] = self.startWavelength       + \
                                   pix *   self.firstKoeff   + \
                                  (pix**2)*self.secondKoeff  + \
                                  (pix**3)*self.thirdKoeff   + \
                                  (pix**4)*self.fourthKoeff  + \
                                  (pix**5)*self.fifthKoeff
        print(self.wlArr)

    def findAllConnectedSpectrometers(self):
            return self.specs
    def _findAllConnectedSpectrometers(self):
        """Function to find all connected USB-spectrometers

        Returns a list/dictionary? with spectrometers containing:
        - device name
        - serial number
        - start wavelength
        """

        specs = {}
        self.usedInterface = "kernel"

        basePath = "/sys/bus/usb/drivers/usbhspec/"
        if not os.path.exists(basePath):
                self.usedInterface = "pyusb"
                print("No spectrometer found using the kernel module.")
                print("Now testing pyusb!")

        if self.usedInterface == "kernel":
                fList = os.listdir(basePath)

                for i in fList:
                        mtch = re.search("\d\-\d.*\:\d+\.\d+", i)
                        if mtch:
                                serNr = open(os.path.join(basePath, i, "serial_number"), "r").read().strip()
                                res = getDeviceFileFromAddress("usb", i)
                                if len(res) <> 1:
                                        print("Something went wrong. I found two USB devices with the same path!")
                                        for i in res:
                                                print(i)
                                        print("PLEASE call someone (Carsten) who knows what to do now!")
                                        sys.exit()

                                specs[serNr] = (res[0][0], i, "%.0f" % (float(file(os.path.join(basePath, i,"a0")).read())))
        elif self.usedInterface == "pyusb":
                # use the pyusb interface (only ONE of these interfaces WILL work)
                devs = list(usb.core.find(idVendor=USB_USBSPEC_VENDOR_ID, idProduct=USB_USBSPEC_PRODUCT_ID_USB4000, find_all=True))
                #devs = usb.core.find(idVendor=USB_USBSPEC_VENDOR_ID, idProduct=USB_USBSPEC_PRODUCT_ID_USB650, find_all=True)
                if len(devs) > 0:
                        print("Found %d spectrometer(s) via pyusb!" % (len(devs)))
                else:
                        print("Also no spectrometer found using pyusb.")

                # find alls connected devices
                for dev in devs:
                        #dev.set_configuration()
                        #cfg = dev.get_active_configuration()
                        #interface_number = cfg[(0,0)].bInterfaceNumber
                        #alternate_setting = usb.control.get_interface(dev, interface_number)
                        #intf = usb.util.find_descriptor(cfg, bInterfaceNumber = interface_number,bAlternateSetting = alternate_setting)

                        cfg=dev[0]
                        intf=cfg[(0, 0)]

                        self.ep1Out=intf[0]
                        self.ep1In =intf[3]

                        #self.ep1Out = usb.util.find_descriptor(intf, custom_match = lambda e: e.bEndpointAddress == 0x01)
                        #self.ep1In  = usb.util.find_descriptor(intf, custom_match = lambda e: e.bEndpointAddress == 0x81)

                        readSuccess = False
                        while not readSuccess:
                                # INITIALIZE
                                self.ep1Out.write(chr(0x01))
                                time.sleep(0.5)
                                readSuccess = True
                                # get integration time

                                #self.ep1Out.write(chr(0xfe))
                                #try:
                                        #res = self.ep1In.read(64)
                                        #readSuccess = True
                                #except usb.core.USBError:
                                        #print "Failed"
                                        #pass

                        #int_time = (res[5]<<24 br="" res="">                        #print int_time

                        # get necessary data for all devices {'510C2114': ('usbhspec0', '5-2:1.0', '324'  )}
                        #                                    { serialNo : ( 'pyusb'   ,  None    , firstWL)}
                        # get serial number
                        serNr = self._query(0x00, "str")
                        # get a0
                        a0 = self._query(0x01, "num")
                        del(self.ep1Out, self.ep1In)
                        specs[serNr] = ( 'pyusb'   ,  None    ,  "%.0f" % (float(a0)), dev)
        else:
                print("This point should never be reached!")
                sys.exit()

        if len(specs) == 0:
                self.usedInterface = None

        return specs

    def _query(self, byte, decode=None):
        self.ep1Out.write(chr(0x05) + chr(byte))
        res = self.ep1In.read(64)
        if   decode == 'str':
            s   = ''.join(map(chr,res[2:])).rstrip()
            res = s.replace('\x00','')
            res = res.replace('\xa4','')
        elif decode == 'num':
            s   = ''.join(map(chr,res[2:])).rstrip()
            res = s.replace('\x00','')
            res = res.replace('\xa4','')  #FIXME: ??
            res = float(res)
        return res

    def setIntegrationTime(self, intTime, test=True):
        # integration_time possible values between 10 - 65535000 (in usec)
        if (intTime < 10) or  (intTime > 65535000):
                print("USB4000.setIntegrationTime : Integration Time not allowed! please use vaues between")
                print("10 and 65535000 us")
                return False
        while True:
                if   self.usedInterface == 'pyusb':
                        c = []
                        c.append( intTime        & 0xFF )
                        c.append((intTime >>  8) & 0xFF )
                        c.append((intTime >> 16) & 0xFF )
                        c.append((intTime >> 24) & 0xFF )
                        self.ep1Out.write(chr(0x02) + bytearray(c))
                else:
                        print("Interface not yet implemented")
                        sys.exit()

                if not test:
                        break
                time.sleep(.01)
                devIT = self.getIntegrationTime()
                print("setIntTime : %d  ----  deviceIntTime : %d" % (devIT, intTime))
                if devIT == intTime:
                        break
                if (time.time() - startT) > 1.0:
                        return False
        self.integrationTime = intTime
        return True

    def getIntegrationTime(self):
        # integration_time possible values between 10000 and 10000000 (in usec)
        if   self.usedInterface == 'pyusb':

                startT = time.time()
                self.ep1Out.write(chr(0xfe))
                res    = self.ep1In.read(64)
                #while len(res) <> 4:
                        #print("--------------------------------- getIntegrationTime -- Answer incorrect (too long or too short)!")
                        #time.sleep(.01)
                        #res    = self.deviceName.ctrl_transfer(bmRequestType = 0xc0, bRequest = 0x0b, wValue = 0x01, wIndex = 0x00, data_or_wLength = 4, timeout = 2000)
                        #if (time.time() - startT) > .5:
                                #raise
                intTime = (res[5] << 24) + (res[4] << 16) + (res[3] << 8) + res[2]
        elif self.usedInterface == 'kernel':
                print("Interface not yet implemented")
                sys.exit()
        return intTime

    def getSensorName(self):
        return self.sensorName

    def getSerialNumber(self):
        return self.serialNumber

    def getSpectrum(self, timeout = None):
        """This function grabs spectral data from the spectrometer. Addidtional
        information is also encoded in the data read from the interface so
        take nothing for granted!

        I've got two different spectrometers from which I tried to conclude
        what to do with the data. I may have made invalid assumptions!

        You have to read 0x1040 bytes of data. These are 16bit numbers so it does
        make sense to calculate these numbers from the data and the only use those
        integers.

        The first number (16 bit in this context) was alwas 2. That only changes
        if you read data if the spectrometer is not yet ready (integration time).
        If the spectrometer isn't ready all numers are zero.

        The second number is an index which is 0,1 or 2 and just counts up.

        Third is the amount of active pixels (in contrast to the amount of pixels
        sixth number (index 5)). Please see the documentation to your image sensor
        (e.g. S10420-1106 from Hamamtsu).

        Forth (index 3) is the most important number because it says where to find
        the first pixel in the whole dataset of 0x1040/2 = 0x820 16bit numbers.

        The fifth seems to be the end index because startIndex + amountOfPixels = endIndex
        HOWEVER in my case the end index is higer than 0x820 which means that I can be
        very wrong with my interpretation.

        In my case and using the S10420-1106 sensor I found that the first four numbers
        of the spectrum (starting with startIndex) seem to be darkened pixels. You can
        increase the integration time as much as you wish these numbers stay (more or less)
        the same. Use at your own risc!

        Actually the spectrum seems to start at startIndex + 10 pixels/numbers which was
        veryfied for MY spectrometer with a really good and freshly checked laboratory
        spectrometer from Perkin Elmer (wavelength correctness was checkt with the aid of
        special filters).
        So I calculate the start of the spectrum unsing
        startSpectrum = startIndex + (amountOfPixels - amountOfActivePixels) / 2
        which seems to make sense.

        The wavelength correctness was VERY good compared to spectrometers from avantes,
        ocean optics and trios. We estimat an offset of about .4 nm over the whole spectrum
        which lies in the tolerance of of our measurement setup.
        """

        if timeout == None:
                timeout = self.integrationTime / 1000000.0 * 2.1
        startT = time.time()
        while 1:
                #: Grab data from the interface
                if self.usedInterface == 'pyusb':
                        # ask for the data
                        self.ep1Out.write(chr(0x09))
                        resArr = np.zeros(256 * 15)
                        resArrIndex = 0
                        # read four times from endpoint 6 an four times from ep2
                        while 1:
                                try:
                                        res = self.ep6.read(512)
                                except usb.core.USBError:
                                        if (time.time() - startT) > timeout:
                                                raise usb.core.USBError("Timeout")
                                        time.sleep(.01)
                                        continue
                                else:
                                        break

                        for i in range(0,len(res),2):
                                resArr[resArrIndex] = (res[i+1] << 8) + res[i]
                                resArrIndex += 1


                        for i in range(3):
                            res = self.ep6.read(512)
                            for i in range(0,len(res),2):
                                resArr[resArrIndex] = (res[i+1] << 8) + res[i]
                                resArrIndex += 1
                        for i in range(4,15):
                            res = self.ep2.read(512)
                            for i in range(0,len(res),2):
                                resArr[resArrIndex] = (res[i+1] << 8) + res[i]
                                resArrIndex += 1
                        sync_packet = self.ep2.read(1)
                        return resArr
                else:
                        return None

        return resArr

def frange(start, end=None, inc=None):
    "A range function, that does accept float increments..."

    if end == None:
        end = start + 0.0
        start = 0.0

    if inc == None:
        inc = 1.0

    L = []
    while 1:
        next = start + len(L) * inc
        if inc > 0 and next >= end:
            break
        elif inc < 0 and next <= end:
            break
        L.append(next)

    return L

pauseEvent = False
animationHandle = None

def main(argv):
    global animationHandle
    
    ham = USB4000()
    #print ham.findAllConnectedSpectrometers()
    ham.setIntegrationTime(100000)
    res = ham.getSpectrum()
    print(res, len(res), max(res))
    
    fig = plt.figure()
    fig.suptitle('Demo. of Spectrometer')

    ax = fig.add_subplot(1, 1, 1)
    #plt.axis([0, len(res), 0, 40000])
    
    '''
    li, = ax.plot(ham.wlArr, res, c='r')
    #ax.relim()
    #ax.autoscale_view(True, True, True)
    #fig.canvas.draw()
    plt.show(block=False)

    while True:
        try:
            res = ham.getSpectrum()
            li.set_ydata(res)
            fig.canvas.draw()
        except KeyboardInterrupt:
            break

    '''
    def draw_spectrum(i):
        res = ham.getSpectrum()
        ax.clear()
        ax.set_title('USB4000')
        #ax.set_xlim(ham.wlArr.min(), ham.wlArr.max())
        #ax.set_ylim(0, 36000)
        ax.set_xlabel('Wavelength')
        ax.set_ylabel('Intensity')
        ax.plot(ham.wlArr, res, c='r')
        
    ax.relim()
    ax.autoscale_view(True, True, True)
    animationHandle = animation.FuncAnimation(fig, draw_spectrum, blit=False, interval=1, repeat=True)
    
    def on_click(event):
        global pauseEvent
        global animationaHandle
        #print('clicked')
        pauseEvent ^= True
        if pauseEvent:
            animationHandle.event_source.stop()
        else:
            animationHandle.event_source.start()

    fig.canvas.mpl_connect('button_press_event', on_click)

    plt.show()
    
    return 0
    
if __name__ == '__main__':
    sys.exit(main(sys.argv))


3.4. Execution.




4. References

https://sourceforge.net/projects/seabreeze/?source=typ_redirect

https://sourceforge.net/p/usbspecdrivers/wiki/Installation/



2016년 4월 20일 수요일

조명 장치의 조사 영역 분포도 검사 시뮬레이션

파이선 소스 코드


 #!/usr/bin/python  
 import Image  
 import numpy  
 import math  
 palette=((0, 0, 0), (0, 0, 10), (0, 0, 20), (0, 0, 30), (0, 0, 37), (0, 0, 42), (0, 0, 46), (0, 0, 50), (0, 0, 54), (0, 0, 58), (0, 0, 62), (0, 0, 66), (0, 0, 70), (0, 0, 74), (0, 0, 79), (0, 0, 82), (1, 0, 85), (1, 0, 87), (2, 0, 89), (2, 0, 92), (3, 0, 94), (4, 0, 97), (4, 0, 99), (5, 0, 101), (6, 0, 103), (7, 0, 105), (8, 0, 107), (9, 0, 110), (10, 0, 112), (11, 0, 115), (12, 0, 116), (13, 0, 117), (13, 0, 118), (14, 0, 119), (16, 0, 120), (18, 0, 121), (19, 0, 123), (21, 0, 124), (23, 0, 125), (25, 0, 126), (27, 0, 128), (28, 0, 129), (30, 0, 131), (32, 0, 132), (34, 0, 133), (36, 0, 134), (38, 0, 135), (40, 0, 137), (42, 0, 137), (44, 0, 138), (46, 0, 139), (48, 0, 140), (50, 0, 141), (52, 0, 142), (54, 0, 142), (56, 0, 143), (57, 0, 144), (59, 0, 145), (60, 0, 146), (62, 0, 147), (63, 0, 147), (65, 0, 148), (66, 0, 149), (68, 0, 149), (69, 0, 150), (71, 0, 150), (73, 0, 150), (74, 0, 150), (76, 0, 151), (78, 0, 151), (79, 0, 151), (81, 0, 151), (82, 0, 152), (84, 0, 152), (86, 0, 152), (88, 0, 153), (90, 0, 153), (92, 0, 153), (93, 0, 154), (95, 0, 154), (97, 0, 155), (99, 0, 155), (100, 0, 155), (102, 0, 155), (104, 0, 155), (106, 0, 155), (108, 0, 156), (109, 0, 156), (111, 0, 156), (112, 0, 156), (113, 0, 157), (115, 0, 157), (117, 0, 157), (119, 0, 157), (120, 0, 157), (122, 0, 157), (124, 0, 157), (126, 0, 157), (127, 0, 157), (129, 0, 157), (131, 0, 157), (132, 0, 157), (134, 0, 157), (135, 0, 157), (137, 0, 157), (138, 0, 157), (139, 0, 157), (141, 0, 157), (143, 0, 156), (145, 0, 156), (147, 0, 156), (149, 0, 156), (150, 0, 155), (152, 0, 155),  (153, 0, 155),  (155, 0, 155),  (156, 0, 155),  (157, 0, 155),  (159, 0, 155),  (160, 0, 155),  (162, 0, 155),  (163, 0, 155),  (164, 0, 155),  (166, 0, 154),  (167, 0, 154),  (168, 0, 154),  (169, 0, 153),  (170, 0, 153),  (171, 0, 153),  (173, 0, 153),  (174, 1, 152),  (175, 1, 152),  (176, 1, 152),  (176, 1, 152),  (177, 1, 151),  (178, 1, 151),  (179, 1, 150),  (180, 2, 150),  (181, 2, 149),  (182, 2, 149),  (183, 3, 149),  (184, 3, 149),  (185, 4, 149),  (186, 4, 149),  (186, 4, 148),  (187, 5, 147),  (188, 5, 147),  (189, 5, 147),  (190, 6, 146),  (191, 6, 146),  (191, 6, 146),  (192, 7, 145),  (192, 7, 145),  (193, 8, 144),  (193, 9, 144),  (194, 10, 143),  (195, 10, 142),  (195, 11, 142),  (196, 12, 141),  (197, 12, 140),  (198, 13, 139),  (198, 14, 138),  (199, 15, 137),  (200, 16, 136),  (201, 17, 135),  (202, 18, 134),  (202, 19, 133),  (203, 19, 133),  (203, 20, 132),  (204, 21, 130),  (205, 22, 129),  (206, 23, 128),  (206, 24, 126),  (207, 24, 124),  (207, 25, 123),  (208, 26, 121),  (209, 27, 120),  (209, 28, 118),  (210, 28, 117),  (210, 29, 116),  (211, 30, 114),  (211, 32, 113),  (212, 33, 111),  (212, 34, 110),  (213, 35, 107),  (213, 36, 105),  (214, 37, 103),  (215, 38, 101),  (216, 39, 100),  (216, 40, 98),  (217, 42, 96),  (218, 43, 94),  (218, 44, 92),  (219, 46, 90),  (219, 47, 87),  (220, 47, 84),  (221, 48, 81),  (221, 49, 78),  (222, 50, 74),  (222, 51, 71),  (223, 52, 68),  (223, 53, 65),  (223, 54, 61),  (224, 55, 58),  (224, 56, 55),  (224, 57, 51),  (225, 58, 48),  (226, 59, 45),  (226, 60, 42),  (227, 61, 38),  (227, 62, 35),  (228, 63, 32),  (228, 65, 29),  (228, 66, 28),  (229, 67, 27),  (229, 68, 25),  (229, 69, 24),  (230, 70, 22),  (231, 71, 21),  (231, 72, 20),  (231, 73, 19),  (232, 74, 18),  (232, 76, 16),  (232, 76, 15),  (233, 77, 14),  (233, 77, 13),  (234, 78, 12),  (234, 79, 12),  (235, 80, 11),  (235, 81, 10),  (235, 82, 10),  (235, 83, 9),  (236, 84, 9),  (236, 86, 8),  (236, 87, 8),  (236, 88, 8),  (237, 89, 7),  (237, 90, 7),  (237, 91, 6),  (238, 92, 6),  (238, 92, 5),  (238, 93, 5),  (238, 94, 5),  (239, 95, 4),  (239, 96, 4),  (239, 97, 4),  (239, 98, 4),  (240, 99, 3),  (240, 100, 3),  (240, 101, 3),  (241, 102, 3),  (241, 102, 3),  (241, 103, 3),  (241, 104, 3),  (241, 105, 2),  (241, 106, 2),  (241, 107, 2),  (241, 107, 2),  (242, 108, 1),  (242, 109, 1),  (242, 110, 1),  (243, 111, 1),  (243, 112, 1),  (243, 113, 1),  (243, 114, 1),  (244, 115, 0),  (244, 116, 0),  (244, 117, 0),  (244, 118, 0),  (244, 119, 0),  (244, 120, 0),  (244, 122, 0),  (245, 123, 0),  (245, 124, 0),  (245, 126, 0),  (245, 127, 0),  (246, 128, 0),  (246, 129, 0),  (246, 130, 0),  (247, 131, 0),  (247, 132, 0),  (247, 133, 0),  (247, 134, 0),  (248, 135, 0),  (248, 136, 0),  (248, 136, 0),  (248, 137, 0),  (248, 138, 0),  (248, 139, 0),  (248, 140, 0),  (249, 141, 0),  (249, 141, 0),  (249, 142, 0),  (249, 143, 0),  (249, 144, 0),  (249, 145, 0),  (249, 146, 0),  (249, 147, 0),  (250, 148, 0),  (250, 149, 0),  (250, 150, 0),  (251, 152, 0),  (251, 153, 0),  (251, 154, 0),  (251, 156, 0),  (252, 157, 0),  (252, 159, 0),  (252, 160, 0),  (252, 161, 0),  (253, 162, 0),  (253, 163, 0),  (253, 164, 0),  (253, 166, 0),  (253, 167, 0),  (253, 168, 0),  (253, 170, 0),  (253, 171, 0),  (253, 172, 0),  (253, 173, 0),  (253, 174, 0),  (254, 175, 0),  (254, 176, 0),  (254, 177, 0),  (254, 178, 0),  (254, 179, 0),  (254, 180, 0),  (254, 181, 0),  (254, 182, 0),  (254, 184, 0),  (254, 185, 0),  (254, 185, 0),  (254, 186, 0),  (254, 187, 0),  (254, 188, 0),  (254, 189, 0),  (254, 190, 0),  (254, 192, 0),  (254, 193, 0),  (254, 194, 0),  (254, 195, 0),  (254, 196, 0),  (254, 197, 0),  (254, 198, 0),  (254, 199, 0),  (254, 200, 0),  (254, 201, 1),  (254, 202, 1),  (254, 202, 1),  (254, 203, 1),  (254, 204, 2),  (254, 205, 2),  (254, 206, 3),  (254, 207, 4),  (254, 207, 4),  (254, 208, 5),  (254, 209, 6),  (254, 211, 8),  (254, 212, 9),  (254, 213, 10),  (254, 214, 10),  (254, 215, 11),  (254, 216, 12),  (254, 217, 13),  (255, 218, 14),  (255, 218, 14),  (255, 219, 16),  (255, 220, 18),  (255, 220, 20),  (255, 221, 22),  (255, 222, 25),  (255, 222, 27),  (255, 223, 30),  (255, 224, 32),  (255, 225, 34),  (255, 226, 36),  (255, 226, 38),  (255, 227, 40),  (255, 228, 43),  (255, 228, 46),  (255, 229, 49),  (255, 230, 53),  (255, 230, 56),  (255, 231, 60),  (255, 232, 63),  (255, 233, 67),  (255, 234, 70),  (255, 235, 73),  (255, 235, 77),  (255, 236, 80),  (255, 237, 84),  (255, 238, 87),  (255, 238, 91),  (255, 238, 95),  (255, 239, 99),  (255, 239, 103),  (255, 240, 106),  (255, 240, 110),  (255, 241, 114),  (255, 241, 119),  (255, 241, 123),  (255, 242, 128),  (255, 242, 133),  (255, 242, 138),  (255, 243, 142),  (255, 244, 146),  (255, 244, 150),  (255, 244, 154),  (255, 245, 158),  (255, 245, 162),  (255, 245, 166),  (255, 246, 170),  (255, 246, 175),  (255, 247, 179),  (255, 247, 182),  (255, 248, 186),  (255, 248, 189),  (255, 248, 193),  (255, 248, 196),  (255, 249, 199),  (255, 249, 202),  (255, 249, 205),  (255, 250, 209),  (255, 250, 212),  (255, 251, 216),  (255, 252, 219),  (255, 252, 223),  (255, 253, 226),  (255, 253, 229),  (255, 253, 232),  (255, 254, 235),  (255, 254, 238),  (255, 254, 241),  (255, 254, 244),  (255, 255, 246))    
 LEDs_on_head = 4  
 LED_interval = 60  
 shift_on_head = 30   
 head_angle = 30  
 distance_to_head = 200  
 #user_FOV_width  
 #user_FOV_height  
 #45 degree -> 0  
 #22.5 degree -> 400  
 #0 degree -> 2000  
 LED_FOV_dy = int(round(distance_to_head * math.tan(math.radians(45)) * 1.25))  
 LED_FOV_dx1 = int(round(distance_to_head * math.cos(math.radians(head_angle)) * math.tan(math.radians(45 + head_angle)) - distance_to_head * math.sin(math.radians(head_angle))))  
 LED_FOV_dx2 = int(round(distance_to_head * math.sin(math.radians(head_angle)) - distance_to_head * math.cos(math.radians(head_angle)) * math.tan(math.radians(head_angle - 45))))  
 LED_FOV_xcenter = LED_FOV_dx1  
 LED_FOV_ycenter = LED_FOV_dy  
 LED_FOV_width = LED_FOV_dx1 + LED_FOV_dx2  
 LED_FOV_height = 2 * LED_FOV_dy  
 print LED_FOV_width  
 print LED_FOV_height  
 def py_ang(v1, v2):  
   """ Returns the angle in radians between vectors 'v1' and 'v2'  """  
   cosang = numpy.dot(v1, v2)  
   sinang = numpy.linalg.norm(numpy.cross(v1, v2))  
   return numpy.arctan2(sinang, cosang)  
 LED_FOV_map = numpy.zeros((LED_FOV_height, LED_FOV_width))  
 v1 = numpy.array([-distance_to_head * math.sin(math.radians(head_angle)), 0, -distance_to_head * math.cos(math.radians(head_angle))])  
 for y in range(LED_FOV_height):  
   for x in range(LED_FOV_width):  
     dv = numpy.array([x - LED_FOV_xcenter, y - LED_FOV_ycenter, 0])  
     v2 = v1 + dv  
     ang = abs(math.degrees(py_ang(v1, v2)))  
     if ang > 45.0:  
       intensity = 0  
     elif ang > 22.5:  
       intensity = -400.0 / (45.0 - 22.5) * (ang - 45.0)  
     elif ang > 11.2:  
       intensity = (400.0 - 1600.0) / (22.5 - 11.2) * (ang - 22.5) + 400.0  
     else:  
       intensity = (1600.0 - 2000.0) / (11.2 - 0) * (ang - 11.2) + 1600.0  
     LED_FOV_map[y][x] = intensity * numpy.power(numpy.dot(v1, v2), 2) / numpy.power(numpy.linalg.norm(v2), 4)  
 head_FOV_width = 2 * max(LED_FOV_dx1, LED_FOV_dx2)  
 head_FOV_height = LED_FOV_height + (LEDs_on_head - 1) * LED_interval + shift_on_head  
 head_FOV_map = numpy.zeros((head_FOV_height, head_FOV_width))  
 print head_FOV_width  
 print head_FOV_height  
 for y in range(LED_FOV_height):  
   for x in range(LED_FOV_width):  
     for i in range(LEDs_on_head):  
       head_FOV_map[y + i * LED_interval][x] += LED_FOV_map[y][x]  
       head_FOV_map[y + i * LED_interval + shift_on_head][(head_FOV_width -1) - x] += LED_FOV_map[y][x]  
 # 380 nm to 780 nm -> RGB  
 def wave2rgb(wavelength):  
   GAMMA = 1.0  
   # ITYPE=1 - PLAIN SPECTUM  
   # ITYPE=2 - MARK SPECTRUM AT 100 nm INTEVALS  
   # ITYPE=3 - HYDROGEN BALMER EMISSION SPECTRA  
   # ITYPE=4 - HYDROGEN BALMER ABSORPTION SPECTRA  
   ITYPE = 1  
   if wavelength < 440:  
     r = -1.0 * (wavelength - 440.0) / (440.0 - 380.0)  
     g = 0  
     b = 1  
   elif wavelength < 490.0:  
     r = 0.0  
     g = (wavelength - 440.0) / (490.0 - 440.0)  
     b = 1.0  
   elif wavelength < 510.0:  
     r = 0.0  
     g = 1.0  
     b = -1.0 * (wavelength - 510.0) / (510.0 - 490.0)  
   elif wavelength < 580:  
     r = (wavelength - 510.0) / (580.0 - 510.0)  
     g = 1.0  
     b = 0.0  
   elif wavelength < 645:  
     r = 1.0  
     g = -1.0 * (wavelength - 645.0) / (645.0 - 580.0)  
     b = 0.0  
   else:  
     r = 1.0  
     g = 0.0  
     b = 0.0  
   if wavelength > 700.0:  
     sss = 0.3 + 0.7 * (780.0 - wavelength) / (780.0 - 700.0)  
   elif wavelength < 420.0:  
     sss = 0.3 + 0.7 * (wavelength - 380.0) / (420.0 - 380.0)  
   else:  
     sss = 1.0  
   # Gamma adjust and write image to an array  
   r = int(255.0 * math.pow(sss * r, GAMMA))  
   g = int(255.0 * math.pow(sss * g, GAMMA))  
   b = int(255.0 * math.pow(sss * b, GAMMA))  
   if ITYPE == 2:  
     if abs(wavelength - 400) < 1 or abs(wavelength - 500) < 1 or abs(wavelength - 600) < 1 or abs(wavelength - 700) < 1:  
       r = 255  
       g = 255  
       b = 255  
   elif ITYPE == 3:  
     if abs(wavelength-656.0) > 1.0 and abs(wavelength-486.0) > 1.0 and abs(wavelength-433.0) > 1.0 and abs(wavelength-410.0) > 1.0 and abs(wavelength-396.0) > 1.0:  
       r = 0  
       g = 0  
       b = 0  
   elif ITYPE == 4:  
     if abs(wavelength-656.0) < 1.1 or abs(wavelength-486.0) < 1.1 or abs(wavelength-433.0) < 1.1 or abs(wavelength-410.0) < 1.1 or abs(wavelength-396.0) < 1.1:  
       r = 0  
       g = 0  
       b = 0  
   return (r, g, b)  
 minvalue = maxvalue = head_FOV_map[0][0]  
 for i in range(head_FOV_height):  
   for j in range(head_FOV_width):  
     if head_FOV_map[i][j] > maxvalue:  
       maxvalue = head_FOV_map[i][j]  
     elif head_FOV_map[i][j] < minvalue:  
       minvalue = head_FOV_map[i][j]  
 print minvalue  
 print maxvalue  
 print "profile"  
 for i in range(head_FOV_height):  
   print head_FOV_map[i][head_FOV_width / 2]  
 img = Image.new('RGB', (head_FOV_width, head_FOV_height), "black")  
 #img = Image.new('L', (head_FOV_width, head_FOV_height))  
 pixels = img.load()  
 for i in range(img.size[1]):  
   for j in range(img.size[0]):  
     #pixels[j, i] = wave2rgb(head_FOV_map[i][j] / 8000.0 * 400.0 + 380.0)  
     pixels[j, i] = palette[int(round((head_FOV_map[i][j] - minvalue) / (maxvalue - minvalue) * (len(palette) - 1)))]  
     #pixels[j, i] = int(round((head_FOV_map[i][j] - minvalue) / (maxvalue - minvalue) * 255.0))  
 img.show()  

결과물


 FOV_simulation_assign_60mm_30mm



 FOV_simulation_assign_90mm_45mm


 시각적 변화를 위한 몇 가지 프로파일들


Yellow gradient

 palette=((0, 0, 0), (53, 2, 0), (53, 2, 0), (53, 3, 0), (53, 3, 0), (53, 4, 0), (52, 4, 0), (52, 5, 0), (52, 6, 0), (52, 6, 0), (51, 7, 0), (51, 8, 0), (51, 9, 0), (51, 9, 0), (51, 10, 0), (51, 10, 0), (51, 11, 0), (51, 11, 0), (51, 12, 0), (51, 12, 0), (51, 13, 0), (50, 14, 0), (50, 14, 0), (50, 15, 0), (50, 15, 0), (50, 16, 0), (50, 16, 0), (50, 17, 0), (50, 17, 0), (50, 18, 0), (50, 18, 0), (50, 19, 0), (50, 20, 0), (50, 20, 0), (50, 21, 0), (51, 21, 0), (51, 22, 0), (51, 22, 0), (51, 23, 0), (51, 24, 0), (51, 25, 0), (51, 25, 0), (52, 26, 0), (52, 27, 0), (52, 27, 0), (52, 28, 0), (52, 28, 0), (52, 29, 0), (52, 29, 0), (52, 30, 0), (53, 30, 0), (53, 31, 0), (53, 32, 0), (54, 32, 0), (54, 33, 0), (54, 33, 0), (54, 34, 0), (55, 34, 0), (55, 35, 0), (55, 35, 0), (55, 36, 0), (56, 36, 0), (56, 37, 0), (56, 38, 0), (57, 39, 0), (57, 39, 0), (57, 40, 0), (58, 41, 0), (58, 41, 0), (59, 42, 0), (59, 42, 0), (59, 43, 0), (60, 43, 0), (60, 44, 0), (61, 45, 0), (61, 45, 0), (62, 46, 0), (62, 46, 0), (63, 47, 0), (63, 47, 0), (64, 48, 0), (64, 48, 0), (64, 49, 0), (65, 50, 0), (65, 50, 0), (66, 51, 0), (66, 51, 0), (67, 52, 0), (67, 52, 0), (68, 53, 0), (69, 53, 0), (70, 54, 0), (71, 55, 0), (72, 56, 0), (72, 56, 0), (73, 57, 0), (74, 58, 0), (74, 58, 0), (75, 59, 0), (75, 59, 0), (76, 60, 0), (77, 60, 0), (78, 61, 0), (78, 61, 0), (79, 62, 0), (80, 63, 0), (80, 63, 0), (81, 64, 0), (82, 64, 0), (83, 65, 0), (84, 65, 0), (84, 66, 0), (85, 66, 0), (86, 67, 0), (87, 68, 0), (88, 68, 0), (88, 69, 0), (89, 69, 0), (90, 70, 0), (92, 71, 0), (93, 72, 0), (94, 72, 0), (94, 73, 0), (95, 73, 0), (96, 74, 0), (97, 75, 0), (98, 75, 0), (98, 76, 0), (99, 76, 0), (101, 77, 0), (102, 77, 0), (103, 78, 0), (104, 78, 0), (104, 79, 0), (105, 79, 0), (106, 80, 0), (107, 81, 0), (108, 81, 0), (109, 82, 0), (110, 82, 0), (111, 83, 0), (112, 83, 0), (114, 84, 0), (115, 84, 0), (115, 85, 0), (116, 86, 0), (117, 86, 0), (118, 87, 0), (119, 88, 0), (120, 89, 0), (122, 89, 0), (123, 90, 0), (124, 90, 0), (125, 91, 0), (126, 91, 0), (127, 92, 0), (128, 93, 0), (129, 93, 0), (130, 94, 0), (131, 94, 0), (133, 95, 0), (134, 95, 0), (135, 96, 0), (136, 96, 0), (137, 97, 0), (138, 98, 0), (139, 98, 0), (140, 99, 0), (141, 99, 0), (142, 100, 0), (143, 100, 0), (145, 101, 0), (146, 102, 0), (147, 102, 0), (148, 103, 0), (149, 104, 0), (150, 105, 0), (151, 105, 0), (152, 106, 0), (153, 106, 0), (155, 107, 0), (156, 107, 0), (158, 108, 0), (159, 108, 0), (160, 109, 0), (161, 109, 0), (162, 110, 0), (163, 111, 0), (164, 111, 0), (164, 112, 0), (165, 112, 0), (167, 113, 0), (168, 113, 0), (169, 114, 0), (170, 114, 0), (171, 115, 0), (173, 116, 0), (174, 116, 0), (175, 117, 0), (176, 117, 0), (177, 118, 0), (178, 118, 0), (179, 119, 0), (180, 120, 0), (181, 121, 0), (182, 121, 0), (183, 122, 0), (184, 123, 0), (185, 123, 0), (186, 124, 0), (187, 124, 0), (188, 125, 0), (190, 125, 0), (191, 126, 0), (192, 126, 0), (193, 127, 0), (194, 127, 0), (195, 128, 0), (195, 129, 0), (196, 129, 0), (197, 130, 0), (198, 130, 0), (200, 131, 0), (201, 131, 0), (202, 132, 0), (203, 132, 0), (204, 133, 0), (205, 134, 0), (206, 135, 0), (206, 135, 0), (207, 136, 0), (208, 137, 0), (209, 137, 0), (210, 138, 0), (211, 138, 0), (212, 139, 0), (213, 139, 0), (214, 140, 0), (215, 141, 0), (216, 141, 0), (216, 142, 0), (217, 142, 0), (218, 143, 0), (219, 143, 0), (220, 144, 0), (221, 144, 0), (221, 145, 0), (222, 145, 0), (223, 146, 0), (224, 147, 0), (224, 147, 0), (225, 148, 0), (225, 148, 0), (226, 149, 0), (227, 149, 0), (228, 150, 0), (229, 151, 0), (229, 151, 0), (230, 152, 0), (231, 153, 0), (232, 154, 0), (232, 154, 0), (233, 155, 0), (233, 155, 0), (234, 156, 0), (235, 156, 0), (236, 157, 0), (236, 157, 0), (237, 158, 0), (238, 159, 0), (238, 159, 0), (239, 160, 0), (239, 160, 0), (240, 161, 0), (240, 161, 0), (240, 162, 0), (241, 162, 0), (241, 163, 0), (241, 163, 0), (242, 164, 0), (243, 165, 0), (243, 165, 0), (244, 166, 0), (244, 167, 0), (245, 168, 0), (245, 168, 0), (246, 169, 0), (246, 169, 0), (247, 170, 0), (247, 171, 0), (248, 171, 0), (248, 172, 0), (248, 172, 0), (248, 173, 0), (249, 173, 0), (249, 174, 0), (249, 174, 0), (249, 175, 0), (250, 175, 0), (250, 176, 0), (250, 177, 0), (251, 177, 0), (251, 178, 0), (251, 178, 0), (251, 179, 0), (252, 179, 0), (252, 180, 0), (252, 180, 0), (252, 181, 0), (252, 181, 0), (252, 182, 0), (252, 183, 0), (253, 184, 0), (253, 184, 0), (253, 185, 0), (253, 186, 0), (253, 186, 0), (253, 187, 0), (253, 187, 0), (253, 188, 0), (254, 189, 0), (254, 189, 0), (254, 190, 0), (254, 190, 0), (254, 191, 0), (254, 191, 0), (254, 192, 0), (254, 192, 0), (254, 193, 0), (254, 193, 0), (254, 194, 0), (254, 195, 0), (254, 195, 0), (254, 196, 0), (254, 196, 0), (254, 197, 0), (254, 197, 0), (254, 198, 0), (253, 199, 0), (253, 200, 0), (253, 200, 0), (253, 201, 0), (253, 202, 0), (253, 202, 0), (253, 203, 0), (252, 203, 0), (252, 204, 0), (252, 204, 0), (252, 205, 0), (252, 205, 0), (252, 206, 0), (252, 207, 0), (251, 207, 0), (251, 208, 0), (251, 208, 0), (251, 209, 0), (250, 209, 0), (250, 210, 0), (250, 210, 0), (250, 211, 0), (250, 211, 0), (250, 212, 0), (250, 213, 0), (249, 213, 0), (249, 214, 0), (249, 214, 0), (249, 215, 0), (248, 216, 0), (248, 217, 0), (248, 217, 0), (248, 218, 0), (247, 218, 0), (247, 219, 0), (247, 220, 0), (246, 220, 0), (246, 221, 0), (246, 221, 0), (246, 222, 0), (245, 222, 0), (245, 223, 0), (245, 223, 0), (245, 224, 0), (244, 225, 0), (244, 225, 0), (244, 226, 0), (243, 226, 0), (243, 227, 0), (243, 227, 0), (242, 228, 0), (242, 228, 0), (241, 229, 0), (241, 230, 0), (241, 230, 0), (240, 231, 0), (240, 232, 0), (240, 233, 0), (239, 233, 0), (239, 234, 0), (239, 234, 0), (239, 235, 0), (238, 235, 0), (238, 236, 0), (238, 236, 0), (237, 237, 0), (237, 238, 0), (237, 238, 0), (237, 239, 0), (236, 239, 0), (236, 240, 0), (236, 240, 0), (235, 241, 0), (235, 241, 0), (234, 242, 0), (234, 243, 0), (233, 243, 0), (233, 244, 0), (233, 244, 0), (233, 245, 0), (232, 245, 0), (232, 246, 0), (232, 247, 0), (232, 247, 0), (231, 248, 0), (231, 249, 0), (231, 250, 0), (230, 250, 0), (230, 251, 0), (230, 251, 0), (230, 252, 0), (229, 252, 0), (229, 253, 0), (229, 253, 0), (229, 254, 0), (229, 254, 0)) 


Glowbow gradient


 palette =((0, 0, 0), (2, 0, 0), (4, 1, 1), (6, 1, 1), (8, 1, 1), (10, 1, 2), (12, 2, 2), (13, 2, 3), (15, 2, 3), (17, 2, 3), (19, 2, 4), (21, 2, 4), (23, 2, 4), (24, 3, 5), (26, 3, 5), (28, 3, 5), (30, 3, 6), (32, 4, 6), (34, 4, 7), (35, 4, 7), (37, 4, 7), (39, 5, 8), (41, 5, 8), (43, 5, 8), (45, 5, 9), (47, 5, 9), (49, 5, 9), (51, 5, 9), (53, 6, 10), (55, 6, 10), (57, 6, 10), (59, 7, 11), (60, 7, 12), (62, 7, 12), (64, 7, 12), (66, 8, 13), (67, 8, 13), (69, 8, 13), (71, 8, 13), (73, 8, 14), (75, 8, 14), (77, 8, 14), (79, 9, 15), (81, 9, 16), (83, 9, 16), (85, 9, 16), (88, 10, 17), (91, 10, 17), (94, 10, 17), (97, 11, 18), (100, 11, 19), (103, 12, 20), (105, 12, 20), (106, 12, 21), (108, 12, 21), (110, 12, 21), (112, 12, 21), (113, 13, 22), (115, 13, 22), (117, 13, 22), (119, 13, 22), (121, 14, 23), (123, 14, 23), (125, 14, 24), (127, 15, 24), (129, 15, 25), (131, 15, 25), (133, 15, 25), (135, 15, 26), (136, 15, 26), (138, 15, 26), (140, 15, 26), (142, 16, 27), (144, 16, 27), (146, 16, 28), (147, 17, 28), (149, 17, 29), (151, 17, 29), (153, 17, 29), (155, 18, 30), (157, 18, 30), (159, 18, 30), (160, 18, 30), (162, 18, 31), (164, 18, 31), (166, 18, 32), (168, 19, 32), (170, 19, 33), (172, 19, 33), (174, 19, 33), (176, 20, 34), (178, 20, 34), (180, 20, 34), (182, 21, 35), (183, 21, 35), (185, 21, 35), (187, 21, 35), (189, 21, 36), (190, 21, 36), (192, 21, 36), (194, 21, 37), (196, 22, 37), (198, 22, 38), (200, 22, 38), (202, 23, 39), (204, 23, 39), (205, 23, 39), (206, 24, 39), (206, 24, 38), (207, 25, 38), (207, 26, 38), (207, 26, 37), (208, 27, 37), (208, 28, 36), (209, 29, 36), (209, 29, 35), (210, 30, 35), (210, 30, 35), (211, 31, 35), (211, 31, 34), (212, 32, 34), (212, 33, 34), (212, 33, 33), (213, 34, 33), (213, 35, 32), (214, 36, 32), (214, 36, 31), (215, 37, 31), (215, 37, 31), (216, 38, 31), (216, 38, 30), (217, 39, 30), (217, 39, 30), (217, 40, 30), (218, 40, 29), (218, 41, 29), (219, 42, 28), (219, 43, 28), (220, 44, 27), (220, 44, 27), (221, 45, 27), (221, 45, 26), (222, 46, 26), (222, 46, 26), (222, 47, 26), (223, 48, 25), (223, 48, 25), (224, 49, 24), (224, 50, 24), (225, 51, 23), (225, 51, 23), (226, 52, 23), (226, 52, 22), (227, 53, 22), (227, 53, 22), (228, 54, 21), (228, 55, 21), (228, 55, 21), (229, 56, 21), (229, 57, 20), (230, 58, 20), (230, 58, 20), (231, 59, 19), (231, 59, 19), (232, 60, 18), (232, 61, 18), (233, 61, 17), (233, 62, 17), (233, 62, 17), (234, 63, 17), (234, 63, 16), (235, 64, 16), (235, 65, 16), (236, 65, 15), (236, 66, 15), (237, 67, 14), (237, 68, 14), (238, 68, 13), (238, 69, 13), (238, 69, 13), (239, 70, 13), (239, 70, 12), (240, 71, 12), (240, 72, 12), (241, 72, 11), (241, 73, 11), (242, 74, 10), (242, 75, 10), (243, 75, 9), (243, 76, 9), (243, 76, 9), (244, 77, 9), (244, 77, 8), (245, 78, 8), (245, 78, 8), (246, 79, 8), (247, 80, 7), (247, 80, 7), (247, 81, 6), (248, 82, 6), (248, 83, 5), (248, 83, 5), (249, 84, 5), (249, 84, 4), (250, 85, 4), (250, 85, 4), (251, 86, 4), (252, 87, 3), (252, 87, 3), (252, 88, 2), (253, 89, 2), (253, 90, 1), (253, 90, 1), (254, 91, 1), (254, 91, 0), (255, 92, 0), (255, 93, 0), (255, 94, 0), (255, 95, 0), (255, 96, 0), (255, 97, 0), (255, 98, 0), (255, 100, 0), (255, 101, 0), (255, 102, 0), (255, 103, 0), (255, 105, 0), (255, 106, 0), (255, 107, 0), (255, 108, 0), (255, 109, 0), (255, 110, 0), (255, 111, 0), (255, 113, 0), (255, 114, 0), (255, 115, 0), (255, 116, 0), (255, 117, 0), (255, 118, 0), (255, 119, 0), (255, 120, 0), (255, 121, 0), (255, 123, 0), (255, 124, 0), (255, 126, 0), (255, 127, 0), (255, 128, 0), (255, 129, 0), (255, 130, 0), (255, 131, 0), (255, 132, 0), (255, 133, 0), (255, 134, 0), (255, 136, 0), (255, 137, 0), (255, 138, 0), (255, 139, 0), (255, 140, 0), (255, 141, 0), (255, 142, 0), (255, 143, 0), (255, 145, 0), (255, 146, 0), (255, 147, 0), (255, 149, 0), (255, 150, 0), (255, 151, 0), (255, 152, 0), (255, 153, 0), (255, 154, 0), (255, 155, 0), (255, 156, 0), (255, 157, 0), (255, 158, 0), (255, 160, 0), (255, 161, 0), (255, 162, 0), (255, 163, 0), (255, 164, 0), (255, 166, 0), (255, 167, 0), (255, 168, 0), (255, 169, 0), (255, 170, 0), (255, 172, 0), (255, 173, 0), (255, 174, 0), (255, 175, 0), (255, 176, 0), (255, 177, 0), (255, 178, 0), (255, 179, 0), (255, 180, 0), (255, 181, 0), (255, 182, 0), (255, 184, 0), (255, 185, 0), (255, 186, 0), (255, 188, 0), (255, 189, 0), (255, 190, 0), (255, 191, 0), (255, 192, 0), (255, 193, 0), (255, 194, 0), (255, 196, 0), (255, 197, 0), (255, 198, 0), (255, 199, 0), (255, 200, 0), (255, 201, 0), (255, 202, 0), (255, 203, 0), (255, 204, 0), (255, 206, 0), (255, 207, 0), (255, 208, 0), (255, 210, 0), (255, 211, 0), (255, 212, 0), (255, 213, 0), (255, 214, 0), (255, 215, 0), (255, 216, 0), (255, 217, 0), (255, 218, 1), (255, 218, 3), (255, 219, 5), (255, 219, 8), (255, 219, 10), (255, 219, 12), (255, 220, 15), (255, 220, 17), (255, 221, 20), (255, 221, 22), (255, 222, 24), (255, 222, 26), (255, 222, 29), (255, 223, 31), (255, 223, 34), (255, 223, 36), (255, 224, 38), (255, 224, 40), (255, 224, 43), (255, 224, 45), (255, 225, 47), (255, 225, 50), (255, 225, 52), (255, 226, 55), (255, 226, 57), (255, 227, 60), (255, 227, 62), (255, 228, 64), (255, 228, 66), (255, 228, 69), (255, 228, 71), (255, 229, 73), (255, 229, 75), (255, 229, 78), (255, 229, 80), (255, 230, 82), (255, 230, 85), (255, 231, 87), (255, 231, 90), (255, 232, 92), (255, 232, 95), (255, 232, 97), (255, 233, 99), (255, 233, 101), (255, 233, 104), (255, 233, 106), (255, 234, 109), (255, 234, 111), (255, 234, 113), (255, 235, 115), (255, 235, 118), (255, 235, 120), (255, 236, 122), (255, 236, 125), (255, 237, 127), (255, 237, 130), (255, 237, 132), (255, 238, 134), (255, 238, 136), (255, 238, 138), (255, 239, 141), (255, 239, 143), (255, 239, 145), (255, 239, 148), (255, 240, 150), (255, 240, 153), (255, 240, 155), (255, 240, 157), (255, 241, 159), (255, 241, 161), (255, 242, 164), (255, 242, 166), (255, 243, 169), (255, 243, 171), (255, 243, 174), (255, 244, 176), (255, 244, 179), (255, 244, 181), (255, 245, 183), (255, 245, 185), (255, 245, 187), (255, 245, 190), (255, 246, 192), (255, 246, 194), (255, 246, 196), (255, 247, 199), (255, 247, 201), (255, 248, 204), (255, 248, 206), (255, 249, 209), (255, 249, 211), (255, 249, 214), (255, 249, 216), (255, 250, 218), (255, 250, 220), (255, 250, 223), (255, 250, 225), (255, 251, 228), (255, 251, 230), (255, 252, 232), (255, 252, 234), (255, 253, 237), (255, 253, 239), (255, 253, 241), (255, 254, 244), (255, 254, 246), (255, 254, 249), (255, 254, 251), (255, 255, 253)) 


gray gradient


 palette=((1, 1, 1), (1, 1, 1), (2, 2, 2), (2, 2, 2), (3, 3, 3), (3, 3, 3), (4, 4, 4), (4, 4, 4), (5, 5, 5), (5, 5, 5), (6, 6, 6), (7, 7, 7), (8, 8, 8), (9, 9, 9), (9, 9, 9), (10, 10, 10), (10, 10, 10), (11, 11, 11), (11, 11, 11), (12, 12, 12), (13, 13, 13), (13, 13, 13), (14, 14, 14), (14, 14, 14), (15, 15, 15), (15, 15, 15), (16, 16, 16), (16, 16, 16), (17, 17, 17), (17, 17, 17), (18, 18, 18), (19, 19, 19), (19, 19, 19), (20, 20, 20), (21, 21, 21), (22, 22, 22), (22, 22, 22), (23, 23, 23), (23, 23, 23), (24, 24, 24), (24, 24, 24), (25, 25, 25), (26, 26, 26), (26, 26, 26), (27, 27, 27), (27, 27, 27), (28, 28, 28), (28, 28, 28), (29, 29, 29), (29, 29, 29), (30, 30, 30), (31, 31, 31), (31, 31, 31), (32, 32, 32), (32, 32, 32), (33, 33, 33), (33, 33, 33), (34, 34, 34), (35, 35, 35), (35, 35, 35), (36, 36, 36), (37, 37, 37), (38, 38, 38), (38, 38, 38), (39, 39, 39), (39, 39, 39), (40, 40, 40), (40, 40, 40), (41, 41, 41), (41, 41, 41), (42, 42, 42), (42, 42, 42), (43, 43, 43), (44, 44, 44), (44, 44, 44), (45, 45, 45), (45, 45, 45), (46, 46, 46), (46, 46, 46), (47, 47, 47), (47, 47, 47), (48, 48, 48), (49, 49, 49), (49, 49, 49), (50, 50, 50), (51, 51, 51), (52, 52, 52), (52, 52, 52), (53, 53, 53), (53, 53, 53), (54, 54, 54), (54, 54, 54), (55, 55, 55), (56, 56, 56), (56, 56, 56), (57, 57, 57), (57, 57, 57), (58, 58, 58), (58, 58, 58), (59, 59, 59), (59, 59, 59), (60, 60, 60), (60, 60, 60), (61, 61, 61), (62, 62, 62), (62, 62, 62), (63, 63, 63), (64, 64, 64), (65, 65, 65), (65, 65, 65), (66, 66, 66), (66, 66, 66), (67, 67, 67), (68, 68, 68), (68, 68, 68), (69, 69, 69), (69, 69, 69), (70, 70, 70), (70, 70, 70), (71, 71, 71), (71, 71, 71), (72, 72, 72), (72, 72, 72), (73, 73, 73), (74, 74, 74), (74, 74, 74), (75, 75, 75), (75, 75, 75), (76, 76, 76), (76, 76, 76), (77, 77, 77), (78, 78, 78), (78, 78, 78), (79, 79, 79), (80, 80, 80), (81, 81, 81), (81, 81, 81), (82, 82, 82), (82, 82, 82), (83, 83, 83), (83, 83, 83), (84, 84, 84), (84, 84, 84), (85, 85, 85), (86, 86, 86), (86, 86, 86), (87, 87, 87), (87, 87, 87), (88, 88, 88), (88, 88, 88), (89, 89, 89), (89, 89, 89), (90, 90, 90), (91, 91, 91), (92, 92, 92), (92, 92, 92), (93, 93, 93), (94, 94, 94), (94, 94, 94), (95, 95, 95), (95, 95, 95), (96, 96, 96), (96, 96, 96), (97, 97, 97), (98, 98, 98), (98, 98, 98), (99, 99, 99), (99, 99, 99), (100, 100, 100), (100, 100, 100), (101, 101, 101), (101, 101, 101), (102, 102, 102), (102, 102, 102), (103, 103, 103), (104, 104, 104), (104, 104, 104), (105, 105, 105), (105, 105, 105), (106, 106, 106), (107, 107, 107), (108, 108, 108), (108, 108, 108), (109, 109, 109), (109, 109, 109), (110, 110, 110), (111, 111, 111), (111, 111, 111), (112, 112, 112), (112, 112, 112), (113, 113, 113), (113, 113, 113), (114, 114, 114), (114, 114, 114), (115, 115, 115), (116, 116, 116), (116, 116, 116), (117, 117, 117), (117, 117, 117), (118, 118, 118), (118, 118, 118), (119, 119, 119), (119, 119, 119), (120, 120, 120), (121, 121, 121), (121, 121, 121), (122, 122, 122), (123, 123, 123), (124, 124, 124), (124, 124, 124), (125, 125, 125), (125, 125, 125), (126, 126, 126), (126, 126, 126), (127, 127, 127), (127, 127, 127), (128, 128, 128), (129, 129, 129), (129, 129, 129), (130, 130, 130), (130, 130, 130), (131, 131, 131), (131, 131, 131), (132, 132, 132), (132, 132, 132), (133, 133, 133), (134, 134, 134), (135, 135, 135), (135, 135, 135), (136, 136, 136), (137, 137, 137), (137, 137, 137), (138, 138, 138), (138, 138, 138), (139, 139, 139), (139, 139, 139), (140, 140, 140), (141, 141, 141), (141, 141, 141), (142, 142, 142), (142, 142, 142), (143, 143, 143), (143, 143, 143), (144, 144, 144), (144, 144, 144), (145, 145, 145), (145, 145, 145), (146, 146, 146), (147, 147, 147), (147, 147, 147), (148, 148, 148), (148, 148, 148), (149, 149, 149), (150, 150, 150), (151, 151, 151), (151, 151, 151), (152, 152, 152), (153, 153, 153), (153, 153, 153), (154, 154, 154), (154, 154, 154), (155, 155, 155), (155, 155, 155), (156, 156, 156), (156, 156, 156), (157, 157, 157), (157, 157, 157), (158, 158, 158), (159, 159, 159), (159, 159, 159), (160, 160, 160), (160, 160, 160), (161, 161, 161), (161, 161, 161), (162, 162, 162), (162, 162, 162), (163, 163, 163), (164, 164, 164), (165, 165, 165), (165, 165, 165), (166, 166, 166), (167, 167, 167), (167, 167, 167), (168, 168, 168), (168, 168, 168), (169, 169, 169), (169, 169, 169), (170, 170, 170), (171, 171, 171), (171, 171, 171), (172, 172, 172), (172, 172, 172), (173, 173, 173), (173, 173, 173), (174, 174, 174), (174, 174, 174), (175, 175, 175), (175, 175, 175), (176, 176, 176), (177, 177, 177), (178, 178, 178), (178, 178, 178), (179, 179, 179), (180, 180, 180), (180, 180, 180), (181, 181, 181), (181, 181, 181), (182, 182, 182), (182, 182, 182), (183, 183, 183), (184, 184, 184), (184, 184, 184), (185, 185, 185), (185, 185, 185), (186, 186, 186), (186, 186, 186), (187, 187, 187), (187, 187, 187), (188, 188, 188), (189, 189, 189), (189, 189, 189), (190, 190, 190), (190, 190, 190), (191, 191, 191), (191, 191, 191), (192, 192, 192), (193, 193, 193), (194, 194, 194), (194, 194, 194), (195, 195, 195), (196, 196, 196), (196, 196, 196), (197, 197, 197), (197, 197, 197), (198, 198, 198), (198, 198, 198), (199, 199, 199), (199, 199, 199), (200, 200, 200), (200, 200, 200), (201, 201, 201), (202, 202, 202), (202, 202, 202), (203, 203, 203), (203, 203, 203), (204, 204, 204), (204, 204, 204), (205, 205, 205), (206, 206, 206), (207, 207, 207), (208, 208, 208), (208, 208, 208), (209, 209, 209), (209, 209, 209), (210, 210, 210), (210, 210, 210), (211, 211, 211), (211, 211, 211), (212, 212, 212), (212, 212, 212), (213, 213, 213), (214, 214, 214), (214, 214, 214), (215, 215, 215), (215, 215, 215), (216, 216, 216), (216, 216, 216), (217, 217, 217), (217, 217, 217), (218, 218, 218), (218, 218, 218), (219, 219, 219), (220, 220, 220), (221, 221, 221), (221, 221, 221), (222, 222, 222), (223, 223, 223), (223, 223, 223), (224, 224, 224), (224, 224, 224), (225, 225, 225), (226, 226, 226), (226, 226, 226), (227, 227, 227), (227, 227, 227), (228, 228, 228), (228, 228, 228), (229, 229, 229), (229, 229, 229), (230, 230, 230), (230, 230, 230), (231, 231, 231), (232, 232, 232), (232, 232, 232), (233, 233, 233), (233, 233, 233), (234, 234, 234), (234, 234, 234), (235, 235, 235), (236, 236, 236), (237, 237, 237), (237, 237, 237), (238, 238, 238), (239, 239, 239), (239, 239, 239), (240, 240, 240), (240, 240, 240), (241, 241, 241), (241, 241, 241), (242, 242, 242), (242, 242, 242), (243, 243, 243), (244, 244, 244), (244, 244, 244), (245, 245, 245), (245, 245, 245), (246, 246, 246), (246, 246, 246), (247, 247, 247), (248, 248, 248), (248, 248, 248), (249, 249, 249), (250, 250, 250), (251, 251, 251), (251, 251, 251), (252, 252, 252), (252, 252, 252), (253, 253, 253), (253, 253, 253), (254, 254, 254), (254, 254, 254), (254, 254, 254), (255, 255, 255)) 


Iron gradient




 palette=((0, 0, 0), (0, 0, 10), (0, 0, 20), (0, 0, 30), (0, 0, 37), (0, 0, 42), (0, 0, 46), (0, 0, 50), (0, 0, 54), (0, 0, 58), (0, 0, 62), (0, 0, 66), (0, 0, 70), (0, 0, 74), (0, 0, 79), (0, 0, 82), (1, 0, 85), (1, 0, 87), (2, 0, 89), (2, 0, 92), (3, 0, 94), (4, 0, 97), (4, 0, 99), (5, 0, 101), (6, 0, 103), (7, 0, 105), (8, 0, 107), (9, 0, 110), (10, 0, 112), (11, 0, 115), (12, 0, 116), (13, 0, 117), (13, 0, 118), (14, 0, 119), (16, 0, 120), (18, 0, 121), (19, 0, 123), (21, 0, 124), (23, 0, 125), (25, 0, 126), (27, 0, 128), (28, 0, 129), (30, 0, 131), (32, 0, 132), (34, 0, 133), (36, 0, 134), (38, 0, 135), (40, 0, 137), (42, 0, 137), (44, 0, 138), (46, 0, 139), (48, 0, 140), (50, 0, 141), (52, 0, 142), (54, 0, 142), (56, 0, 143), (57, 0, 144), (59, 0, 145), (60, 0, 146), (62, 0, 147), (63, 0, 147), (65, 0, 148), (66, 0, 149), (68, 0, 149), (69, 0, 150), (71, 0, 150), (73, 0, 150), (74, 0, 150), (76, 0, 151), (78, 0, 151), (79, 0, 151), (81, 0, 151), (82, 0, 152), (84, 0, 152), (86, 0, 152), (88, 0, 153), (90, 0, 153), (92, 0, 153), (93, 0, 154), (95, 0, 154), (97, 0, 155), (99, 0, 155), (100, 0, 155), (102, 0, 155), (104, 0, 155), (106, 0, 155), (108, 0, 156), (109, 0, 156), (111, 0, 156), (112, 0, 156), (113, 0, 157), (115, 0, 157), (117, 0, 157), (119, 0, 157), (120, 0, 157), (122, 0, 157), (124, 0, 157), (126, 0, 157), (127, 0, 157), (129, 0, 157), (131, 0, 157), (132, 0, 157), (134, 0, 157), (135, 0, 157), (137, 0, 157), (138, 0, 157), (139, 0, 157), (141, 0, 157), (143, 0, 156), (145, 0, 156), (147, 0, 156), (149, 0, 156), (150, 0, 155), (152, 0, 155), (153, 0, 155), (155, 0, 155), (156, 0, 155), (157, 0, 155), (159, 0, 155), (160, 0, 155), (162, 0, 155), (163, 0, 155), (164, 0, 155), (166, 0, 154), (167, 0, 154), (168, 0, 154), (169, 0, 153), (170, 0, 153), (171, 0, 153), (173, 0, 153), (174, 1, 152), (175, 1, 152), (176, 1, 152), (176, 1, 152), (177, 1, 151), (178, 1, 151), (179, 1, 150), (180, 2, 150), (181, 2, 149), (182, 2, 149), (183, 3, 149), (184, 3, 149), (185, 4, 149), (186, 4, 149), (186, 4, 148), (187, 5, 147), (188, 5, 147), (189, 5, 147), (190, 6, 146), (191, 6, 146), (191, 6, 146), (192, 7, 145), (192, 7, 145), (193, 8, 144), (193, 9, 144), (194, 10, 143), (195, 10, 142), (195, 11, 142), (196, 12, 141), (197, 12, 140), (198, 13, 139), (198, 14, 138), (199, 15, 137), (200, 16, 136), (201, 17, 135), (202, 18, 134), (202, 19, 133), (203, 19, 133), (203, 20, 132), (204, 21, 130), (205, 22, 129), (206, 23, 128), (206, 24, 126), (207, 24, 124), (207, 25, 123), (208, 26, 121), (209, 27, 120), (209, 28, 118), (210, 28, 117), (210, 29, 116), (211, 30, 114), (211, 32, 113), (212, 33, 111), (212, 34, 110), (213, 35, 107), (213, 36, 105), (214, 37, 103), (215, 38, 101), (216, 39, 100), (216, 40, 98), (217, 42, 96), (218, 43, 94), (218, 44, 92), (219, 46, 90), (219, 47, 87), (220, 47, 84), (221, 48, 81), (221, 49, 78), (222, 50, 74), (222, 51, 71), (223, 52, 68), (223, 53, 65), (223, 54, 61), (224, 55, 58), (224, 56, 55), (224, 57, 51), (225, 58, 48), (226, 59, 45), (226, 60, 42), (227, 61, 38), (227, 62, 35), (228, 63, 32), (228, 65, 29), (228, 66, 28), (229, 67, 27), (229, 68, 25), (229, 69, 24), (230, 70, 22), (231, 71, 21), (231, 72, 20), (231, 73, 19), (232, 74, 18), (232, 76, 16), (232, 76, 15), (233, 77, 14), (233, 77, 13), (234, 78, 12), (234, 79, 12), (235, 80, 11), (235, 81, 10), (235, 82, 10), (235, 83, 9), (236, 84, 9), (236, 86, 8), (236, 87, 8), (236, 88, 8), (237, 89, 7), (237, 90, 7), (237, 91, 6), (238, 92, 6), (238, 92, 5), (238, 93, 5), (238, 94, 5), (239, 95, 4), (239, 96, 4), (239, 97, 4), (239, 98, 4), (240, 99, 3), (240, 100, 3), (240, 101, 3), (241, 102, 3), (241, 102, 3), (241, 103, 3), (241, 104, 3), (241, 105, 2), (241, 106, 2), (241, 107, 2), (241, 107, 2), (242, 108, 1), (242, 109, 1), (242, 110, 1), (243, 111, 1), (243, 112, 1), (243, 113, 1), (243, 114, 1), (244, 115, 0), (244, 116, 0), (244, 117, 0), (244, 118, 0), (244, 119, 0), (244, 120, 0), (244, 122, 0), (245, 123, 0), (245, 124, 0), (245, 126, 0), (245, 127, 0), (246, 128, 0), (246, 129, 0), (246, 130, 0), (247, 131, 0), (247, 132, 0), (247, 133, 0), (247, 134, 0), (248, 135, 0), (248, 136, 0), (248, 136, 0), (248, 137, 0), (248, 138, 0), (248, 139, 0), (248, 140, 0), (249, 141, 0), (249, 141, 0), (249, 142, 0), (249, 143, 0), (249, 144, 0), (249, 145, 0), (249, 146, 0), (249, 147, 0), (250, 148, 0), (250, 149, 0), (250, 150, 0), (251, 152, 0), (251, 153, 0), (251, 154, 0), (251, 156, 0), (252, 157, 0), (252, 159, 0), (252, 160, 0), (252, 161, 0), (253, 162, 0), (253, 163, 0), (253, 164, 0), (253, 166, 0), (253, 167, 0), (253, 168, 0), (253, 170, 0), (253, 171, 0), (253, 172, 0), (253, 173, 0), (253, 174, 0), (254, 175, 0), (254, 176, 0), (254, 177, 0), (254, 178, 0), (254, 179, 0), (254, 180, 0), (254, 181, 0), (254, 182, 0), (254, 184, 0), (254, 185, 0), (254, 185, 0), (254, 186, 0), (254, 187, 0), (254, 188, 0), (254, 189, 0), (254, 190, 0), (254, 192, 0), (254, 193, 0), (254, 194, 0), (254, 195, 0), (254, 196, 0), (254, 197, 0), (254, 198, 0), (254, 199, 0), (254, 200, 0), (254, 201, 1), (254, 202, 1), (254, 202, 1), (254, 203, 1), (254, 204, 2), (254, 205, 2), (254, 206, 3), (254, 207, 4), (254, 207, 4), (254, 208, 5), (254, 209, 6), (254, 211, 8), (254, 212, 9), (254, 213, 10), (254, 214, 10), (254, 215, 11), (254, 216, 12), (254, 217, 13), (255, 218, 14), (255, 218, 14), (255, 219, 16), (255, 220, 18), (255, 220, 20), (255, 221, 22), (255, 222, 25), (255, 222, 27), (255, 223, 30), (255, 224, 32), (255, 225, 34), (255, 226, 36), (255, 226, 38), (255, 227, 40), (255, 228, 43), (255, 228, 46), (255, 229, 49), (255, 230, 53), (255, 230, 56), (255, 231, 60), (255, 232, 63), (255, 233, 67), (255, 234, 70), (255, 235, 73), (255, 235, 77), (255, 236, 80), (255, 237, 84), (255, 238, 87), (255, 238, 91), (255, 238, 95), (255, 239, 99), (255, 239, 103), (255, 240, 106), (255, 240, 110), (255, 241, 114), (255, 241, 119), (255, 241, 123), (255, 242, 128), (255, 242, 133), (255, 242, 138), (255, 243, 142), (255, 244, 146), (255, 244, 150), (255, 244, 154), (255, 245, 158), (255, 245, 162), (255, 245, 166), (255, 246, 170), (255, 246, 175), (255, 247, 179), (255, 247, 182), (255, 248, 186), (255, 248, 189), (255, 248, 193), (255, 248, 196), (255, 249, 199), (255, 249, 202), (255, 249, 205), (255, 250, 209), (255, 250, 212), (255, 251, 216), (255, 252, 219), (255, 252, 223), (255, 253, 226), (255, 253, 229), (255, 253, 232), (255, 254, 235), (255, 254, 238), (255, 254, 241), (255, 254, 244), (255, 255, 246)) 


Rainbow gradient


 palette=((0, 0, 0), (4, 0, 4), (8, 0, 8), (12, 0, 12), (17, 0, 17), (21, 0, 21), (25, 0, 25), (30, 0, 30), (34, 0, 34), (39, 0, 39), (43, 0, 43), (47, 0, 47), (52, 0, 52), (56, 0, 56), (60, 0, 60), (65, 0, 65), (69, 0, 69), (74, 0, 74), (78, 0, 78), (82, 0, 82), (87, 0, 87), (91, 0, 91), (96, 0, 96), (100, 0, 100), (104, 0, 104), (109, 0, 109), (113, 0, 113), (118, 0, 118), (122, 0, 122), (126, 0, 126), (131, 0, 131), (135, 0, 135), (139, 0, 139), (144, 0, 144), (148, 0, 148), (153, 0, 153), (157, 0, 157), (161, 0, 161), (166, 0, 166), (170, 0, 170), (175, 0, 175), (179, 0, 179), (183, 0, 183), (188, 0, 188), (192, 0, 192), (197, 0, 197), (201, 0, 201), (205, 0, 205), (210, 0, 210), (214, 0, 214), (218, 0, 218), (223, 0, 223), (227, 0, 227), (232, 0, 232), (236, 0, 236), (240, 0, 240), (245, 0, 245), (249, 0, 249), (254, 0, 254), (252, 0, 254), (248, 0, 253), (243, 0, 251), (239, 0, 250), (235, 0, 249), (230, 0, 247), (226, 0, 246), (221, 0, 244), (217, 0, 243), (213, 0, 242), (208, 0, 240), (204, 0, 239), (199, 0, 238), (195, 0, 237), (191, 0, 236), (186, 0, 235), (182, 0, 233), (178, 0, 232), (173, 0, 230), (169, 0, 229), (164, 0, 228), (160, 0, 226), (156, 0, 225), (151, 0, 224), (147, 0, 223), (142, 0, 222), (138, 0, 220), (134, 0, 219), (129, 0, 218), (125, 0, 216), (121, 0, 215), (116, 0, 214), (112, 0, 212), (107, 0, 211), (103, 0, 210), (99, 0, 209), (94, 0, 208), (90, 0, 206), (85, 0, 205), (81, 0, 204), (77, 0, 202), (72, 0, 201), (68, 0, 200), (63, 0, 198), (59, 0, 197), (55, 0, 196), (50, 0, 195), (46, 0, 194), (42, 0, 192), (37, 0, 191), (33, 0, 190), (28, 0, 188), (24, 0, 187), (20, 0, 185), (15, 0, 184), (11, 0, 183), (7, 0, 182), (3, 0, 181), (0, 1, 180), (0, 5, 181), (0, 9, 183), (0, 14, 184), (0, 18, 185), (0, 22, 186), (0, 27, 188), (0, 31, 189), (0, 36, 190), (0, 40, 192), (0, 44, 193), (0, 49, 194), (0, 53, 196), (0, 57, 197), (0, 62, 198), (0, 66, 199), (0, 71, 200), (0, 75, 202), (0, 79, 203), (0, 84, 204), (0, 88, 206), (0, 93, 207), (0, 97, 208), (0, 101, 210), (0, 106, 211), (0, 110, 212), (0, 114, 213), (0, 119, 214), (0, 123, 216), (0, 128, 217), (0, 132, 219), (0, 136, 220), (0, 141, 221), (0, 145, 223), (0, 150, 224), (0, 154, 225), (0, 158, 226), (0, 163, 227), (0, 167, 229), (0, 172, 230), (0, 176, 231), (0, 180, 233), (0, 185, 234), (0, 189, 235), (0, 193, 237), (0, 198, 238), (0, 202, 239), (0, 207, 240), (0, 211, 241), (0, 215, 243), (0, 220, 244), (0, 224, 245), (0, 229, 247), (0, 233, 248), (0, 237, 249), (0, 242, 251), (0, 246, 252), (0, 250, 254), (0, 255, 255), (0, 252, 251), (0, 250, 246), (0, 247, 242), (0, 244, 238), (0, 242, 233), (0, 239, 229), (0, 237, 224), (0, 234, 220), (0, 232, 216), (0, 229, 211), (0, 227, 207), (0, 224, 203), (0, 222, 198), (0, 220, 194), (0, 217, 189), (0, 215, 185), (0, 212, 181), (0, 210, 176), (0, 207, 172), (0, 205, 167), (0, 202, 163), (0, 200, 159), (0, 197, 154), (0, 195, 150), (0, 192, 146), (0, 190, 141), (0, 187, 137), (0, 185, 132), (0, 183, 128), (0, 180, 124), (0, 178, 119), (0, 175, 115), (0, 173, 110), (0, 170, 106), (0, 168, 102), (0, 165, 97), (0, 163, 93), (0, 160, 88), (0, 158, 84), (0, 155, 80), (0, 153, 75), (0, 150, 71), (0, 148, 67), (0, 146, 62), (0, 143, 58), (0, 141, 53), (0, 138, 49), (0, 136, 45), (0, 133, 40), (0, 131, 36), (0, 128, 31), (0, 126, 27), (0, 123, 23), (0, 121, 18), (0, 118, 14), (0, 116, 10), (0, 113, 6), (0, 111, 2), (3, 111, 0), (7, 114, 0), (11, 116, 0), (15, 118, 0), (19, 120, 0), (23, 123, 0), (27, 125, 0), (31, 128, 0), (35, 130, 0), (40, 132, 0), (44, 134, 0), (48, 137, 0), (52, 139, 0), (56, 142, 0), (60, 144, 0), (64, 146, 0), (68, 148, 0), (72, 151, 0), (77, 153, 0), (81, 155, 0), (85, 158, 0), (89, 160, 0), (93, 163, 0), (97, 165, 0), (101, 167, 0), (105, 169, 0), (109, 172, 0), (114, 174, 0), (118, 177, 0), (122, 179, 0), (126, 181, 0), (130, 183, 0), (134, 186, 0), (138, 188, 0), (142, 190, 0), (146, 193, 0), (151, 195, 0), (155, 198, 0), (159, 200, 0), (163, 202, 0), (167, 204, 0), (171, 207, 0), (175, 209, 0), (179, 212, 0), (184, 214, 0), (188, 216, 0), (192, 218, 0), (196, 221, 0), (200, 223, 0), (204, 225, 0), (208, 228, 0), (212, 230, 0), (216, 232, 0), (221, 235, 0), (225, 237, 0), (229, 239, 0), (233, 242, 0), (237, 244, 0), (241, 247, 0), (245, 249, 0), (249, 252, 0), (253, 254, 0), (254, 252, 0), (253, 248, 0), (252, 244, 0), (251, 240, 0), (250, 236, 0), (249, 232, 0), (249, 228, 0), (248, 224, 0), (247, 220, 0), (246, 215, 0), (245, 211, 0), (244, 207, 0), (244, 203, 0), (243, 199, 0), (242, 195, 0), (241, 191, 0), (240, 187, 0), (239, 183, 0), (238, 178, 0), (237, 174, 0), (236, 170, 0), (235, 166, 0), (234, 162, 0), (234, 158, 0), (233, 154, 0), (232, 150, 0), (231, 145, 0), (230, 141, 0), (229, 137, 0), (229, 133, 0), (227, 129, 0), (226, 125, 0), (225, 121, 0), (224, 117, 0), (224, 113, 0), (223, 108, 0), (222, 104, 0), (221, 100, 0), (220, 96, 0), (219, 92, 0), (219, 88, 0), (218, 84, 0), (217, 80, 0), (216, 76, 0), (215, 71, 0), (214, 67, 0), (213, 63, 0), (212, 59, 0), (211, 55, 0), (210, 51, 0), (209, 47, 0), (209, 43, 0), (208, 39, 0), (207, 34, 0), (206, 30, 0), (205, 26, 0), (204, 22, 0), (204, 18, 0), (203, 14, 0), (202, 10, 0), (201, 6, 0), (200, 2, 0), (200, 2, 2), (201, 5, 5), (201, 8, 8), (202, 11, 11), (203, 14, 14), (204, 18, 18), (204, 21, 21), (205, 24, 24), (206, 27, 27), (206, 30, 30), (207, 33, 33), (208, 36, 36), (208, 40, 40), (209, 43, 43), (210, 46, 46), (211, 49, 49), (211, 52, 52), (212, 55, 55), (212, 58, 58), (213, 62, 62), (214, 65, 65), (215, 68, 68), (215, 71, 71), (216, 75, 75), (217, 78, 78), (217, 81, 81), (218, 84, 84), (219, 87, 87), (220, 90, 90), (220, 94, 94), (221, 97, 97), (221, 100, 100), (222, 103, 103), (223, 106, 106), (223, 109, 109), (224, 112, 112), (225, 116, 116), (226, 119, 119), (226, 122, 122), (227, 125, 125), (227, 129, 129), (228, 132, 132), (229, 135, 135), (230, 139, 139), (230, 142, 142), (231, 145, 145), (232, 148, 148), (232, 151, 151), (233, 154, 154), (234, 157, 157), (235, 161, 161), (235, 164, 164), (236, 167, 167), (236, 170, 170), (237, 173, 173), (238, 176, 176), (239, 179, 179), (239, 183, 183), (240, 186, 186), (241, 189, 189), (241, 193, 193), (242, 196, 196), (243, 199, 199), (243, 202, 202), (244, 205, 205), (245, 208, 208), (246, 211, 211), (246, 215, 215), (247, 218, 218), (247, 221, 221), (248, 224, 224), (249, 227, 227), (250, 230, 230), (250, 233, 233), (251, 237, 237), (251, 240, 240))