///|
pub struct HsvPixel {
hue : Int
saturation : Int
value : Int
} derive(Debug, Eq)
///|
pub fn HsvPixel::new(hue~ : Int, saturation~ : Int, value~ : Int) -> HsvPixel {
{
hue: (hue % 360 + 360) % 360,
saturation: clamp(saturation, low=0, high=1000),
value: clamp(value, low=0, high=255),
}
}
///|
pub fn Rgb::luminance(self : Rgb) -> Int {
(self.r * 299 + self.g * 587 + self.b * 114) / 1000
}
///|
pub fn Rgb::max_channel(self : Rgb) -> Int {
max_i(self.r, max_i(self.g, self.b))
}
///|
pub fn Rgb::min_channel(self : Rgb) -> Int {
min_i(self.r, min_i(self.g, self.b))
}
///|
pub fn Rgb::to_hsv(self : Rgb) -> HsvPixel {
let high = self.max_channel()
let low = self.min_channel()
let delta = high - low
let saturation = if high == 0 { 0 } else { delta * 1000 / high }
let mut hue = 0
if delta != 0 {
if high == self.r {
hue = 60 * (self.g - self.b) / delta
} else if high == self.g {
hue = 60 * (self.b - self.r) / delta + 120
} else {
hue = 60 * (self.r - self.g) / delta + 240
}
}
HsvPixel::new(hue~, saturation~, value=high)
}
///|
pub fn hsv_to_rgb(hsv : HsvPixel) -> Rgb {
let chroma = hsv.value * hsv.saturation / 1000
let section = hsv.hue / 60
let remainder = hsv.hue % 60
let intermediate = chroma * (60 - abs_i(remainder * 2 - 60)) / 60
let offset = hsv.value - chroma
let rgb = if section == 0 {
(chroma, intermediate, 0)
} else if section == 1 {
(intermediate, chroma, 0)
} else if section == 2 {
(0, chroma, intermediate)
} else if section == 3 {
(0, intermediate, chroma)
} else if section == 4 {
(intermediate, 0, chroma)
} else {
(chroma, 0, intermediate)
}
Rgb::new(r=rgb.0 + offset, g=rgb.1 + offset, b=rgb.2 + offset)
}
///|
pub fn RgbImage::map_channels(
self : RgbImage,
red_delta : Int,
green_delta : Int,
blue_delta : Int,
) -> RgbImage {
self.map(fn(pixel) {
Rgb::new(
r=pixel.r + red_delta,
g=pixel.g + green_delta,
b=pixel.b + blue_delta,
)
})
}
///|
pub fn RgbImage::blend(
self : RgbImage,
other : RgbImage,
alpha_per_1000 : Int,
) -> RgbImage {
let alpha = clamp(alpha_per_1000, low=0, high=1000)
let out = RgbImage::new(width=self.width, height=self.height)
for y in 0.. GrayImage {
let out = GrayImage::new(width=self.width, height=self.height)
for y in 0.. RgbImage {
let out = RgbImage::new(width=image.width, height=image.height)
for y in 0.. RgbImage {
colorize_gray(image, Rgb::new(r=0, g=0, b=128), Rgb::new(r=255, g=64, b=0))
}
///|
pub fn RgbImage::mean_luminance(self : RgbImage) -> Int {
if self.pixels.length() == 0 {
0
} else {
let mut total = 0
for pixel in self.pixels {
total += pixel.luminance()
}
total / self.pixels.length()
}
}
///|
pub fn RgbImage::luminance(self : RgbImage) -> GrayImage {
let out = GrayImage::new(width=self.width, height=self.height)
for y in 0.. RgbImage {
self.map(fn(pixel) {
let value = pixel.luminance()
if value >= low.value && value <= high.value {
replacement
} else {
pixel
}
})
}
///|
pub fn color_distance(a : Rgb, b : Rgb) -> Int {
abs_i(a.r - b.r) + abs_i(a.g - b.g) + abs_i(a.b - b.b)
}
///|
pub fn rgb_checksum(image : RgbImage) -> UInt {
let mut checksum : UInt = 2166136261
for pixel in image.pixels {
checksum = (checksum ^ pixel.r.reinterpret_as_uint()) * 16777619
checksum = (checksum ^ pixel.g.reinterpret_as_uint()) * 16777619
checksum = (checksum ^ pixel.b.reinterpret_as_uint()) * 16777619
}
checksum
}