Java 上でカラーマップの表示

Toru Kano 

読み込んだテキストデータをスペースで区切り、数値の配列に格納していきます。
ここでは、cmp のフォーマットを対象にコード例を記していきます。

変数・配列への格納のコード例(RGB補間)

    int cp; // コントロールポイント数
    int dataMin, dataMax; // データの最小値・最大値
    float[][] colorData = new float[256][2]; // CP位置と透明度
    float[][] colorDataRGB = new float[256][3]; // RGB値
    BufferedImage bufImage; // カラーマップ描画用
    String lastDir = "C:\\Users\\Toru\\Documents\\ColorMaps";

    private void btnReadCMPActionPerformed(java.awt.event.ActionEvent evt) {                                           
        try {
            // ファイルを開く
            JFileChooser fc = new JFileChooser(lastDir);
            fc.setFileFilter(new FileNameExtensionFilter("カラーマップファイル", "cmp", "cmp"));
            if (fc.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) return;
            File file = fc.getSelectedFile();
            lastDir = file.getAbsolutePath();
            FileInputStream fis = new FileInputStream(file);
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader bur = new BufferedReader(isr);

            // ファイルの中身を読み込んで変数に格納(cmp専用)
            String[] line;
            line = bur.readLine().split(" ");
            cp = Integer.parseInt(line[0]);
            dataMin = Integer.parseInt(line[1]);
            dataMax = Integer.parseInt(line[2]);
            for (int i = 0; i < cp; i++) {
                line = bur.readLine().split(" ");
                colorData[i][0] = Float.parseFloat(line[0]);
                colorData[i][1] = Float.parseFloat(line[1]);
                colorDataRGB[i][0] = Float.parseFloat(line[2]);
                colorDataRGB[i][1] = Float.parseFloat(line[3]);
                colorDataRGB[i][2] = Float.parseFloat(line[4]);
            }

            // ファイルを閉じる
            bur.close();
            isr.close();
            fis.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
        // カラーマップを BufferedImage に描画
        bufImage = new BufferedImage(lblColorMap.getWidth(), lblColorMap.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics g = bufImage.getGraphics();
        for (int x = 0; x < 256; x++) {
            g.setColor(getColorRGB(x));
            g.fillRect(x * 2, 0, 2, lblColorMap.getHeight());
        }
        // BufferedImage をラベルに貼り付け
        lblColorMap.setIcon(new ImageIcon(bufImage));
    }                                          

    // カラーマップから RGB値を取得するメソッド
    Color getColorRGB(float value) {
        float red = 0, green = 0, blue = 0;
        for (int i = 1; i < cp; i++) {
            if (colorData[i - 1][0] <= value && value <= colorData[i][0]) {
                red = colorDataRGB[i - 1][0] + (value - colorData[i - 1][0]) * (colorDataRGB[i][0] - colorDataRGB[i - 1][0]) / (colorData[i][0] - colorData[i - 1][0]);
                green = colorDataRGB[i - 1][1] + (value - colorData[i - 1][0]) * (colorDataRGB[i][1] - colorDataRGB[i - 1][1]) / (colorData[i][0] - colorData[i - 1][0]);
                blue = colorDataRGB[i - 1][2] + (value - colorData[i - 1][0]) * (colorDataRGB[i][2] - colorDataRGB[i - 1][2]) / (colorData[i][0] - colorData[i - 1][0]);
                break;
            }
        }
        return new Color(red, green, blue);
    }

上記のコードを実行すると、以下のようなカラーマップが得られます。

greyscale.cmp

rgb_greyscale

defaultstep.cmp

rgb_step

default.cmp

rgb_default

midrange.cmp

rgb_mid

colorwave.cmp

rgb_wave

RGB値による補間でも「greyscale.cmp」や「defaultstep.cmp」には影響はありませんが、それ以外のカラーマップは色相が考慮されていない影響を受けます。次に、HSB値による補間のプログラム例を示します。

変数・配列への格納のコード例(HSB補間)

    int cp; // コントロールポイント数
    int dataMin, dataMax; // データの最小値・最大値
    float[][] colorData = new float[256][2]; // CP位置と透明度
    float[][] colorDataRGB = new float[256][3]; // RGB値
    float[][] colotDataHSB = new float[256][3]; // HSB値
    BufferedImage bufImage; // カラーマップ描画用
    String lastDir = "C:\\Users\\Toru\\Documents\\ColorMaps";

    private void btnReadCMPActionPerformed(java.awt.event.ActionEvent evt) {                                           
        try {
            // ファイルを開く
            JFileChooser fc = new JFileChooser(lastDir);
            fc.setFileFilter(new FileNameExtensionFilter("カラーマップファイル", "cmp", "cmp"));
            if (fc.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) return;
            File file = fc.getSelectedFile();
            lastDir = file.getAbsolutePath();
            FileInputStream fis = new FileInputStream(file);
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader bur = new BufferedReader(isr);

            // ファイルの中身を読み込んで変数に格納(cmp専用)
            String[] line;
            line = bur.readLine().split(" ");
            cp = Integer.parseInt(line[0]);
            dataMin = Integer.parseInt(line[1]);
            dataMax = Integer.parseInt(line[2]);
            for (int i = 0; i < cp; i++) {
                line = bur.readLine().split(" ");
                colorData[i][0] = Float.parseFloat(line[0]);
                colorData[i][1] = Float.parseFloat(line[1]);
                colorDataRGB[i][0] = Float.parseFloat(line[2]);
                colorDataRGB[i][1] = Float.parseFloat(line[3]);
                colorDataRGB[i][2] = Float.parseFloat(line[4]);

                Color.RGBtoHSB((int) (255 * colorDataRGB[i][0]), (int) (255 * colorDataRGB[i][1]), (int) (255 * colorDataRGB[i][2]), colotDataHSB[i]);
            }

            // ファイルを閉じる
            bur.close();
            isr.close();
            fis.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
        // カラーマップを BufferedImage に描画
        bufImage = new BufferedImage(lblColorMap.getWidth(), lblColorMap.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics g = bufImage.getGraphics();
        for (int x = 0; x < 256; x++) {
            g.setColor(getColorHSB(x));
            g.fillRect(x * 2, 0, 2, lblColorMap.getHeight());
        }
        // BufferedImage をラベルに貼り付け
        lblColorMap.setIcon(new ImageIcon(bufImage));
    }    

    // カラーマップから HSB値を取得するメソッド    
    Color getColorHSB(float value) {
        float hue = 0, saturation = 0, brightness = 0;
        for (int i = 1; i < cp; i++) {
            if (colorData[i - 1][0] <= value && value <= colorData[i][0]) {
                hue = colotDataHSB[i - 1][0] + (value - colorData[i - 1][0]) * (colotDataHSB[i][0] - colotDataHSB[i - 1][0]) / (colorData[i][0] - colorData[i - 1][0]);
                saturation = colotDataHSB[i - 1][1] + (value - colorData[i - 1][0]) * (colotDataHSB[i][1] - colotDataHSB[i - 1][1]) / (colorData[i][0] - colorData[i - 1][0]);
                brightness = colotDataHSB[i - 1][2] + (value - colorData[i - 1][0]) * (colotDataHSB[i][2] - colotDataHSB[i - 1][2]) / (colorData[i][0] - colorData[i - 1][0]);
                break;
            }
        }
        return new Color(Color.HSBtoRGB(hue, saturation, brightness));
    }

上記ソースコードのハイライトされた部分を実装することで、HSBによる補間になります
RGB と HSB の変換には、Color クラスの RGBtoHSB/HSBtoRGB メソッドが利用可能です。
このコードで実際に得られるカラーマップは以下のとおりです。

greyscale.cmp

hsb_grey

defaultstep.cmp

hsb_step

default.cmp

hsb_default

midrange.cmp

hsb_mid

colorwave.cmp

hsb_wave

「greyscale.cmp」や「defaultstep.cmp」に変化はありませんが、それ以外のカラーマップはカラフルになっていることがわかります。状況に応じてどちらの補間も扱えるようになっておくと良いかと思います。

臨時:一次元配列版コード

// カラーマップから RGB値を取得するメソッド
Color getColorRGB(float value) {
    float red = 0, green = 0, blue = 0;
    for (int i = 1; i < cp; i++) {
        if (cpPos[i - 1] <= value && value <= cpPos[i]) {
            red = dataRed[i - 1] + (value - cpPos[i - 1]) * (dataRed[i] - dataRed[i - 1]) / (cpPos[i] - cpPos[i - 1]);
            green = dataGreen[i - 1] + (value - cpPos[i - 1]) * (dataGreen[i] - dataGreen[i - 1]) / (cpPos[i] - cpPos[i - 1]);
            blue = dataBlue[i - 1] + (value - cpPos[i - 1]) * (dataBlue[i] - dataBlue[i - 1]) / (cpPos[i] - cpPos[i - 1]);
            break;
        }
    }
    return new Color(red, green, blue);