1use crate::error::ImageError;
13
14pub fn rgb_to_gray(rgb: &[f32], width: usize, height: usize) -> Result<Vec<f32>, ImageError> {
23 let pixels = width * height;
24 if rgb.len() != pixels * 3 {
25 return Err(ImageError::BufferLengthMismatch {
26 expected: pixels * 3,
27 got: rgb.len(),
28 width,
29 height,
30 });
31 }
32
33 let mut gray = Vec::with_capacity(pixels);
34 for i in 0..pixels {
35 let r = rgb[i * 3];
36 let g = rgb[i * 3 + 1];
37 let b = rgb[i * 3 + 2];
38 gray.push(0.299 * r + 0.587 * g + 0.114 * b);
40 }
41 Ok(gray)
42}
43
44pub fn rgb_to_hsv(rgb: &[f32], width: usize, height: usize) -> Result<Vec<f32>, ImageError> {
53 let pixels = width * height;
54 if rgb.len() != pixels * 3 {
55 return Err(ImageError::BufferLengthMismatch {
56 expected: pixels * 3,
57 got: rgb.len(),
58 width,
59 height,
60 });
61 }
62
63 let mut hsv = vec![0.0_f32; pixels * 3];
64 for i in 0..pixels {
65 let (h, s, v) = rgb_pixel_to_hsv(rgb[i * 3], rgb[i * 3 + 1], rgb[i * 3 + 2]);
66 hsv[i * 3] = h;
67 hsv[i * 3 + 1] = s;
68 hsv[i * 3 + 2] = v;
69 }
70 Ok(hsv)
71}
72
73fn rgb_pixel_to_hsv(r: f32, g: f32, b: f32) -> (f32, f32, f32) {
75 let max = r.max(g).max(b);
76 let min = r.min(g).min(b);
77 let delta = max - min;
78
79 let v = max;
80 let s = if max > f32::EPSILON { delta / max } else { 0.0 };
81
82 let h = if delta < f32::EPSILON {
83 0.0
84 } else if (max - r).abs() < f32::EPSILON {
85 60.0 * (((g - b) / delta) % 6.0)
86 } else if (max - g).abs() < f32::EPSILON {
87 60.0 * ((b - r) / delta + 2.0)
88 } else {
89 60.0 * ((r - g) / delta + 4.0)
90 };
91
92 let h = if h < 0.0 { h + 360.0 } else { h };
93 (h, s, v)
94}
95
96pub fn hsv_to_rgb(hsv: &[f32], width: usize, height: usize) -> Result<Vec<f32>, ImageError> {
104 let pixels = width * height;
105 if hsv.len() != pixels * 3 {
106 return Err(ImageError::BufferLengthMismatch {
107 expected: pixels * 3,
108 got: hsv.len(),
109 width,
110 height,
111 });
112 }
113
114 let mut rgb = vec![0.0_f32; pixels * 3];
115 for i in 0..pixels {
116 let (r, g, b) = hsv_pixel_to_rgb(hsv[i * 3], hsv[i * 3 + 1], hsv[i * 3 + 2]);
117 rgb[i * 3] = r;
118 rgb[i * 3 + 1] = g;
119 rgb[i * 3 + 2] = b;
120 }
121 Ok(rgb)
122}
123
124fn hsv_pixel_to_rgb(h: f32, s: f32, v: f32) -> (f32, f32, f32) {
126 if s < f32::EPSILON {
127 return (v, v, v);
128 }
129
130 let h = h % 360.0;
131 let c = v * s;
132 let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs());
133 let m = v - c;
134
135 let (r1, g1, b1) = match (h / 60.0) as u32 {
136 0 => (c, x, 0.0),
137 1 => (x, c, 0.0),
138 2 => (0.0, c, x),
139 3 => (0.0, x, c),
140 4 => (x, 0.0, c),
141 _ => (c, 0.0, x),
142 };
143
144 (r1 + m, g1 + m, b1 + m)
145}
146
147pub fn connected_components(
156 image: &[f32],
157 width: usize,
158 height: usize,
159) -> Result<Vec<u32>, ImageError> {
160 if image.len() != width * height {
161 return Err(ImageError::BufferLengthMismatch {
162 expected: width * height,
163 got: image.len(),
164 width,
165 height,
166 });
167 }
168
169 let pixels = width * height;
170 let mut labels = vec![0u32; pixels];
171 let mut parent = Vec::with_capacity(pixels / 4);
172 parent.push(0); first_pass(image, &mut labels, &mut parent, width, height);
176
177 for i in 0..parent.len() {
179 parent[i] = find(&parent, i as u32);
180 }
181
182 let mut remap = vec![0u32; parent.len()];
184 let mut next_label = 1u32;
185 for i in 1..parent.len() {
186 let root = parent[i] as usize;
187 if remap[root] == 0 {
188 remap[root] = next_label;
189 next_label += 1;
190 }
191 remap[i] = remap[root];
192 }
193
194 for label in &mut labels {
195 if *label > 0 {
196 *label = remap[*label as usize];
197 }
198 }
199
200 Ok(labels)
201}
202
203fn first_pass(
205 image: &[f32],
206 labels: &mut [u32],
207 parent: &mut Vec<u32>,
208 width: usize,
209 height: usize,
210) {
211 for y in 0..height {
212 for x in 0..width {
213 let idx = y * width + x;
214 if image[idx].abs() < f32::EPSILON {
215 continue; }
217
218 let left = if x > 0 { labels[idx - 1] } else { 0 };
219 let above = if y > 0 { labels[idx - width] } else { 0 };
220
221 match (left > 0, above > 0) {
222 (false, false) => {
223 let new_label = parent.len() as u32;
225 parent.push(new_label);
226 labels[idx] = new_label;
227 }
228 (true, false) => labels[idx] = left,
229 (false, true) => labels[idx] = above,
230 (true, true) => {
231 labels[idx] = left.min(above);
232 union(parent, left, above);
233 }
234 }
235 }
236 }
237}
238
239fn find(parent: &[u32], mut x: u32) -> u32 {
241 while parent[x as usize] != x {
242 x = parent[x as usize];
243 }
244 x
245}
246
247fn union(parent: &mut [u32], a: u32, b: u32) {
249 let ra = find(parent, a);
250 let rb = find(parent, b);
251 if ra != rb {
252 let min = ra.min(rb);
253 let max = ra.max(rb);
254 parent[max as usize] = min;
255 }
256}