thermography.h
#pragma once
#include <vector>
#include<cassert>
class Thermography {
using InputColor = std::array<int, 3>;
using CalcColor = std::array<double, 3>;
using OutputColor = std::array<unsigned char, 3>;
std::vector< InputColor > m_ctable;
double m_dmin;
double m_dmax;
private:
template<typename Return>
Return clamp(Return _min, Return _max, double value) const {
if (value < _min)
return _min;
if (value > _max)
return _max;
return value;
}
//! @brief 0.0~1.0 の範囲のRGBを取得
CalcColor calc(const int from, const double ratio)const {
constexpr int R = 0, G = 1, B = 2;
const int to = from + 1;
double r = (m_ctable[from][R] + (m_ctable[to][R] - m_ctable[from][R]) * ratio) / 255.0;
double g = (m_ctable[from][G] + (m_ctable[to][G] - m_ctable[from][G]) * ratio) / 255.0;
double b = (m_ctable[from][B] + (m_ctable[to][B] - m_ctable[from][B]) * ratio) / 255.0;
return CalcColor{r,g,b};
}
//! @brief 0~255の範囲のRGBを取得
OutputColor toOutput(const CalcColor& cc)const {
return
OutputColor{
clamp<unsigned char>(0 ,255 ,cc[0] * 255),
clamp<unsigned char>(0 ,255 ,cc[1] * 255),
clamp<unsigned char>(0 ,255 ,cc[2] * 255)
};
}
public:
// @brief カラーテーブルを設定する
template<class It>
void setColorTable(It first, It last) {
for (auto c = first;c!= last;c++)
m_ctable.push_back(*c);
}
// @brief カラーテーブルを設定する
void setColorTable(
std::initializer_list< InputColor > colors
) {
setColorTable(colors.begin(), colors.end());
}
// @brief 着色する値の範囲を設定
void setArea(double _min, double _max) {
m_dmin = _min;
m_dmax = _max;
}
//! @brief 値をRGB色へ変換
OutputColor thermography(const double value)const {
constexpr int R = 0, G = 1, B = 2;
int N = m_ctable.size();
// 値の正規化
double nvalue;
double vwidth = m_dmax - m_dmin;
nvalue = (value - m_dmin) / vwidth;
int from, to;
double ratio;
//////////////////////////////
// 範囲外
if (nvalue <= 0.0) {
from = 0;
ratio = 0.0;
}
else if (nvalue >= 1.0) {
from = m_ctable.size() - 2;
ratio = 1.0;
}
//////////////////////////////
// 範囲内なら from ~ to の間で正規化してratioにする
else {
from = nvalue * (N - 1);
to = from + 1;
double NnFrom = from / double(N - 1);
double NnTo = to / double(N - 1);
ratio = (nvalue - NnFrom) / (NnTo - NnFrom);
}
CalcColor rgb = calc(from, ratio);
return toOutput(rgb);
}
};
呼び出し例
#include <iostream>
// https://www.study.suzulang.com/2dcg-functions/nbyte-data-type
#include "NByteData.hpp"
#include "ppmP3_read.hpp"
#include "thermography.h"
#include <vector>
#include <array>
void ppmP3_write(
const char* const fname,
const int width,
const int height,
const unsigned char* const p,
const int vmax
);
int main()
{
using PixelT = NByteData<3>;
std::vector<PixelT> mem;
// 画像読み込み
int width;
int height;
int vmax;
ppmP3_read(
"C:\\test\\ppp.ppm",
&width,
&height,
&vmax,
[&mem](const size_t pixelcount) {
mem.resize(pixelcount);
return (unsigned char*)&mem[0];
}
);
//////////////////////////////////////////////
//////////////////////////////////////////////
std::vector< std::array<int, 3>> ColorTable{
std::array<int, 3>{ 0 , 0, 0 }, // 黒
std::array<int, 3>{ 0 , 0, 255}, // 青
std::array<int, 3>{ 0 ,200,200}, // 水色
std::array<int, 3>{ 0 ,255, 0 }, // 緑
std::array<int, 3>{200,200, 0 }, // 橙
std::array<int, 3>{255, 0 , 0 }, // 赤
std::array<int, 3>{255,255,255} // 白
};
Thermography c;
c.setArea(0, 255);//この範囲外の値は0,255として扱われる
c.setColorTable(ColorTable.begin(), ColorTable.end());
// 色を反転
for (auto& p : mem) {
std::array<unsigned char,3> rgb = c.thermography(p.data()[0]);
p.data()[0] = rgb[0];
p.data()[1] = rgb[1];
p.data()[2] = rgb[2];
p.data()[0] = (p.data()[0] > 255) ? 255 : p.data()[0];
p.data()[1] = (p.data()[1] > 255) ? 255 : p.data()[1];
p.data()[2] = (p.data()[2] > 255) ? 255 : p.data()[2];
}
/////////////////////////////////
/////////////////////////////////
ppmP3_write(
"C:\\test\\qqq.ppm",
width,
height,
(unsigned char*)&mem[0], 255);
}
//! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む
//! @param [in] fname ファイル名
//! @param [in] width 画像の幅
//! @param [in] height 画像の高さ
//! @param [in] p 画像のメモリへのアドレス
//! @param [in] vmax 全てのRGBの中の最大値。普通の画像なら255
//! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む
void ppmP3_write(
const char* const fname,
const int width,
const int height,
const unsigned char* const p,
const int vmax
) {
FILE* fp = fopen(fname, "wb");
fprintf(fp, "P3\n%d %d\n%d\n", width, height, vmax);
size_t k = 0;
for (size_t i = 0; i < (size_t)height; i++) {
for (size_t j = 0; j < (size_t)width; j++) {
fprintf(fp, "%d %d %d ",
p[k * 3 + 0],
p[k * 3 + 1],
p[k * 3 + 2]
);
k++;
}
fprintf(fp, "\n");
}
fclose(fp);
}
ppmP3_read.hpp
#include <iostream>
// https://www.study.suzulang.com/2dcg-functions/nbyte-data-type
#include "NByteData.hpp"
// https://suzulang.com/ppmp3_read-memalloc-ver/
#include "ppmP3_read.hpp"
#include "thermography.h"
#include <vector>
#include <array>
void ppmP3_write(
const char* const fname,
const int width,
const int height,
const unsigned char* const p,
const int vmax
);
int main()
{
using PixelT = NByteData<3>;
std::vector<PixelT> mem;
// 画像読み込み
int width;
int height;
int vmax;
ppmP3_read(
"C:\\test\\ppp.ppm",
&width,
&height,
&vmax,
[&mem](const size_t pixelcount) {
mem.resize(pixelcount);
return (unsigned char*)&mem[0];
}
);
//////////////////////////////////////////////
//////////////////////////////////////////////
std::vector< std::array<int, 3>> ColorTable{
std::array<int, 3>{ 0 , 0, 0 }, // 黒
std::array<int, 3>{ 0 , 0, 255}, // 青
std::array<int, 3>{ 0 ,200,200}, // 水色
std::array<int, 3>{ 0 ,255, 0 }, // 緑
std::array<int, 3>{200,200, 0 }, // 橙
std::array<int, 3>{255, 0 , 0 }, // 赤
std::array<int, 3>{255,255,255} // 白
};
Thermography c;
c.setArea(0, 255);//この範囲外の値は0,255として扱われる
c.setColorTable(ColorTable.begin(), ColorTable.end());
// 色を反転
for (auto& p : mem) {
std::array<unsigned char,3> rgb = c.thermography(p.data()[0]);
p.data()[0] = rgb[0];
p.data()[1] = rgb[1];
p.data()[2] = rgb[2];
p.data()[0] = (p.data()[0] > 255) ? 255 : p.data()[0];
p.data()[1] = (p.data()[1] > 255) ? 255 : p.data()[1];
p.data()[2] = (p.data()[2] > 255) ? 255 : p.data()[2];
}
/////////////////////////////////
/////////////////////////////////
ppmP3_write(
"C:\\test\\qqq.ppm",
width,
height,
(unsigned char*)&mem[0], 255);
}
//! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む
//! @param [in] fname ファイル名
//! @param [in] width 画像の幅
//! @param [in] height 画像の高さ
//! @param [in] p 画像のメモリへのアドレス
//! @param [in] vmax 全てのRGBの中の最大値。普通の画像なら255
//! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む
void ppmP3_write(
const char* const fname,
const int width,
const int height,
const unsigned char* const p,
const int vmax
) {
FILE* fp = fopen(fname, "wb");
fprintf(fp, "P3\n%d %d\n%d\n", width, height, vmax);
size_t k = 0;
for (size_t i = 0; i < (size_t)height; i++) {
for (size_t j = 0; j < (size_t)width; j++) {
fprintf(fp, "%d %d %d ",
p[k * 3 + 0],
p[k * 3 + 1],
p[k * 3 + 2]
);
k++;
}
fprintf(fp, "\n");
}
fclose(fp);
}