This module is available here:
from IPMatrix import Matrix
These functions are used to convert bmp
/jpg
files to the matrix file format, bitmap
:
import numpy
from PIL import Image
def bitmap2image(file):
''' convert format .bitmap image to .jpg/.bmp '''
im = Matrix.load(file)
n,m = im.dim()
ar = numpy.zeros((n,m)) #an nXm array of zeros
for i in range(n):
for j in range(m):
ar[i,j] = im[i,j]
image = Image.fromarray(numpy.uint8(ar))
image.save(file.split(".")[0] + ".bmp")
def image2bitmap(file):
''' convert .jpg/.bmp file to format .bitmap
which can be loaded into class Matrix using Matrix.load() '''
image = Image.open(file).convert("L") # converts to 8 bit black and white image
im = numpy.asarray(image) # stores image in an array
im.setflags(write=1) # makes array writeable
n,m = im.shape[0], im.shape[1] # image dimensions
new_file_name = file.split(".")[0] + ".bitmap"
new_file = open(new_file_name, 'w')
print(n,m, file=new_file)
for i in range(n):
for j in range(m):
print(int(im[i,j]), end=" ", file = new_file)
print("", file=new_file)#newline
new_file.close()
Lets load an image and start working with it:
im = Matrix.load("eiffel.bitmap")
im
<IPMatrix.Matrix at 0x86c8e48>
def mult(im,k):
return im * k
mult(im, 2)
<IPMatrix.Matrix at 0x86b78d0>
def add(im, k):
n,m = im.dim()
im2 = Matrix(n,m)
for i in range(n):
for j in range(m):
im2[i,j] = (im[i,j] + k) % 256
return im2
add(im,50)
<IPMatrix.Matrix at 0x7b86320>
add(im,-50)
<IPMatrix.Matrix at 0x7b79780>
High-order functions!
def pixelwise_operation(im, op):
n,m = im.dim()
im2 = Matrix(n,m)
for i in range(n):
for j in range(m):
im2[i,j] = op(im, i, j)
return im2
def add(im, k):
op = lambda im,i,j: im[i,j] + k
return pixelwise_operation(im, op)
add(im, 100)
<IPMatrix.Matrix at 0x8832828>
secret(im) # SHHHHH, the code is below
<IPMatrix.Matrix at 0x9960470>
def secret(im):
n,m = im.dim()
im2 = Matrix(n,m)
for i in range(n):
im2.rows[i] = sorted(im.rows[i])
return im2
def negate(im):
op = lambda im,i,j: 255 - im[i,j]
return pixelwise_operation(im, op)
negate(im)
<IPMatrix.Matrix at 0x995d898>
def shift(im, v_shift, h_shift):
op = lambda im,i,j: im[(i - v_shift) % im.dim()[0], (j - h_shift) % im.dim()[1]]
return pixelwise_operation(im, op)
shift(im, 100, 0)
<IPMatrix.Matrix at 0x995d550>
shift(im, 0, 100)
<IPMatrix.Matrix at 0x995d828>
shift(im, 50, 50)
<IPMatrix.Matrix at 0x995da58>
def upside_down(im):
op = lambda im,i,j: im[im.dim()[0] - i - 1, j]
return pixelwise_operation(im, op)
upside_down(im)
<IPMatrix.Matrix at 0x99740f0>
def concatenate(im1, im2):
n1,m1 = im1.dim()
n2,m2 = im2.dim()
n = max(n1,n2)
im3 = Matrix(n,m1+m2)
im3[:n1,:m1] = im1
im3[:n2, m1:m1+m2] = im2
return im3
concatenate(im,im)
<IPMatrix.Matrix at 0xa8b0358>
def strech(im, ratio=1):
n,m = im.dim()
im2 = Matrix(n * ratio, m)
for i in range(n):
for j in range(m):
for k in range(ratio):
im2[ratio * i + k , j] = im[i,j]
return im2
strech(im,3)
<IPMatrix.Matrix at 0xa8bc0f0>
This strech just multiplies every pixel.
A better solution would be to insert the average between adjacent pixels.
The same goes for squeeze.
In class we saw two types o noises:
The basic scheme for denoising is that we change the value of each pixel wrt to the value of its neighbours using some function. The neighbors of a pixel is pixels in a square around the pixel.
method | pros | cons | works well with |
---|---|---|---|
local means | fast good on smooth areas | blurs edges affected by outliers | Gaussian noise |
local medians | preserves edges not affected by outliers | slow (median calculation) eliminates fine details (contours) | salt & pepper noise |
This image has a XxX white spot:
X = 5
im[50:50 + X,50:50 + X] = Matrix(X, X, 255)
im
<IPMatrix.Matrix at 0x85a18d0>
Which denoising method would you use to denoise it, with what neighborhood size?
To minimize the effect of the denoising on the rest of the image, we will use the local medians method.
We start by implementing a function that returns the neighborhood :
def items(mat):
lst = []
n,m = mat.dim()
for i in range(n):
lst = lst + [mat[i,j] for j in range(m)]
return lst
def median(lst):
return sorted(lst)[len(lst) // 2]
def local_medians(A, k=1):
n,m = A.dim()
res = A.copy()
for i in range(k,n-k):
for j in range(k,m-k):
neighborhood = items(A[i-k:i+k+1,j-k:j+k+1])
res[i,j] = median(neighborhood)
return res
local_medians(im)
<IPMatrix.Matrix at 0x90c34a8>
local_medians(im, k=3)
<IPMatrix.Matrix at 0x90d9358>
local_medians(im, k=5)
<IPMatrix.Matrix at 0x90d9128>
When using a small value for k
the spot is not cleaned, when using a large value the image is blurred.
When darkness/brightness is extreme (close to 0 or 255) we can do better:
def local_medians_bounded(A, k=1, black=10, white=250):
n,m = A.dim()
res1 = A.copy()
#fix white
for i in range(k,n-k):
for j in range(k,m-k):
neighborhood = items(A[i-k:i+k+1,j-k:j+k+1])
res1[i,j] = fix_white(neighborhood, white)
#fix black
res2 = res1.copy()
for i in range(k,n-k):
for j in range(k,m-k):
neighborhood = items(res1[i-k:i+k+1,j-k:j+k+1])
res2[i,j] = fix_black(neighborhood, black)
return res2
def fix_white(lst, white_thr):
center = len(lst)//2
if lst[center] > white_thr:
new_lst = [i for i in lst if i <= white_thr]
if new_lst != []:
return median(new_lst)
return lst[center] #either center was not extreme
#or all its neighbors are extreme
def fix_black(lst, black_thr):
center = len(lst)//2
if lst[center] < black_thr:
new_lst = [i for i in lst if i >= black_thr]
if new_lst != []:
return median(new_lst)
return lst[center] #either center was not extreme
#or all its neighbors are extreme
local_medians_bounded(im, k=3)
<IPMatrix.Matrix at 0x95bd4e0>
First, how do we add Salt and Pepper noise?
def add_SP(mat, p=0.01):
''' Generates salt and pepper noise: Each pixel is "hit" indep.
with prob. p. If hit, it has fifty fifty chance of becoming
white or black. '''
n,m = mat.dim()
new = Matrix(n,m)
for i in range (n):
for j in range (m):
rand = random.randint(0,20000)
if rand < p * 20000:
if rand % 2 == 1:
new[i,j] = 0
elif rand % 2 == 0:
new[i,j] = 255
else:
new[i,j] = mat[i,j]
return new
Now we load a picture of a famous person, noise it and try to denoise it:
person = Matrix.load("person.bitmap")
person_noise = add_SP(person, p=0.7)
person_noise
<IPMatrix.Matrix at 0x95ce9e8>
local_medians(person_noise)
<IPMatrix.Matrix at 0x95bd668>
person_denoised = local_medians_bounded(person_noise)
person_denoised
<IPMatrix.Matrix at 0x95c30f0>
local_medians_bounded(person_denoised)
<IPMatrix.Matrix at 0x95bd898>
Here is the original:
person
<IPMatrix.Matrix at 0x90d94e0>
This notebook is part of the Extended introduction to computer science course at Tel-Aviv University.
The notebook was written using Python 3.2 and IPython 0.13.1 with Pillow 2.0.0 and NumPy 1.7.1rc1.
The code is available at https://raw.github.com/yoavram/CS1001.py/master/recitation13.ipynb.
The notebook can be viewed online at http://nbviewer.ipython.org/urls/raw.github.com/yoavram/CS1001.py/master/recitation13.ipynb.
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.