p2hacks2023 / pre-06

fuNG
0 stars 1 forks source link

WASM: RGB to HSVを実装 #37

Closed Yourein closed 9 months ago

Yourein commented 9 months ago

ImageライブラリはRGB画像やグレースケール画像を扱うことを前提としていそう。RGB to HSVはそんなに実装が重いわけではないので、普通に書いてしまっていいと思う。

Image::DynamicImage::pixelsが返してくるイテレータは実装を読んだらこんなイテレーターだった

impl<'a, I: GenericImageView> Iterator for Pixels<'a, I> {
    type Item = (u32, u32, I::Pixel);

    fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
        if self.x >= self.width {
            self.x = 0;
            self.y += 1;
        }

        if self.y >= self.height {
            None
        } else {
            let pixel = self.image.get_pixel(self.x, self.y);
            let p = (self.x, self.y, pixel);

            self.x += 1;

            Some(p)
        }
    }
}

get_pixelimage::Rgbaを返す。 Image::rgbaに以下のようなimplを生やすのが簡単そう

impl image::rgba {
    pub fn to_hsv(&self) -> img_util::hsv {
        todo!{}
    }
}
pub(crate) struct hsv {
    hue: Option<f64>,
    saturation: f64,
    value: f64
}

impl hsv {
    pub fn get_hue() -> Option<f64> {}
    pub fn get_saturation() -> f64 {}
    pub fn get_value() -> f64 {}
}

計算方法についてはIssue #7 の https://github.com/p2hacks2023/pre-06/issues/7#issuecomment-1851821297 を参照

Yourein commented 9 months ago

出典によって変換式が全然違うことになっていたので、信頼できる出典 (ディジタル画像処理(改定新版), 公益財団法人画像情報教育振興協会) にあたることにした。

それに従うと、変換式は以下の通り


I_{\text{max}} = \text{max}(R, G, B), \hspace{0.5em} I_{\text{min}} = \text{min}(R, G, B)
V = I_{\text{max}}
S = (I_{\text{max} - I_{\text{min}}}) / I_{\text{max}}
H = 
\begin{cases}
  \dfrac{G - B}{I_{\text{max}} - I_{\text{min}}} \times 60 + 0   & (I_{\text{max}} = R) \\
  \dfrac{B - R}{I_{\text{max}} - I_{\text{min}}} \times 60 + 120 & (I_{\text{max}} = G) \\
  \dfrac{R - G}{I_{\text{max}} - I_{\text{min}}} \times 60 + 240 & (I_{\text{max}} = B) \\
\end{cases}

$I{\text{max}} = I{\text{min}}$の場合に$H$が不定となるが、この実装上では0にしておきたい。

Yourein commented 9 months ago

$S, V$の値は0~100の範囲の値にしておきたい (GIMPがそう) ので、実際のコードには $S, V$ をその範囲に押し込めるような式を書く