├── .gitattributes ├── .gitignore ├── 0.png ├── 0_out.png ├── 1.png ├── 1_out.png ├── Cargo.lock ├── Cargo.toml ├── README.md ├── rust.png ├── rust_out.png ├── sjxxb.png ├── src ├── main.rs └── test.rs └── table.png /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target/ 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planet0104/edge_detection/308648b1b6a46ec725779e0a4ee15e608d970ac8/0.png -------------------------------------------------------------------------------- /0_out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planet0104/edge_detection/308648b1b6a46ec725779e0a4ee15e608d970ac8/0_out.png -------------------------------------------------------------------------------- /1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planet0104/edge_detection/308648b1b6a46ec725779e0a4ee15e608d970ac8/1.png -------------------------------------------------------------------------------- /1_out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planet0104/edge_detection/308648b1b6a46ec725779e0a4ee15e608d970ac8/1_out.png -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "image_contrast" 3 | version = "0.1.0" 4 | dependencies = [ 5 | "lodepng 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 6 | ] 7 | 8 | [[package]] 9 | name = "libc" 10 | version = "0.2.36" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | 13 | [[package]] 14 | name = "lodepng" 15 | version = "2.1.2" 16 | source = "registry+https://github.com/rust-lang/crates.io-index" 17 | dependencies = [ 18 | "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", 19 | "rgb 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", 20 | ] 21 | 22 | [[package]] 23 | name = "rgb" 24 | version = "0.8.7" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | 27 | [metadata] 28 | "checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" 29 | "checksum lodepng 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e23bb21f018611cb9406eab31a8c357f4b16a8ecddafc8cdf147a47eb8cfb685" 30 | "checksum rgb 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a2709858644231956f913ee2951111c9aef89e016ed0c2bf16d58c1328d68fe" 31 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "image_contrast" 3 | version = "0.1.0" 4 | authors = ["Jia Ye "] 5 | 6 | [dependencies] 7 | lodepng = "*" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # image edge detection imitate Retina principle 2 | 本算法模仿视网膜中双极细胞和水平细胞的作用,来提取图像的边缘特征:


3 |
4 | 详情查看:神经节细胞

5 |

6 | 上图中,字母代表图片的像素,B代表双极细胞, H代表水平细胞。粗体B点代表当前像素点,那么当前像素点的输出等于4个细胞输出值之和除以4:
7 | pixel(1,1) = Sum(outB+outH+outB+outH)/4
8 | B和H的输出,根据亮度计算,如果像素亮度超过阈值,B输出255,H输出-255,没有超过阈值,二者都输出0。

9 | 算法运行效果如下:

10 |
11 |
12 |

13 | 此代码并非专业用途,纯属个人爱好。如果此算法并没有什么实际用途或者本身有错误,欢迎指正。 14 | -------------------------------------------------------------------------------- /rust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planet0104/edge_detection/308648b1b6a46ec725779e0a4ee15e608d970ac8/rust.png -------------------------------------------------------------------------------- /rust_out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planet0104/edge_detection/308648b1b6a46ec725779e0a4ee15e608d970ac8/rust_out.png -------------------------------------------------------------------------------- /sjxxb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planet0104/edge_detection/308648b1b6a46ec725779e0a4ee15e608d970ac8/sjxxb.png -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate lodepng; 2 | use lodepng::RGB; 3 | 4 | fn main() { 5 | let bitmap = lodepng::decode24_file("rust.png").unwrap(); 6 | let (width, height) = (bitmap.width, bitmap.height); 7 | println!("width={},height={}", width, height); 8 | 9 | let buffer = edge_detection(&bitmap.buffer, width, height, 127.5); 10 | 11 | lodepng::encode24_file("rust_out.png", &buffer, width, height).unwrap(); 12 | } 13 | 14 | //边缘检测 15 | //buffer: 图像数据 16 | //height: 图像高度 17 | //width: 图像宽度 18 | //threshold: 阈值0~255 19 | //返回: 黑底百色边缘的图像数据 20 | fn edge_detection(buffer:&Vec>, width:usize, height:usize, threshold:f32)->Vec>{ 21 | let mut out_buffer:Vec> = vec![]; 22 | let mut i = 0; 23 | 24 | for _row in 0..height{ 25 | for _col in 0..width{ 26 | //4个像素 27 | //双极细胞 给光ON,撤光OFF => 超过阈值:255 28 | //水平细胞 亮光抑制,弱光增强,和双极细胞正好相反 => 超过阈值:-255 29 | match((calc_pixel(buffer.get(i).unwrap_or(&buffer[i]), 255.0, threshold) 30 | + calc_pixel(buffer.get(i+1).unwrap_or(&buffer[i]), -255.0, threshold) 31 | +calc_pixel(buffer.get(i).unwrap_or(&buffer[i]), 255.0, threshold) 32 | + calc_pixel(buffer.get(i+width).unwrap_or(&buffer[i]), -255.0, threshold) 33 | )/4.0) as i32{ //(Sum(..pixel..)/255*4)*255 = Sum(..pixel..)/4 34 | 0 => out_buffer.push(RGB::new(0, 0, 0)), 35 | _ => out_buffer.push(RGB::new(255, 255, 255)), 36 | } 37 | i += 1; 38 | } 39 | } 40 | 41 | out_buffer 42 | } 43 | 44 | //计算每个像素的输出 45 | // p: 像素 46 | // out: 超过阈值细胞的输出 47 | // threshold: 阈值0~255 48 | fn calc_pixel(pixel:&RGB, out:f32, threshold:f32)->f32{ 49 | //二值化以后根据双极细胞、水平细胞返回输出值 50 | if 0.299*pixel.r as f32+0.587*pixel.g as f32+0.114*pixel.b as f32>threshold{ 51 | out 52 | }else{ 53 | 0.0 //弱光都不返回 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test.rs: -------------------------------------------------------------------------------- 1 | extern crate lodepng; 2 | use lodepng::RGB; 3 | 4 | fn main() { 5 | let bitmap = lodepng::decode24_file("rust.png").unwrap(); 6 | let (width, height) = (bitmap.width, bitmap.height); 7 | println!("width={},height={}", width, height); 8 | 9 | let mut buffer:Vec> = vec![RGB::new(0, 0, 0); width*height]; 10 | 11 | edge_detection_h(&bitmap.buffer, &mut buffer, width, height, 127.0); 12 | edge_detection_v(&bitmap.buffer, &mut buffer, width, height, 127.0); 13 | 14 | lodepng::encode24_file("test_out.png", &buffer, width, height).unwrap(); 15 | } 16 | 17 | //边缘检测 18 | //buffer: 图像数据 19 | //height: 图像高度 20 | //width: 图像宽度 21 | //threshold: 阈值0~255 22 | //返回: 黑底百色边缘的图像数据 23 | fn edge_detection_h(buffer:&Vec>, out_buffer:&mut Vec>, width:usize, height:usize, threshold:f32){ 24 | let mut row_first_binary = true; //当前行第一个是否是双极细胞 25 | let mut i = 0; 26 | 27 | for _row in 0..height{ 28 | //第一列是否是双极细胞 29 | let mut col_binary = row_first_binary; 30 | for _col in 0..width{ 31 | 32 | match((calc_pixel(buffer.get(i+width), !col_binary, &buffer[i], threshold) 33 | + calc_pixel(buffer.get(i+width+1), col_binary, &buffer[i], threshold) 34 | )/2.0) as i32{ //(Sum(..pixel..)/255*4)*255 = Sum(..pixel..)/4 35 | 0 => { 36 | //out_buffer[i].r = 0; 37 | //out_buffer[i].g = 0; 38 | //out_buffer[i].b = 0; 39 | } 40 | _ => { 41 | out_buffer[i].r = 255; 42 | out_buffer[i].g = 255; 43 | out_buffer[i].b = 255; 44 | } 45 | } 46 | //下一列是否是双极细胞 47 | col_binary = !col_binary; 48 | i += 1; 49 | } 50 | //下一行第一个是否是双极细胞 51 | row_first_binary = !row_first_binary; 52 | } 53 | } 54 | 55 | fn edge_detection_v(buffer:&Vec>, out_buffer:&mut Vec>, width:usize, height:usize, threshold:f32){ 56 | let mut row_first_binary = true; //当前行第一个是否是双极细胞 57 | let mut i = 0; 58 | 59 | for _row in 0..height{ 60 | //第一列是否是双极细胞 61 | let mut col_binary = row_first_binary; 62 | for _col in 0..width{ 63 | 64 | match(( 65 | calc_pixel(buffer.get(i+width), !col_binary, &buffer[i], threshold) 66 | + calc_pixel(buffer.get(i+width+width), col_binary, &buffer[i], threshold) 67 | )/2.0) as i32{ //(Sum(..pixel..)/255*4)*255 = Sum(..pixel..)/4 68 | 0 => { 69 | //out_buffer[i].r = 0; 70 | //out_buffer[i].g = 0; 71 | //out_buffer[i].b = 0; 72 | } 73 | _ => { 74 | out_buffer[i].r = 255; 75 | out_buffer[i].g = 0; 76 | out_buffer[i].b = 0; 77 | } 78 | } 79 | //下一列是否是双极细胞 80 | col_binary = !col_binary; 81 | i += 1; 82 | } 83 | //下一行第一个是否是双极细胞 84 | row_first_binary = !row_first_binary; 85 | } 86 | } 87 | 88 | //计算每个像素的输出 89 | //双极细胞(binary) 给光ON,撤光OFF 90 | //水平细胞(!binary) 亮光抑制,弱光增强,和双极细胞正好相反。 91 | // p: 像素 92 | // binary: true说明是像素代表双极细胞, false说明像素代表水平细胞 93 | // c: 如果像素没有找到,用此像素替换。 94 | // threshold: 阈值0~255 95 | fn calc_pixel(p:Option<&RGB>, binray:bool, c:&RGB, threshold:f32)->f32{ 96 | let pixel = match p{ 97 | Some(pixel) => pixel, 98 | None => c 99 | }; 100 | //二值化以后根据双极细胞、水平细胞返回输出值 101 | if 0.299*pixel.r as f32+0.587*pixel.g as f32+0.114*pixel.b as f32>threshold{ 102 | if binray{ 103 | 255.0 //强光双击细胞返回ON 104 | }else{ 105 | -255.0 //强光水平细胞返回OFF 106 | } 107 | }else{ 108 | 0.0 //弱光都不返回 109 | } 110 | } -------------------------------------------------------------------------------- /table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planet0104/edge_detection/308648b1b6a46ec725779e0a4ee15e608d970ac8/table.png --------------------------------------------------------------------------------