http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=6619091&tag=1
This is about simulation of CVPR paper.
In [1]:
from PIL import Image # Load PIL(Python Image Library)
import matplotlib.pyplot as plt # Load pyplot library
import numpy as np # Load Numerical Library
import copy
import timeit
import math
import random
In [2]:
im = Image.open('road.jpg') # Load the image file
imarray = np.array(im) # Construct the array
print im.size
In [3]:
imgray = im.convert('L') # Convert the image to gray scale
plt.imshow(imgray, cmap=plt.get_cmap('gray'), interpolation='nearest') # interpolation='nearest' simply display the image without try to interpolate betwen pixels if the display resolution is not the same as the image resolution (which is most often the case). It will results in an image in which is image pixel is displayed as a square of multiple display pixels.
imgray_array = np.array(imgray) # Let imgray_array be the array of imgray.
print imgray_array # As we know, each pixels have a color value.
In [4]:
plt.hist(imgray_array.flatten(), 256, [0,256]);
In [5]:
img = imgray_array
print im.size
The Poisson parameter $\lambda_F$ which represents the expected number of junction-points is calculated as the average number of junction-points in the annotated image samples.
In [8]:
lambda_F = 10
def poisson_dist(n, lamb):
return (lamb**n*math.exp(-lamb))/math.factorial(n)
The Maximum Likelihood Estimate of each occurrence probability $p_k \in \mathcal{P}$ is given by the rate of k-junction-points in the annotated image samples.
In [8]:
Since there is no closed-form solution for the Maximum Likelihood Estimate of Dirichlet distribution, we apply a fixed-point iteration to estimate the parameter set $\alpha$[1].
[1]: Minka, Thomas P. "Estimating a Dirichlet distribution.", 2000
In [8]:
$H_w$ is estimated by counting the number of lines with different widths from the annotated image samples.
In [8]:
$\lambda_F$ is the Poisson parameter representing the expected number of junction-points in the domain $F$.
$n(x')$ is the number of jucntion-points in the proposed configuration $x'$.
$p_d$ is the probability of choosing a death.
$p_b$ is the probability of choosing a birth. In practice, $p_d=p_b=0.5$.
The translation kernel allows a junction-point to be moved without modifying the graph complexity. As the translation of a junction-point is proposed randomly, the proposition kernel ratio is simply given by $$\frac{Q_T (x'\rightarrow x)}{Q_T(x\rightarrow x')}=1$$
In [9]:
plt.imshow(img, cmap=plt.get_cmap('gray'), interpolation='nearest')
Out[9]:
In [10]:
imgy, imgx = img.shape
print imgx, imgy
total = imgx*imgy
In [11]:
from scipy.ndimage import filters
imx = np.zeros(img.shape)
imy = np.zeros(img.shape)
#filters.sobel(img, 1, imx)
$I_x$
In [12]:
for j in xrange(imgy-1):
for i in xrange(imgx-1):
imx[j,i]=img[j,i+1]-img[j,i] # delta x is 1
In [13]:
plt.imshow(imx, cmap=plt.get_cmap('gray'), interpolation='nearest')
Out[13]:
$I_y$
In [14]:
for j in xrange(imgx-1):
for i in xrange(imgy-1):
imy[i, j]=img[i+1,j]-img[i, j] # delta y is 1
In [15]:
plt.imshow(imy, cmap=plt.get_cmap('gray'), interpolation='nearest')
Out[15]:
In [16]:
img_grad = np.zeros(img.shape)
for j in xrange(imgy-1):
for i in xrange(imgx-1):
img_grad[j, i] = math.sqrt(imx[j, i]**2 + imy[j, i]**2)
In [17]:
plt.imshow(img_grad, cmap=plt.get_cmap('gray'), interpolation='nearest')
Out[17]:
In [18]:
fig, ax = plt.subplots(1, 4, figsize=(15,10))
ax[0].imshow(img, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[0].set_title('original image')
ax[1].imshow(imx, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[1].set_title('x-derivative')
ax[2].imshow(imy, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[2].set_title('y-derivative')
ax[3].imshow(img_grad, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[3].set_title('Gradient magnitude')
Out[18]:
But we use the sobel filter for the performance. http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.ndimage.filters.sobel.html
In [19]:
from scipy.ndimage import filters
imx = np.zeros(img.shape)
filters.sobel(img, 1, imx)
imy = np.zeros(img.shape)
filters.sobel(img, 0, imy)
img_grad = np.sqrt(imx**2 + imy**2)
fig, ax = plt.subplots(1, 4, figsize=(15,10))
ax[0].imshow(img, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[0].set_title('original image')
ax[1].imshow(imx, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[1].set_title('x-derivative')
ax[2].imshow(imy, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[2].set_title('y-derivative')
ax[3].imshow(img_grad, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[3].set_title('Gradient magnitude')
Out[19]:
In [20]:
plt.imshow(img_grad, cmap=plt.get_cmap('gray'), interpolation='nearest')
Out[20]:
In [21]:
plt.plot(img_grad[0]) # for first row of image
Out[21]:
So I assume that the boundary $\partial G_x$ of the line region if img_grad value is bigger than 200
In [22]:
def rand(imgx, imgy):
x = random.choice(range(imgx))
y = random.choice(range(imgy))
return x, y
========================================================================================
In [340]:
sample = 10 # the number of randomly selected points
fig, ax = plt.subplots(1,1, figsize=(5,5))
ax.set_xlim([0,300])
# ax.set_ylim([0,200])
ax.imshow(img, cmap=plt.get_cmap('gray'), interpolation='nearest')
w = []
for i in xrange(sample):
x, y = rand(imgx, imgy)
w.append([x,y])
ax.plot(x, y, '.r')
In [177]:
r = random.random()
if r>0.5:
Q = Q_BD
else:
Q = Q_T
$\lambda_F$ is the Poisson parameter representing the expected number of junction-points in the domain $F$.
$n(x')$ is the number of jucntion-points in the proposed configuration $x'$.
$p_d$ is the probability of choosing a death.
$p_b$ is the probability of choosing a birth. In practice, $p_d=p_b=0.5$.
In [417]:
def Q_BD(w):
if random.random()>0.5:
# Birth
x, y = rand(imgx, imgy)
w.append([x, y])
else:
# Death
w.pop(w.index(random.choice(w)))
return w
The translation kernel allows a junction-point to be moved without modifying the graph complexity. As the translation of a junction-point is proposed randomly, the proposition kernel ratio is simply given by $$\frac{Q_T (x'\rightarrow x)}{Q_T(x\rightarrow x')}=1$$
In [416]:
def Q_T(w):
return 1
In [418]:
n = 11 # the number of junction-points
p = float(n)/total
lambda_F = n*p
print lambda_F
$h(x)\propto h_d(x)h_p(x)$
We use the two conventional assumptions(similar colors, large gradients) to design the data consistency density $h_d$. $$h_d(x)\propto \prod_{p\in I}P(I_p | G_x )$$
In [311]:
plt.figure(figsize=(15,15))
plt.imshow(img_grad, interpolation='nearest')
Out[311]:
We must make 'Region-based intensity' and 'Boundary-based intensity'. But I don't know the algorithm. So just consider the simple approaches.
Boundary means highvalue-lowvalue-highvalue. So I will extract this pattern from each row.
In [46]:
plt.imshow(img_grad[80:100,60:80], interpolation='nearest')
Out[46]:
In [49]:
plt.plot(img_grad[80:100,60:80]);
E.g., this pattern is boundary. I consider that the region is area between boundarys. So the region [13-15] is one region.
In [52]:
plt.plot(img_grad[80:100,60:80][0]);
In [64]:
plt.plot(img_grad[80])
Out[64]:
In [342]:
row = img_grad[80]
left = row[0]
temp = []
for right in row[1:]:
if right>left and right>200: # differential > 0 and threshold of intensity
left = right
temp.append(right)
else:
left = right
temp.append(0)
plt.plot(temp)
Out[342]:
In [344]:
interval = 8 # Take the interval [pixel, pixel+interval] at each pixel
index = 0
region = np.zeros(img.shape)
for value in temp:
next_index = min(index+interval, len(temp))
test_box = []
if value != 0:
d1 = temp[index]
for d2 in temp[index+1:next_index]:
if d2 > d1:
test_box.append(1)
else:
test_box.append(0)
d1 = d2
""" Search pattern """
pattern_box = array(test_box)
pos = np.where(pattern_box == 1)[0]
if pos.size > 0:
d1 = pos[0]
ox = 0
for d2 in pos[1:]:
if d2 != d1+1:
ox = 1
d1 = d2
if ox == 1:
print index, test_box
for k in range(min(pos),max(pos)+1):
region[0, index+k] = 1
index += 1
I consider that the region is area between boundarys.
In [349]:
def region_based(interval):
threshold = 300
region = np.zeros(img.shape)
column = 0
for row in img_grad:
left = row[0]
temp = []
for right in row[1:]:
if right>left and right>threshold: # differential > 0
left = right
temp.append(right)
else:
left = right
temp.append(0)
index = 0
for value in temp:
next_index = min(index+interval, len(temp))
test_box = []
if value != 0:
d1 = temp[index]
for d2 in temp[index+1:next_index]:
if d2 > d1:
test_box.append(1)
else:
test_box.append(0)
d1 = d2
""" Search pattern """
pattern_box = array(test_box)
pos = np.where(pattern_box == 1)[0]
if pos.size > 0:
d1 = pos[0]
ox = 0
for d2 in pos[1:]:
if d2 != d1+1:
ox = 1
d1 = d2
if ox == 1:
for k in range(min(pos),max(pos)+1):
region[column, index+k] = 1
index += 1
column += 1
return region
In [350]:
fig, ax = plt.subplots(1, 4, figsize=(15,10))
ax[0].imshow(region_based(4), cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[0].set_title('Interval 4')
ax[1].imshow(region_based(5), cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[1].set_title('Interval 5')
ax[2].imshow(region_based(8), cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[2].set_title('Interval 8')
ax[3].imshow(region_based(10), cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[3].set_title('Interval 10')
Out[350]:
If we combine with "interval 4" and "interval 8" for noise remove or consider vertical direction, then more good. But there is no time. We use "interval 8" as the region-based intensity.
Compare it with original image.
In [347]:
plt.imshow(img, cmap=plt.get_cmap('gray'), interpolation='nearest')
Out[347]:
In [348]:
fig, ax = plt.subplots(1, 4, figsize=(15,10))
ax[0].imshow(img_grad>200, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[0].set_title('|gradient| > 200')
ax[1].imshow(img_grad>300, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[1].set_title('|gradient| > 300')
ax[2].imshow(img_grad>400, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[2].set_title('|gradient| > 400')
ax[3].imshow(img_grad>500, cmap=plt.get_cmap('gray'), interpolation='nearest')
ax[3].set_title('|gradient| > 500')
Out[348]:
The histograms $H_r$ is estimated by counting the number of pixels with different colors in line regions.
In [286]:
line_region = region_based(8)
In [295]:
histogram1 = np.zeros(img.shape)
index_row = 0
for row in line_region:
index_column = 0
for column in row:
if line_region[index_row, index_column] > 0:
histogram1[index_row, index_column] = img[index_row, index_column]
index_column += 1
index_row += 1
In [296]:
plt.imshow(histogram1, interpolation='nearest')
Out[296]:
In [307]:
flat = histogram1.flatten()
flat = np.delete(flat, np.where(flat == 0)) # delete 0 for distribution
line_region_dist = plt.hist(flat, 256, normed=True);
The histograms $H_n$ is estimated by counting the number of pixels with different colors in non-line regions.
In [298]:
histogram2 = np.zeros(img.shape)
index_row = 0
for row in line_region:
index_column = 0
for column in row:
if line_region[index_row, index_column] == 0:
histogram2[index_row, index_column] = img[index_row, index_column]
index_column += 1
index_row += 1
In [352]:
plt.imshow(histogram2, interpolation='nearest')
Out[352]:
In [308]:
flat = histogram2.flatten()
flat = np.delete(flat, np.where(flat == 0)) # delete 0 for distribution
nonline_region_dist = plt.hist(flat, 256, normed=True);
$I_p$ is the color intensity of the image at $p$.
The local likelihood at pixel $p$ is expressed by taking into account both color similarity on the lines and discontinuity on the line borders.
In [383]:
p=[0,0] # pixel
Ip = img[p[0], p[1]] # i_p , intensity of pixel p
In [384]:
G_x = w # Modify
In [385]:
Ip
Out[385]:
In [387]:
if line_region[p[0], p[1]] > 0:
nabla = img_grad[p]
else:
nabla = 1
if p in G_x:
"""d_inside"""
print 'inside'
dvalue = line_region_dist[0][Ip]*nabla
else:
print 'outside'
"""d_outside"""
dvalue = nonline_region_dist[0][Ip]*nabla
print "P(I_p|G_x)=", dvalue
In [404]:
def data_consistency(w, G):
result = []
for wi in w:
i, j = wi # index
Ip = img[j, i] # intensity
if line_region[j, i] > 0:
nabla = img_grad[j, i]
else:
nabla = 1
if p in G_x:
"""d_inside"""
print 'inside'
dvalue = line_region_dist[0][Ip]*nabla
else:
print 'outside'
"""d_outside"""
dvalue = nonline_region_dist[0][Ip]*nabla
result.append(dvalue)
print "P(I_p|G_x)=", dvalue
return result
In [407]:
likelihood = data_consistency(w, G_x)
So Data consistency is
In [414]:
h_d = 1
for i in likelihood:
h_d = h_d*i
print h_d
print '\nh_d = ', h_d
Three different criteria are taken into account to characterize the shape of a graph $G_x$ from a junction-point configuration $x$:
$h_p \propto h_{connectivity}(x)h_{orientation}(x)h_{width}(x)$
$h_{connectivity} (x) = \frac{(\sum_{k\geq 1}n_k)!}{\prod_{k\geq1}n_k !}\prod_{k\geq1}p_k^{n_k}$
This use Dirichlet law.
Just iterate the Algorithm.
In the top page, we already let the $X_0$.
So we iterate,
In [ ]: