Convert RgbImage into Vec<[u8; 3]> - image

I have an RgbImage but for the gaussian blur algorithm I need to convert it to Vec<[u8; 3]>. I managed to do this before using:
let img: Vec<u8> = img.into_raw();
let mut new: Vec<[u8; 3]> = vec![];
for (r, g, b) in img.into_iter().tuples() {
new.push([r, g, b]);
}
But in my new project for some reason I get the error no method named tuples found for struct std::vec::IntoIter in the current scope. I'm not sure why this is happening but I think there is a much better way to do it anyway.

You need to add the crate itertools for tuples().
Or you can use std's chunks_exact():
for color in img.chunks_exact(3) {
new.push(color.try_into().unwrap());
}

Related

Rust (criterion): how to pass mutable reference within bench_with_input()

I am new to Rust and am trying to benchmark sorting algorithms.
The functions take immutable references to a slice (fn sort(&self, slice: &mut [T])).
I am trying to use the criterion crate to benchmark them for different inputs (random vectors of increasing length).
However I cannot figure out how to pass the vectors to the functions as mutable references. I have tried the the fixes suggested by rustc but each generates another error.
The benchmark code is (shortened example to exclude all the functions):
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use rand::{distributions::Uniform, Rng};
use sorting::*;
fn sorting_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("Sorting");
for i in [1, 10, 100].iter() {
let mut rng = rand::thread_rng();
let range = Uniform::new(0, 100);
let nums: Vec<usize> = (0..(*i)).map(|_| rng.sample(&range)).collect();
let mut v = black_box(nums.to_vec());
group.bench_with_input(BenchmarkId::new("Bubble Sort {}", i), &v, |b, v| {
b.iter(|| BubbleSort.sort(v))
});
group.finish();
}
The function for BubbleSort.sort is:
impl<T> Sorter<T> for BubbleSort {
fn sort(&self, arr: &mut [T])
where
T: Ord,
{
let mut swapped = true;
while swapped {
swapped = false;
for i in 1..arr.len() {
if arr[i - 1] > arr[i] {
arr.swap(i - 1, i);
swapped = true;
}
}
}
}
}
Some examples of the error messages.
First:
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
--> benches/criterion_bench.rs:16:39
|
15 | group.bench_with_input(BenchmarkId::new("Bubble Sort {}", i), &v, |b, v| {
| - help: consider changing this to be mutable: `mut v`
16 | b.iter(|| BubbleSort.sort(&mut v))
| ^^^^^^ cannot borrow as mutable
If I do the suggested fix, I still get cannot borrow as mutable.
I have successfully benchmarked the functions using bench_function from the criterion crate. But this does not help me with benchmarking against multiple inputs for comparison.
The direct problem in your code is that you used &v where you needed &mut v. But that's not actually going to work well, and you should not be using bench_with_input for this purpose. (In fact, I'm not sure what bench_with_input is good for — closure captures work just fine.)
The key thing to understand is that Criterion is going to run your benchmarked function many times (when you call iter). If you did arrange to pass a mutable reference to the same vector for each run, that would not be appropriate for benchmarking a sorting algorithm because it means all iterations but the first would receive already-sorted input. When the performance of the algorithm depends on the order of the input, you want a fresh non-sorted vector each time.
When you want to benchmark a function that consumes or mutates input, you use a different Bencher method than iter(). In particular, iter_batched_ref() is most appropriate for benchmarking a sorting algorithm (or any other function which takes a mutable reference and mutates it).
fn sorting_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("Sorting");
for i in [1, 10, 100] {
let mut rng = rand::thread_rng();
let range = Uniform::new(0, 100);
group.bench_function(BenchmarkId::new("Bubble Sort {}", i), |b| {
b.iter_batched_ref(
|| -> Vec<usize> { (0..i).map(|_| rng.sample(&range)).collect() },
|v| BubbleSort.sort(v),
BatchSize::SmallInput,
)
});
}
group.finish();
}
Notice that the input vector is constructed inside of a function passed to iter_batched_ref. iter_batched_ref will call that function several times, then call the function being benchmarked several times to measure it, with a fresh input each time.

Using ndarray_parallel Zip to iterate through rows of a Array2 and items of Array1

I would like to iterate through rows of an Array2 and items of an Array1 in parallel and do some computation on them with side effects.
I tried something like below,
extern crate ndarray;
extern crate ndarray_parallel;
use ndarray::{Array2, Array, Zip, Axis};
use ndarray_parallel::prelude::*;
fn main() {
let mut a = Array2::<f64>::zeros((5, 5));
let b = Array::from_iter(0..5);
let c = vec![1,2,3,4,5];
let mut d = vec![1,2,3,4,5];
let z = Zip::from(a.axis_iter(Axis(0))).and(&b);
z.par_apply(|x,y| {d[*y as usize] = 10});
}
But the compiler is complaining.
Can anyone advise?
Multiple misconceptions in your code, correct me if any of the followings is not what you want:
b seems to serve as index to the vector. You can use Zip::indexed to produce index along with element directly, no need for an explicit index array.
axis_iter returns an iterator which traverses all axis of underlying ndarray. You probably want index_axis to traverse one of them.
Your arrays host both integers and floats. In rust you can't apply arithmetic operations between the two.
par_apply takes a Fn, so it can't mutate captured variables.
All things considered, the code probably should look like this:
use ndarray::{Array2, Zip, Axis};
use ndarray_parallel::prelude::*;
fn main() {
let a = Array2::<f64>::zeros((5, 5));
let mut d = vec![1.,2.,3.,4.,5.];
Zip::indexed(a.index_axis(Axis(0), 0))
.and(&mut d)
.par_apply(|_i, x, y| *y = x + 10.);
}

How to convert a vector of arrays into 4D array?

I'm trying to play a little bit with Knet.jl and CNNs. Every example I found requires the input for CNN to be in the form of [dim1, dim2, n_of_channels, N] where N is a number of the actual images.
I'm a bit new to Julia and I don't know how to accomplish this.
I loaded images from some private directory and pushed them to a vector, so that their length is N.
images = Vector()
for img_file in readdir(dir)
img = load("$dir/$img_file")
images = vcat(images, [img])
end
typeof(image)
"320-element Array{Any,1}"
However in the following example xtrn is stored as 28x28x1x60000 Array and that is what I would like to accomplish with the private dataset.
using Knet; include(Knet.dir("data","mnist.jl"))
xtrn,ytrn,_,_= mnist()
typeof(xtrn)
Array{Float32,4}
I'm aware of functions as channelview, reshape and it's seems they should provide solution but I played with them a bit and got DimensionMismatch error all the time. I guess there's something I miss.
I don't have the files you are using in your example. But I would use cat in conjunction with a generator. Here's an example of something you can do:
julia> reduce((x,y)->cat(x, y, dims=4), rand(3,3) for _ in 1:3)
3×3×1×3 Array{Float64,4}:
[:, :, 1, 1] =
0.366818 0.847529 0.209042
0.281807 0.467918 0.68881
0.179162 0.222919 0.348935
[:, :, 1, 2] =
0.0418451 0.256611 0.609398
0.65166 0.281397 0.340405
0.11109 0.387638 0.974488
[:, :, 1, 3] =
0.454959 0.37831 0.554323
0.213613 0.980773 0.743419
0.133154 0.782516 0.669733
In order to do this with your files, this might work (untested):
images = reduce((x,y)->cat(x, y, dims=4), load(joinpath(dir, img_file)) for img_file in readdir(dir))
BTW. You should not initialize vectors like this:
images = Vector()
This makes an untyped container, which will have very bad performance. Write e.g.
images = Matrix{Float32}[]
This initializes an empty vector of Matrix{Float32}s.
Just to fill in the answer of DNF, this code results in Array in the form of [dim1, dim2, 1, N]:
images = reduce((x,y)->cat(x, y, dims=4), load(joinpath(dir, img_file)) for img_file in readdir(dir))
I wanted the 3rd dimension to be the channel and hence, the expected output is produced by:
images = reduce((x, y) -> cat(x, y, dims=4), permutedims(channelview(load(joinpath(dir, img_file))), (2, 3, 1)) for img in readdir(dir))

How to Specify a diagonal matrix using tf.get_variable

I am trying to create a diagonal matrix using tf.get_variable
But I do not know how!
Like I can make a variable which is a diagonal matrix like:
dia_size = tf.zeros((num_filters, img_size))
b = tf.Variable(tf.matrix_diag(dia_size), name=name)
b = tf.reshape(b, [-1, img_size, img_size, num_filters])
but I can not do it with tf.get_variable.
Thanks for your help in advance!
If you set the initializer parameter of tf.get_variable to a tensor, the variable will be initialized to the tensor's value. Therefore, you can use the following code:
dia_size = tf.zeros((num_filters, img_size))
b = tf.matrix_diag(dia_size)
var = tf.get_variable(..., initializer=b, ...)

Converting Map[Int, Double] to breeze.linalg.SparseVector

I am new to the Breeze library and I would like to convert a Map[Int, Double] to breeze.linalg.SparseVector, and ideally without having to specify a fixed length of the SparseVector. I managed to achieve the goal with this clumsy code:
import breeze.linalg.{SparseVector => SBV}
val mySparseVector: SBV[Double] = new SBV[Double](Array.empty, Array.empty, 10000)
myMap foreach { e => mySparseVector(e._1) = e._2 }
Not only I have to specify a fixed length of 10,000, but the code runs in O(n), where n is the size of the map. Is there a better way?
You can use VectorBuilder. There's a (sadly) undocumented feature where if you tell it the length is -1, it will happily let you add things. You will have to (annoyingly) set the length before you construct the result...
val vb = new VectorBuilder(length = -1)
myMap foreach { e => vb.add(e._1, e._2) }
vb.length = myMap.keys.max + 1
vb.toSparseVector
(Your code is actually n^2 because SparseVector has to be sorted so you're repeatedly moving elements around in an array. VectorBuilder gives you n log n, which is the best you can do.)

Resources