In this notebook I am going to learn about BitArrays (i.e. arrays of booleans) and image indexing in general.
I am going to create an artistic representation of the original image in the following way:
The end result will be an abstract representation of the original image, rendered with the edges at various colors.
There are a number of ways to generate edge maps, so I am going to try generating two of them:
The final painting will be evocative of Andy Warhol, but only a little ;)
In [356]:
using Images, FileIO, Colors;
The test image is going to be our former president, Barack Obama.
In [357]:
img = load("obama.jpg")
Out[357]:
And it's an RGB image, as we can see:
In [358]:
typeof(img)
Out[358]:
But I want to manipulate the grayscale image, since to compute things like image gradients (to find edges), it is easier to define on grayscale images. The same .
casting notation can be used with the Gray
color type.
In [359]:
gray_img = Gray.(img)
Out[359]:
And we can see the image is now of type Gray
.
In [360]:
typeof(gray_img)
Out[360]:
You access the gray value with .val
, since if you just try to index an image to see its value, the actual color pixel will get rendered.
In [362]:
gray_img[1, 1].val
Out[362]:
In [363]:
gray_img[1, 1]
Out[363]:
Find the edges
Two ways of computing sharpness map:
Image gray = color2gray(im);
Image blurred_gray = gaussianBlur_seperable(gray, sigma);
Image high_freq = gray - blurred_gray;
Image sharpness_map = gaussianBlur_seperable(high_freq * high_freq, 4 * sigma);
sharpness_map = sharpness_map / sharpness_map.max();
return sharpness_map;
Image gradientMagnitude(const Image &im, bool clamp){
// sobel filtering in x direction
Filter sobelX(3, 3);
sobelX(0,0) = -1.0; sobelX(1,0) = 0.0; sobelX(2,0) = 1.0;
sobelX(0,1) = -2.0; sobelX(1,1) = 0.0; sobelX(2,1) = 2.0;
sobelX(0,2) = -1.0; sobelX(1,2) = 0.0; sobelX(2,2) = 1.0;
Image imSobelX = sobelX.Convolve(im, clamp);
// sobel filtering in y direction
Filter sobelY(3, 3);
sobelY(0,0) = -1.0; sobelY(1,0) = -2.0; sobelY(2,0) = -1.0;
sobelY(0,1) = 0.0; sobelY(1,1) = 0.0; sobelY(2,1) = 0.0;
sobelY(0,2) = 1.0; sobelY(1,2) = 2.0; sobelY(2,2) = 1.0;
Image imSobelY = sobelY.Convolve(im, clamp);
// squared magnitude
Image magnitude = imSobelX*imSobelX + imSobelY*imSobelY;
// take the square root
for(int i=0; i<magnitude.number_of_elements(); i++ ){
magnitude(i) = sqrt(magnitude(i));
}
return magnitude;
}
In [7]:
?reduce
Out[7]:
In [8]:
reduce(max, [x.val for x in high_energy])
In [9]:
reduce(min, [x.val for x in high_energy])
In [10]:
?imfilter
Out[10]:
In [11]:
typeof(img[1])
Out[11]:
In [22]:
σ = 3;
img_blurred = imfilter(gray_img, Kernel.gaussian(σ))
Out[22]:
is in Python, and you get a "syntax: use "^" instead of """ error if you use it =)
In [36]:
high_freq = gray_img - img_blurred
Out[36]:
In [53]:
image_sharpness = imfilter(high_freq .^ 1, Kernel.gaussian(2 * σ));
# normalize sharpness map
image_sharpness ./= maximum(image_sharpness)
Out[53]:
In [116]:
threshed = RGB.(Gray.(image_sharpness .> 0.25))
Out[116]:
In [133]:
painting = zeros(threshed);
In [134]:
painting[threshed .== RGB(1, 1, 1)] = RGB(1, 0, 0);
painting
Out[134]:
In [135]:
size(threshed)
Out[135]:
In [136]:
n = fill(false, size(threshed));
start_x = 10;
start_y = 10;
n[start_x:end, start_y:end] = (threshed .== RGB(1, 1, 1))[1:end-start_x+1, 1:end-start_y+1];
painting[n] = RGB(0, 1, 0);
painting
Out[136]:
Painting algorithm:
The entire input to the collection is how many iterations of the above steps we want to do
In [229]:
function sharpness_map(img, σ, thresh)
g = Gray.(img);
high_freq = g - imfilter(g, Kernel.gaussian(σ));
sharpness_map = imfilter(high_freq .^ 2, Kernel.gaussian(2 * σ));
# normalize sharpness map
sharpness_map ./ reduce(max, [x.val for x in sharpness_map]);
threshed = image_sharpness .> thresh;
end
Out[229]:
Julia 0.5 documentation for random numbers: http://docs.julialang.org/en/release-0.5/stdlib/numbers/#random-numbers
In [230]:
function painting_map(s_map)
size_x, size_y = size(s_map);
n = fill(false, (size_x, size_y));
x_start = rand(1:size_x);
y_start = rand(1:size_y);
x_end = rand(x_start:size_x);
y_end = rand(y_start:size_y);
n[x_start:x_end, y_start:y_end] = s_map[x_start:x_end, y_start:y_end];
return n;
end
Out[230]:
In [299]:
reference = load("obama.jpg");
size_x = size(reference, 1);
size_y = size(reference, 2);
In [301]:
painting = zeros(reference);
for i in 1:100
s_map = sharpness_map(reference, 2 * rand() + 0.5, rand() / 2);
n = painting_map(s_map);
painting[n] = rand(RGB);
end
painting
Out[301]:
In [339]:
function compute_dst_range(offset, max_val)
if offset > 0
return offset+1:max_val;
else
return 1:max_val+offset;
end
end
Out[339]:
In [340]:
function compute_src_range(offset, max_val)
return 1:max_val-abs(offset);
end
Out[340]:
In [348]:
function painting_map_offset(s_map)
size_x, size_y = size(s_map);
n = fill(false, (size_x, size_y));
multiplier = 10;
x_start = Int(round(rand(-1*size_x / multiplier:size_x / multiplier)));
y_start = Int(round(rand(-1*size_y / multiplier:size_y / multiplier)));
n[compute_dst_range(x_start, size_x),
compute_dst_range(y_start, size_y)] =
s_map[compute_src_range(x_start, size_x),
compute_src_range(y_start, size_y)];
return n;
end
Out[348]:
In [355]:
painting = zeros(reference);
for i in 1:3
s_map = sharpness_map(reference, 1.5, 0.2);
n = painting_map_offset(s_map);
painting[n] = rand(RGB);
end
painting
Out[355]: