はじめに
HSVからRGBに変換したいとき、正確な計算より「手軽で速い近似値」で十分な場面ってよくありますよね。
今回は、そんなときに使える軽量な近似式によるHSV→RGB変換をC++で書いてみました。
STLだけで動作します。
動作環境
C++17以上で行けるはず。
コード
Colorクラスも勝手に持っていって構いません。
#include <algorithm>
#include <cmath>
#include <iostream>
// ただのRGBな色クラス
// 自由に持っていっていいよ
class Color {
public:
double GetR() const { return r_; }
double GetG() const { return g_; }
double GetB() const { return b_; }
void SetR(double r) { r_ = r; }
void SetG(double g) { g_ = g; }
void SetB(double b) { b_ = b; }
void Saturate() {
SetR(std::clamp(GetR(), static_cast<double>(0.0f), static_cast<double>(1.0f)));
SetG(std::clamp(GetG(), static_cast<double>(0.0f), static_cast<double>(1.0f)));
SetB(std::clamp(GetB(), static_cast<double>(0.0f), static_cast<double>(1.0f)));
}
void Saturate255() {
SetR(std::clamp(GetR(), static_cast<double>(0.0f), static_cast<double>(255.0f)));
SetG(std::clamp(GetG(), static_cast<double>(0.0f), static_cast<double>(255.0f)));
SetB(std::clamp(GetB(), static_cast<double>(0.0f), static_cast<double>(255.0f)));
}
Color() = default;
Color(double r, double g, double b) {
r_ = r;
g_ = g;
b_ = b;
}
// 演算子オーバーロード
Color operator+(const Color& rhs) const { return Color(GetR() + rhs.GetR(), GetG() + rhs.GetG(), GetB() + rhs.GetB()); }
Color operator+(double scalar) const { return Color(GetR() + scalar, GetG() + scalar, GetB() + scalar); }
Color operator-(const Color& rhs) const { return Color(GetR() - rhs.GetR(), GetG() - rhs.GetG(), GetB() - rhs.GetB()); }
Color operator-(double scalar) const { return Color(GetR() - scalar, GetG() - scalar, GetB() - scalar); }
Color operator*(const Color& rhs) const { return Color(GetR() * rhs.GetR(), GetG() * rhs.GetG(), GetB() * rhs.GetB()); }
Color operator*(double scalar) const { return Color(GetR() * scalar, GetG() * scalar, GetB() * scalar); }
Color operator/(const Color& rhs) const { return Color(GetR() / rhs.GetR(), GetG() / rhs.GetG(), GetB() / rhs.GetB()); }
Color operator/(double scalar) const { return Color(GetR() / scalar, GetG() / scalar, GetB() / scalar); }
private:
double r_ = 0;
double g_ = 0;
double b_ = 0;
};
/**
* h : 0.0 ~ 360.0
* s : 0.0 ~ 1.0
* v : 0.0 ~ 1.0
*
* return : 0 ~ 255の範囲で近似値を出す
*/
Color HsvToRgb(double h, double s = 1.0f, double v = 1.0f) {
Color result;
h = std::fmod(h, 360.0f);
h /= 360.0f;
result.SetR(std::abs(h * 6 - 3) - 1);
result.SetG(2 - std::abs(h * 6 - 2));
result.SetB(2 - std::abs(h * 6 - 4));
result.Saturate();
return (((result - 1) * s + 1) * v) * 255.0f;
}
// サンプルコード
int main() {
double h = 0, s = 0, v = 0;
std::cout << "Please input HSV" << std::endl;
std::cin >> h >> s >> v;
Color result = HsvToRgb(h, s, v);
std::cout << result.GetR() << " " << result.GetG() << " " << result.GetB() << std::endl;
return 0;
}
ダウンロード(MITライセンス)
ご自由にどうぞ。
https://github.com/OishiiShishamo/Qiita/blob/main/C%2B%2B/hsv_to_rgb.cpp
参考
HLSL向けのHSV関連のやつが書いてあるやつ: https://www.chilliant.com/rgb2hsv.html
おわりに
Qiitaで記事を書くのは初めてでしたがどうでしたか?
参考になったらぜひいいねをお願いします!
気になる点・もっと良いやり方などあれば、ぜひコメントで教えてください!