Skip to content

Commit 8e8e218

Browse files
author
kmgx
committed
Add working BTC
1 parent b0cb4d5 commit 8e8e218

File tree

10 files changed

+113
-48
lines changed

10 files changed

+113
-48
lines changed

.gitignore

+1-8
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,4 @@
88

99
# These are backup files generated by rustfmt
1010
**/*.rs.bk
11-
12-
13-
#Added by cargo
14-
#
15-
#already existing elements are commented out
16-
17-
/target
18-
#**/*.rs.bk
11+
target/

Block-Truncation-Coding/.vscode/launch.json

Whitespace-only changes.

Block-Truncation-Coding/Cargo.lock

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Block-Truncation-Coding/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ edition = "2018"
1010
image = "0.22.3"
1111
structopt = "0.3.2"
1212
num-traits = "0.2.8"
13-
bitvec = "0.15.2"
13+
bitvec = "0.15.2"
14+
15+
[dependencies.img-quality]
16+
path = "../img-quality"

Block-Truncation-Coding/output.png

45.3 KB
Loading

Block-Truncation-Coding/output16.png

22.8 KB
Loading

Block-Truncation-Coding/output32.png

13 KB
Loading

Block-Truncation-Coding/output4.png

45.3 KB
Loading

Block-Truncation-Coding/output8.png

34.6 KB
Loading

Block-Truncation-Coding/src/main.rs

+100-39
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ use structopt::StructOpt;
22
use image::GenericImageView;
33
use num_traits::pow::Pow;
44
use bitvec::prelude::*;
5-
use std::convert::From;
65
use std::string::String;
7-
8-
mod hpsnr;
9-
6+
use img_quality;
7+
use std::fmt;
108

119
#[derive(StructOpt, Debug)]
1210
#[structopt(name = "basic")]
@@ -15,67 +13,122 @@ struct Opt {
1513
file: String
1614
}
1715

16+
#[derive(Clone)]
17+
struct VecBlock {
18+
width : usize, height : usize,
19+
pixels : Vec<u8>
20+
}
1821

22+
#[derive(Debug, Clone)]
1923
struct BtcBlock {
20-
highCcolor: u8,
21-
lowColor: u8,
22-
pixels: BitVec
24+
highColor: u8, lowColor: u8,
25+
width : usize, height : usize,
26+
pixels: Vec<u8>
2327
}
2428

29+
impl fmt::Display for BtcBlock { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30+
return write!(f, "VecBlock ({}, {}) with a = {}, b = {} has pixels {:?}", self.width, self.height, self.highColor, self.lowColor, self.pixels);
31+
}}
32+
2533
struct BtcImage {
26-
imgSize: (u32, u32),
27-
blockSize: (u32, u32),
34+
blockCountX: usize, blockCountY : usize,
35+
width : usize, height : usize,
2836
blocks: Vec<BtcBlock>
2937
}
3038

39+
fn no_overflow_cast(x : f64) -> u8 {
40+
if x < 0.0 { 0 } else if x > 255.0 { 255 } else { x as u8 }
41+
}
42+
43+
fn get_block_nb(i : usize, img_width : usize, img_height : usize, block_width : usize, block_height : usize, block_count_x : usize) -> (usize, usize, usize){
44+
let pos_x = (i % img_width) as usize;
45+
let pos_y = ((i - pos_x) / img_width) as usize;
46+
47+
let block_x = pos_x / block_width;
48+
let block_y = pos_y / block_height;
49+
let block_count = block_x + (block_y * block_count_x);
50+
//println!("{:?}, {:?}, {:?}, {:?}, {:?}, {:?}, ", block_x, block_y, block_count_x, block_count_y, pos_x, pos_y);
51+
52+
let block_pos_x = pos_x % block_width;
53+
let block_pos_y = pos_y % block_height;
54+
55+
return (block_count, block_pos_x, block_pos_y);
56+
}
3157

