Skip to content

Commit fc4ff2b

Browse files
authored
Merge pull request #3 from phial3/develop
Develop
2 parents 6dfb37c + 0a4ba1f commit fc4ff2b

File tree

7 files changed

+1048
-120
lines changed

7 files changed

+1048
-120
lines changed

src/with_ndarray.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,8 +1014,17 @@ mod tests {
10141014
let src = rgb8_img[[h, w, c]];
10151015
let dst = back_to_rgb[[h, w, c]];
10161016
let diff = (src as i32 - dst as i32).abs();
1017-
println!("rgb8_img:{}, back_to_rgb:{}, diff:{}", src, dst, diff);
1018-
assert!(diff <= 3);
1017+
1018+
assert!(
1019+
diff <= 3,
1020+
"too mush difference at position [{}, {}, {}], src:{}, dst:{}, diff:{}",
1021+
h,
1022+
w,
1023+
c,
1024+
src,
1025+
dst,
1026+
diff
1027+
);
10191028
}
10201029
}
10211030
}

src/with_ndarray_image.rs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
use crate::with_ndarray::{ArrayWithFormat, AvFramePixel, AvPixelFormat, PixelType};
12
use crate::{FromCv, IntoCv, TryFromCv, TryIntoCv};
23
use anyhow::{Error, Result};
34
use image::{GrayImage, ImageBuffer, Luma, Rgb, RgbImage, Rgba, RgbaImage};
45
use ndarray::Array3;
5-
use num_traits::{NumCast, Zero};
66

77
// Array3<T> -> RgbImage
88
impl<T> TryFromCv<Array3<T>> for RgbImage
99
where
10-
T: Copy + Clone + NumCast + Zero,
10+
T: PixelType,
1111
{
1212
type Error = Error;
1313

@@ -40,14 +40,18 @@ where
4040
// RgbImage -> Array3<T>
4141
impl<T> TryFromCv<RgbImage> for Array3<T>
4242
where
43-
T: Copy + Clone + NumCast + Zero,
43+
T: PixelType,
4444
{
4545
type Error = Error;
4646

4747
fn try_from_cv(from: RgbImage) -> Result<Self, Self::Error> {
4848
let (width, height) = from.dimensions();
4949
let mut array = Array3::zeros((height as usize, width as usize, 3));
5050

51+
// 将 image 的 RGB 数据拷贝到 frame 中
52+
// let data_arr = Array3::from_shape_vec((height as usize, width as usize, 3), from.into_raw())
53+
// .expect("Failed to create ndarray from raw image data");
54+
5155
for y in 0..height {
5256
for x in 0..width {
5357
let pixel = from.get_pixel(x, y);
@@ -64,7 +68,7 @@ where
6468
// Array3<T> -> RgbaImage
6569
impl<T> TryFromCv<Array3<T>> for RgbaImage
6670
where
67-
T: Copy + Clone + NumCast + Zero,
71+
T: PixelType,
6872
{
6973
type Error = Error;
7074

@@ -98,7 +102,7 @@ where
98102
// RgbaImage -> Array3<T>
99103
impl<T> TryFromCv<RgbaImage> for Array3<T>
100104
where
101-
T: Copy + Clone + NumCast + Zero,
105+
T: PixelType,
102106
{
103107
type Error = Error;
104108

@@ -123,7 +127,7 @@ where
123127
// Array3<T> -> GrayImage
124128
impl<T> TryFromCv<Array3<T>> for GrayImage
125129
where
126-
T: Copy + Clone + NumCast + Zero,
130+
T: PixelType,
127131
{
128132
type Error = Error;
129133

@@ -152,7 +156,7 @@ where
152156
// GrayImage -> Array3<T>
153157
impl<T> TryFromCv<GrayImage> for Array3<T>
154158
where
155-
T: Copy + Clone + NumCast + Zero,
159+
T: PixelType,
156160
{
157161
type Error = Error;
158162

@@ -277,16 +281,13 @@ mod tests {
277281
let u8_val = (original * 255.0).round() as u8;
278282
let expected = u8_val as f32 / 255.0;
279283

280-
println!("Values different at [{}, {}, {}]: original {:.3} -> expected {:.3} but got {:.3}",
281-
i, j, k, original, expected, converted);
282-
283-
// assert!(expected - converted < 0.01,
284-
// "Values different at [{}, {}, {}]: original {:.3} -> expected {:.3} but got {:.3}",
285-
// i, j, k,
286-
// original,
287-
// expected,
288-
// converted
289-
// );
284+
assert!(expected - converted < 1.0,
285+
"Values different at [{}, {}, {}]: original {:.3} -> expected {:.3} but got {:.3}",
286+
i, j, k,
287+
original,
288+
expected,
289+
converted
290+
);
290291
}
291292
}
292293
}

src/with_opencv_image.rs

Lines changed: 167 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::with_opencv::{MatExt, OpenCvElement};
22
use crate::{FromCv, IntoCv, TryFromCv, TryIntoCv};
3-
use anyhow::{Error, Result};
3+
use anyhow::{Context, Error, Result};
44
use opencv::prelude::*;
55
use std::ops::Deref;
66

@@ -245,12 +245,62 @@ where
245245
}
246246
}
247247

248+
/// RgbImage 转换为 OpenCV Mat
249+
#[allow(dead_code)]
250+
fn image_to_mat(img: &image::RgbImage) -> Result<Mat> {
251+
let width = img.width() as i32;
252+
let height = img.height() as i32;
253+
254+
// 创建 RGB Mat
255+
let rgb_mat = unsafe {
256+
Mat::new_rows_cols_with_data_unsafe_def(
257+
height,
258+
width,
259+
opencv::core::CV_8UC3,
260+
img.as_raw().as_ptr() as *mut _,
261+
)
262+
.context("Failed to create RGB Mat")?
263+
};
264+
265+
// 转换为 openCV 默认 BGR 格式
266+
let mut bgr_mat = Mat::default();
267+
opencv::imgproc::cvt_color_def(&rgb_mat, &mut bgr_mat, opencv::imgproc::COLOR_RGB2BGR)
268+
.context("Failed to convert RGB to BGR")?;
269+
270+
Ok(bgr_mat)
271+
}
272+
273+
/// OpenCV Mat 转换为 RgbImage
274+
#[allow(dead_code)]
275+
fn mat_to_image(mat: &Mat) -> Result<image::RgbImage> {
276+
if mat.empty() {
277+
return Err(anyhow::anyhow!("Input Mat is empty"));
278+
}
279+
280+
// 转换为 RGB
281+
let mut rgb_mat = Mat::default();
282+
opencv::imgproc::cvt_color_def(mat, &mut rgb_mat, opencv::imgproc::COLOR_BGR2RGB)
283+
.context("Failed to convert BGR to RGB")?;
284+
285+
let width = rgb_mat.cols() as u32;
286+
let height = rgb_mat.rows() as u32;
287+
288+
// 获取连续数据
289+
let buffer = rgb_mat
290+
.data_bytes()
291+
.context("Failed to get mat data")?
292+
.to_vec();
293+
294+
image::RgbImage::from_raw(width, height, buffer)
295+
.context("Failed to create RgbImage from Mat data")
296+
}
297+
248298
#[cfg(test)]
249299
mod tests {
300+
use super::*;
250301
use crate::with_opencv::MatExt;
251302
use crate::TryIntoCv;
252-
use anyhow::Result;
253-
use itertools::iproduct;
303+
use anyhow::{Context, Result};
254304
use opencv::prelude::*;
255305

256306
#[test]
@@ -264,7 +314,7 @@ mod tests {
264314
let image: image::GrayImage = (&mat).try_into_cv()?;
265315
let mat2: Mat = (&image).try_into_cv()?;
266316

267-
iproduct!(0..HEIGHT, 0..WIDTH).try_for_each(|(row, col)| {
317+
itertools::iproduct!(0..HEIGHT, 0..WIDTH).try_for_each(|(row, col)| {
268318
let p1: u8 = *mat.at_2d(row as i32, col as i32)?;
269319
let p2 = image[(col as u32, row as u32)].0[0];
270320
let p3: u8 = *mat2.at_2d(row as i32, col as i32)?;
@@ -279,7 +329,7 @@ mod tests {
279329
let image: image::RgbImage = (&mat).try_into_cv()?;
280330
let mat2: Mat = (&image).try_into_cv()?;
281331

282-
iproduct!(0..HEIGHT, 0..WIDTH).try_for_each(|(row, col)| {
332+
itertools::iproduct!(0..HEIGHT, 0..WIDTH).try_for_each(|(row, col)| {
283333
let p1: opencv::core::Point3_<u8> = *mat.at_2d(row as i32, col as i32)?;
284334
let p2: image::Rgb<u8> = image[(col as u32, row as u32)];
285335
let p3: opencv::core::Point3_<u8> = *mat2.at_2d(row as i32, col as i32)?;
@@ -298,4 +348,116 @@ mod tests {
298348

299349
Ok(())
300350
}
351+
352+
fn create_rgb_image() -> image::RgbImage {
353+
let width = 320;
354+
let height = 240;
355+
let mut img = image::RgbImage::new(width, height);
356+
357+
// 创建一个简单的渐变图案
358+
for y in 0..height {
359+
for x in 0..width {
360+
let r = (x as f32 / width as f32 * 255.0) as u8;
361+
let g = (y as f32 / height as f32 * 255.0) as u8;
362+
let b = ((x + y) as f32 / (width + height) as f32 * 255.0) as u8;
363+
img.put_pixel(x, y, image::Rgb([r, g, b]));
364+
}
365+
}
366+
img
367+
}
368+
369+
fn create_test_mat() -> Result<Mat> {
370+
let width = 320;
371+
let height = 240;
372+
373+
// 创建一个 3 通道的空白图像
374+
let mut mat = unsafe {
375+
Mat::new_rows_cols(height, width, opencv::core::CV_8UC3)
376+
.context("Failed to create Mat")?
377+
};
378+
379+
// 创建渐变效果
380+
for y in 0..height {
381+
for x in 0..width {
382+
let b = (y * 255 / height) as u8;
383+
let g = (x * 255 / width) as u8;
384+
let r = ((x + y) * 255 / (width + height)) as u8;
385+
386+
// 使用 Vec3b 设置像素值
387+
let color = opencv::core::Vec3b::from([b, g, r]);
388+
mat.at_2d_mut::<opencv::core::Vec3b>(y, x)
389+
.context("Failed to set pixel value")?
390+
.copy_from_slice(&color.0);
391+
}
392+
}
393+
394+
// 添加一些测试图形
395+
// 1. 画一个矩形
396+
opencv::imgproc::rectangle_points(
397+
&mut mat,
398+
opencv::core::Point::new(50, 50),
399+
opencv::core::Point::new(100, 100),
400+
opencv::core::Scalar::new(0.0, 0.0, 255.0, 0.0), // 红色
401+
2, // 线宽
402+
opencv::imgproc::LINE_8,
403+
0,
404+
)
405+
.context("Failed to draw rectangle")?;
406+
407+
// 2. 画一个圆
408+
opencv::imgproc::circle(
409+
&mut mat,
410+
opencv::core::Point::new(width / 2, height / 2),
411+
40,
412+
opencv::core::Scalar::new(0.0, 255.0, 0.0, 0.0), // 绿色
413+
2, // 线宽
414+
opencv::imgproc::LINE_8,
415+
0,
416+
)
417+
.context("Failed to draw circle")?;
418+
419+
// 3. 画一条线
420+
opencv::imgproc::line(
421+
&mut mat,
422+
opencv::core::Point::new(0, 0),
423+
opencv::core::Point::new(width - 1, height - 1),
424+
opencv::core::Scalar::new(255.0, 0.0, 0.0, 0.0), // 蓝色
425+
2, // 线宽
426+
opencv::imgproc::LINE_8,
427+
0,
428+
)
429+
.context("Failed to draw line")?;
430+
431+
Ok(mat)
432+
}
433+
434+
#[test]
435+
fn test_mat_to_image() -> Result<()> {
436+
let mat = create_test_mat()?;
437+
438+
let img = mat_to_image(&mat)?;
439+
440+
assert_eq!(img.width(), mat.cols() as u32);
441+
assert_eq!(img.height(), mat.rows() as u32);
442+
443+
img.save("/tmp/test_mat_to_image.png")
444+
.expect("mat_to_image error");
445+
446+
Ok(())
447+
}
448+
449+
#[test]
450+
fn test_image_to_mat() -> Result<()> {
451+
let img = create_rgb_image();
452+
453+
let mat = image_to_mat(&img)?;
454+
455+
assert_eq!(mat.cols(), img.width() as i32);
456+
assert_eq!(mat.rows(), img.height() as i32);
457+
assert_eq!(mat.channels(), 3);
458+
459+
println!("test_image_to_mat depth:{}", mat.depth());
460+
461+
Ok(())
462+
}
301463
}

0 commit comments

Comments
 (0)