3258
fn btc_encode(image: image::DynamicImage, blockWidth: usize, blockHeight: usize) -> BtcImage {
33-
let mut pixels : Vec<u8> = image.raw_pixels();
59+
let pixels : Vec<u8> = image.raw_pixels();
3460
let size = image.dimensions();
3561
let img_width = size.0 as usize;
3662
let img_height = size.1 as usize;
3763

38-
39-
40-
4164
// Build the blocks
4265
let block_count_x = (img_width as f64 / blockWidth as f64).ceil() as usize;
4366
let block_count_y = (img_height as f64 / blockHeight as f64).ceil() as usize;
44-
let block_count_total = block_count_x*block_count_y;
45-
let mut blocks: Vec<Vec<u8>> = vec![vec![]; block_count_total];
67+
let block_count_total = block_count_x * block_count_y;
68+
let mut blocks: Vec<VecBlock> = vec![VecBlock{height : 0, width : 0, pixels : vec![]}; block_count_total];
69+
4670
for i in 0..pixels.len() {
47-
let pos_x = (i % img_width) as usize;
48-
let pos_y = ((i - pos_x) / img_width) as usize;
71+
72+
let (block_pos, block_pos_x, block_pos_y) = get_block_nb(i, img_width, img_height, blockWidth, blockHeight, block_count_x);
73+
let block = &mut blocks[block_pos];
4974

50-
let block_x = pos_x / blockWidth;
51-
let block_y = pos_y / blockHeight;
52-
let block_count = block_x + (block_y * block_count_y);
75+
if block_pos_x + 1 > block.width { block.width = block_pos_x + 1; }
76+
if block_pos_y + 1 > block.height { block.height = block_pos_y + 1; }
77+
block.pixels.push(pixels[i]);
78+
}
5379

54-
//println!("{:?}, {:?}, {:?}, {:?}, {:?}, {:?}, ", block_x, block_y, block_count_x, block_count_y, pos_x, pos_y);
80+
// println!("{:?}, {:?}", blocks[0].len(), blocks[0]);
81+
// println!("{:?}", pixels.len());
5582

56-
blocks[block_count].push(pixels[i]);
83+
let mut result : BtcImage = BtcImage{ blockCountX: block_count_x, blockCountY : block_count_y, blocks: vec![], width: img_width, height: img_height};
84+
for i in 0..blocks.len() {
85+
let block = &blocks[i];
86+
87+
let h : f64 = block.pixels.iter().map(|&x| x as f64).sum::<f64>() as f64 / block.pixels.len() as f64;
88+
let h2 : f64 = block.pixels.iter().map(|&val| (val as f64).pow(2)).sum::<f64>() / block.pixels.len() as f64;
89+
let theta : f64 = (h2 - h.pow(2) as f64).sqrt();
90+
let q = block.pixels.iter().filter(|&&x| x as f64 >= h).count() as f64;
91+
let m = block.pixels.len() as f64;
92+
93+
let a = if m-q == 0.0 { h } else { h - (theta * (q/(m-q)).sqrt()) };
94+
let b = if q == 0.0 { h } else { h + (theta * ((m-q)/q).sqrt()) };
95+
// println!("{:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, ", i, h, h2, theta, q, m, a, b);
96+
97+
//let pix : BitVec = block.pixels.iter().map(|&x| if x < h as u8 { 0 } else { 1 }).collect::<Vec<u8>>().into();
98+
let pix : Vec<u8> = block.pixels.iter().map(|&x| if x < h as u8 { 0 } else { 1 }).collect::<Vec<u8>>().into();
99+
let newblock = BtcBlock{pixels: pix, lowColor: no_overflow_cast(a), highColor: no_overflow_cast(b), width: block.width, height : block.height};
100+
//println!("newblock : {}", newblock);
101+
result.blocks.push(newblock);
102+
57103
}
58104

59-
//println!("{:?}", blocks[0].len());
105+
return result;
106+
}
60107

108+
fn btc_decode(image: BtcImage) -> image::DynamicImage {
109+
let mut pixels : Vec<u8> = vec![];
61110

62-
for i in 0..blocks.len() {
63-
64-
let block = blocks[i];
111+
let basewidth = image.blocks[0].width;
112+
let baseheight = image.blocks[0].height;
113+
let fullsize = image.width * image.height;
114+
// println!("{:?}, {:?}", basewidth, baseheight);
65115

66-
let avg = block.iter().sum() as f64 / block.len() as f64;
67-
let sd = (block.iter().map(|val| (*val as f64 - avg).pow(2)).sum() as f64 / block.len() as f64).sqrt();
68-
116+
for i in 0..fullsize {
117+
118+
let (block_pos, block_pos_x, block_pos_y) = get_block_nb(i, image.width, image.height, basewidth, baseheight, image.blockCountX);
119+
let block = &image.blocks[block_pos];
120+
let pixel_pos = (block_pos_y * block.width) + block_pos_x;
121+
122+
let pixel = block.pixels[pixel_pos];
123+
pixels.push(if pixel == 1 { block.highColor } else { block.lowColor });
69124

70125

71126
}
72127

73-
return BtcImage{ imgSize: (0,0), blockSize: (0,0), blocks: vec![]};
74-
}
128+
// println!("{:?}", pixels.len());
75129

76-
//fn btc_decode(image: BtcImage) -> image::DynamicImage {
77-
78-
//}
130+
return image::DynamicImage::ImageLuma8(image::ImageBuffer::from_vec(image.width as u32, image.height as u32, pixels).unwrap());
131+
}
79132

80133

81134
fn main() {
@@ -101,15 +154,23 @@ fn main() {
101154
println!("Saving input image");
102155
img.save("./input.png").unwrap();
103156

104-
/*let output = btc_decode(btc_encode(img.clone()));
157+
let output_4 = btc_decode(btc_encode(img.clone(), 4,4));
158+
let output_8 = btc_decode(btc_encode(img.clone(), 8,8));
159+
let output_16 = btc_decode(btc_encode(img.clone(), 16,16));
160+
let output_32 = btc_decode(btc_encode(img.clone(), 32,32));
105161

106-
println!("MSE : {}", mse(&img, &output).unwrap());
162+
println!("HPSNR 4x4 : {}", img_quality::hpsnr(&img, &output_4).unwrap());
163+
println!("HPSNR 8x8 : {}", img_quality::hpsnr(&img, &output_8).unwrap());
164+
println!("HPSNR 16x16 : {}", img_quality::hpsnr(&img, &output_16).unwrap());
165+
println!("HPSNR 32x32 : {}", img_quality::hpsnr(&img, &output_32).unwrap());
107166

108167

109168

110-
println!("Saving result");
111-
output.save("./output.png").unwrap();*/
112-
btc_encode(img.clone(), 32, 32);
169+
println!("Saving results");
170+
output_4.save("./output4.png").unwrap();
171+
output_8.save("./output8.png").unwrap();
172+
output_16.save("./output16.png").unwrap();
173+
output_32.save("./output32.png").unwrap();
113174

114175

115176
}

0 commit comments

Comments
 (0)