python计算机视觉编程
python计算机视觉编程
python计算机视觉编程
0.1
0.2 Python(x,y)
0.3 PCV
0.4 VLfeat
0.1
0.2 Python(x,y)
from cv2 import __version__
__version__
OpenCV python(x,y)
0.3 PCV
PCV
Windows cmd PCV
cd PCV
python setup.py install
PCV
0.4 VLfeat
VLFeat,
def process_image(imagename,resultname,params="‐‐edge‐thresh 10 ‐‐peak‐thresh 5"):
""" process an image and save the results in a file"""
if imagename[‐3:] != 'pgm':
#create a pgm file
im = Image.open(imagename).convert('L')
im.save('tmp.pgm')
imagename = 'tmp.pgm'
cmmd = str("D:\mltools\win32vlfeat\sift.exe "+imagename+" ‐‐output="+resultname+
" "+params)
os.system(cmmd)
print 'processed', imagename, 'to', resultname
“ ”
« (author.html) » (chapter1.html)
() ()
1.1 PIL-Python
1.1.1
1.1.2
1.1.3
1.1.4
1.2 Matplotlib
1.2.1
1.2.2
1.2.4
1.3 NumPy
1.3.1
1.3.2
1.3-3
1.3.3
1.3.4
1.3.5
1.3.6 Pickle
1.4 SciPy
1.4.1
1.4.2
1.4.3 -
1.4.4 SciPy
1.5
1.1 PIL-Python
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
figure()
pil_im = Image.open('../data/empire.jpg')
gray()
subplot(121)
title(u'原图',fontproperties=font)
axis('off')
imshow(pil_im)
pil_im = Image.open('../data/empire.jpg').convert('L')
subplot(122)
title(u'灰度图',fontproperties=font)
axis('off')
imshow(pil_im)
show()
P002-Fig1-1
1.1.1
filelist = get_imlist('../data/convert_images_format_test/') #获取convert_images_format_test文件夹
下的图片文件名(包括后缀名)
imlist = file('../data/convert_images_format_test/imlist.txt','w') #将获取的图片文件列表保存到
imlist.txt中
pickle.dump(filelist,imlist) #序列化
imlist.close()
for infile in filelist:
outfile = os.path.splitext(infile)[0] + ".png" #分离文件名与扩展名
if infile != outfile:
try:
Image.open(infile).save(outfile)
except IOError:
print "cannot convert", infile
convertimagesformat_test 24 .jpg
.png
PCV PCV [PCV ] ()
1.1.2
PIL thumnail()
1.1.3
crop()
1.1.4
resize()
rotate()
RGB
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
figure()
# 显示原图
pil_im = Image.open('../data/empire.jpg')
print pil_im.mode, pil_im.size, pil_im.format
subplot(231)
title(u'原图', fontproperties=font)
axis('off')
imshow(pil_im)
# 显示灰度图
pil_im = Image.open('../data/empire.jpg').convert('L')
gray()
subplot(232)
title(u'灰度图', fontproperties=font)
axis('off')
imshow(pil_im)
#拷贝粘贴区域
pil_im = Image.open('../data/empire.jpg')
box = (100,100,400,400)
region = pil_im.crop(box)
region = region.transpose(Image.ROTATE_180)
pil_im.paste(region,box)
subplot(233)
title(u'拷贝粘贴区域', fontproperties=font)
axis('off')
imshow(pil_im)
# 缩略图
pil_im = Image.open('../data/empire.jpg')
size = 128, 128
pil_im.thumbnail(size)
print pil_im.size
subplot(234)
title(u'缩略图', fontproperties=font)
axis('off')
imshow(pil_im)
pil_im.save('../images/ch01/thumbnail.jpg') #保存缩略图
# 调整图像尺寸
pil_im = Image.open('../data/empire.jpg')
pil_im = pil_im.resize(size)
print pil_im.size
subplot(235)
title(u'调整尺寸后的图像', fontproperties=font)
axis('off')
imshow(pil_im)
# 旋转图像45°
pil_im = Image.open('../data/empire.jpg')
pil_im = pil_im.rotate(45)
subplot(236)
title(u'旋转45°后的图像', fontproperties=font)
axis('off')
imshow(pil_im)
show()
1.2 Matplotlib
Matplotlib PIL
Matplotlib [matplotlib.sourceforge.net] (http://matplotlib.sourceforge.net/)
1.2.1
Matplotlib
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
im = array(Image.open('../data/empire.jpg'))
figure()
# 画有坐标轴的
subplot(121)
imshow(im)
x = [100, 100, 400, 400]
y = [200, 500, 200, 500]
plot(x, y, 'r*')
plot(x[:2], y[:2])
title(u'绘图: "empire.jpg"', fontproperties=font)
# 不显示坐标轴
subplot(122)
imshow(im)
x = [100, 100, 400, 400]
y = [200, 500, 200, 500]
plot(x, y, 'r*')
plot(x[:2], y[:2])
axis('off') #显示坐标轴
title(u'绘图: "empire.jpg"', fontproperties=font)
show()
[x,y]
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
im = array(Image.open('../data/empire.jpg').convert('L')) # 打开图像 并转成灰度图像
figure()
subplot(121)
gray()
contour(im, origin='image')
axis('equal')
axis('off')
title(u'图像轮廓', fontproperties=font)
subplot(122)
hist(im.flatten(), 128)
title(u'图像直方图', fontproperties=font)
plt.xlim([0,260])
plt.ylim([0,11000])
show()
1-3 :
1.2.4
PyLab
ginput(),
from PIL import Image
from pylab import *
im = array(Image.open('../data/empire.jpg'))
imshow(im)
print 'Please click 3 points'
imshow(im)
x = ginput(3)
print 'You clicked:', x
show()
empire.jpg ginput() 3
1.3 NumPy
1.3.1
array() NumPy
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from pylab import *
im = array(Image.open('../data/empire.jpg'))
print im.shape, im.dtype
im = array(Image.open('../data/empire.jpg').convert('L'),'f')
print im.shape, im.dtype
(800, 569, 3) uint8
(800, 569) float32
value=im[i,j,k] i,j k
im[i,:] = im[j,:] # set the values of row i with values from row j
im[:,i] = 100 # set all values in column i to 100
im[:100,:50].sum() # the sum of the values of the first 100 rows and 50 columns
im[50:100,50:100] # rows 50‐100, columns 50‐100 (100th not included)
im[i].mean() # average of row i
im[:,‐1] # last column
im[‐2,:] (or im[‐2]) # second to last row
1.3.2
NumPy
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from numpy import *
from pylab import *
im = array(Image.open('../data/empire.jpg').convert('L'))
print int(im.min()), int(im.max())
im2 = 255 ‐ im # invert image
print int(im2.min()), int(im2.max())
im3 = (100.0/255) * im + 100 # clamp to interval 100...200
print int(im3.min()), int(im3.max())
im4 = 255.0 * (im/255.0)**2 # squared
print int(im4.min()), int(im4.max())
figure()
gray()
subplot(1, 3, 1)
imshow(im2)
axis('off')
title(r'$f(x)=255‐x$')
subplot(1, 3, 2)
imshow(im3)
axis('off')
title(r'$f(x)=\frac{100}{255}x+100$')
subplot(1, 3, 3)
imshow(im4)
axis('off')
title(r'$f(x)=255(\frac{x}{255})^2$')
show()
2 255
0 253
100 200
0 255
1.3-3
NumPy PIL
def imresize(im,sz):
""" Resize an image array using PIL. """
pil_im = Image.fromarray(uint8(im))
return array(pil_im.resize(sz))
imtools.py
1.3.3
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from pylab import *
from PCV.tools import imtools
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
im = array(Image.open('../data/empire.jpg').convert('L')) # 打开图像 并转成灰度图像
#im = array(Image.open('../data/AquaTermi_lowcontrast.JPG').convert('L'))
im2, cdf = imtools.histeq(im)
figure()
subplot(2, 2, 1)
axis('off')
gray()
title(u'原始图像', fontproperties=font)
imshow(im)
subplot(2, 2, 2)
axis('off')
title(u'直方图均衡化后的图像', fontproperties=font)
imshow(im2)
subplot(2, 2, 3)
axis('off')
title(u'原始直方图', fontproperties=font)
#hist(im.flatten(), 128, cumulative=True, normed=True)
hist(im.flatten(), 128, normed=True)
subplot(2, 2, 4)
axis('off')
title(u'均衡化后的直方图', fontproperties=font)
#hist(im2.flatten(), 128, cumulative=True, normed=True)
hist(im2.flatten(), 128, normed=True)
show()
1.3.4
# ‐*‐ coding: utf‐8 ‐*‐
from PCV.tools.imtools import get_imlist
from PIL import Image
from pylab import *
from PCV.tools import imtools
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
filelist = get_imlist('../data/avg/') #获取convert_images_format_test文件夹下的图片文件名(包括后缀
名)
avg = imtools.compute_average(filelist)
for impath in filelist:
im1 = array(Image.open(impath))
subplot(2, 2, filelist.index(impath)+1)
imshow(im1)
imNum=str(filelist.index(impath)+1)
title(u'待平均图像'+imNum, fontproperties=font)
axis('off')
subplot(2, 2, 4)
imshow(avg)
title(u'平均后的图像', fontproperties=font)
axis('off')
show()
3
1.3.5
# Uses sparse pca codepath.
#imlist = imtools.get_imlist('../data/selectedfontimages/a_selected_thumbs')
# 获取图像列表和他们的尺寸
imlist = imtools.get_imlist('../data/fontimages/a_thumbs') # fontimages.zip is part of the book
data set
im = array(Image.open(imlist[0])) # open one image to get the size
m, n = im.shape[:2] # get the size of the images
imnbr = len(imlist) # get the number of images
print "The number of images is %d" % imnbr
# Create matrix to store all flattened images
immatrix = array([array(Image.open(imname)).flatten() for imname in imlist], 'f')
# PCA降维
V, S, immean = pca.pca(immatrix)
# 保存均值和主成分
#f = open('../ch01/font_pca_modes.pkl', 'wb')
#pickle.dump(immean,f)
#pickle.dump(V,f)
#f.close()
# Show the images (mean and 7 first modes)
# This gives figure 1‐8 (p15) in the book.
figure()
gray()
subplot(2, 4, 1)
axis('off')
imshow(immean.reshape(m, n))
for i in range(7):
subplot(2, 4, i+2)
imshow(V[i].reshape(m, n))
axis('off')
show()
pickle Pickle
Python
f = open('../data/fontimages/font_pca_modes.pkl', 'wb')
pickle.dump(immean,f)
pickle.dump(V,f)
f.close()
# load mean and principal components
f = open('../data/fontimages/font_pca_modes.pkl', 'rb')
immean = pickle.load(f)
V = pickle.load(f)
f.close()
with() pickle
[[docs.python.org/library/pickle.html⧵]](http://docs.python.org/library/pickle.html)
1.4 SciPy
1.4.1
P017 Fig1-9
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from pylab import *
from scipy.ndimage import filters
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
#im = array(Image.open('board.jpeg'))
im = array(Image.open('../data/empire.jpg').convert('L'))
figure()
gray()
axis('off')
subplot(1, 4, 1)
axis('off')
title(u'原图', fontproperties=font)
imshow(im)
for bi, blur in enumerate([2, 5, 10]):
im2 = zeros(im.shape)
im2 = filters.gaussian_filter(im, blur)
im2 = np.uint8(im2)
imNum=str(blur)
subplot(1, 4, 2 + bi)
axis('off')
title(u'标准差为'+imNum, fontproperties=font)
imshow(im2)
#如果是彩色图像 则分别对三个通道进行模糊
#for bi, blur in enumerate([2, 5, 10]):
# im2 = zeros(im.shape)
# for i in range(3):
# im2[:, :, i] = filters.gaussian_filter(im[:, :, i], blur)
# im2 = np.uint8(im2)
# subplot(1, 4, 2 + bi)
# axis('off')
# imshow(im2)
show()
P017 Fig1-9
2 5
10 SciPy scipy.ndimage
[docs.scipy.org/doc/scipy/reference/ndimage.html] (http://docs.scipy.org/doc/scipy/reference/ndimage.html)
1.4.2
P019
Fig1-10
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from pylab import *
from scipy.ndimage import filters
import numpy
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
im = array(Image.open('../data/empire.jpg').convert('L'))
gray()
subplot(1, 4, 1)
axis('off')
title(u'(a)原图', fontproperties=font)
imshow(im)
# Sobel derivative filters
imx = zeros(im.shape)
filters.sobel(im, 1, imx)
subplot(1, 4, 2)
axis('off')
title(u'(b)x方向差分', fontproperties=font)
imshow(imx)
imy = zeros(im.shape)
filters.sobel(im, 0, imy)
subplot(1, 4, 3)
axis('off')
title(u'(c)y方向差分', fontproperties=font)
imshow(imy)
#mag = numpy.sqrt(imx**2 + imy**2)
mag = 255‐numpy.sqrt(imx**2 + imy**2)
subplot(1, 4, 4)
title(u'(d)梯度幅度', fontproperties=font)
axis('off')
imshow(mag)
show()
P019 Fig1-10
P020 Fig1-11
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from pylab import *
from scipy.ndimage import filters
import numpy
# 添加中文字体支持
#from matplotlib.font_manager import FontProperties
#font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
def imx(im, sigma):
imgx = zeros(im.shape)
filters.gaussian_filter(im, sigma, (0, 1), imgx)
return imgx
def imy(im, sigma):
imgy = zeros(im.shape)
filters.gaussian_filter(im, sigma, (1, 0), imgy)
return imgy
def mag(im, sigma):
# there's also gaussian_gradient_magnitude()
#mag = numpy.sqrt(imgx**2 + imgy**2)
imgmag = 255 ‐ numpy.sqrt(imgx ** 2 + imgy ** 2)
return imgmag
im = array(Image.open('../data/empire.jpg').convert('L'))
figure()
gray()
sigma = [2, 5, 10]
for i in sigma:
subplot(3, 4, 4*(sigma.index(i))+1)
axis('off')
imshow(im)
imgx=imx(im, i)
subplot(3, 4, 4*(sigma.index(i))+2)
axis('off')
imshow(imgx)
imgy=imy(im, i)
subplot(3, 4, 4*(sigma.index(i))+3)
axis('off')
imshow(imgy)
imgmag=mag(im, i)
subplot(3, 4, 4*(sigma.index(i))+4)
axis('off')
imshow(imgmag)
show()
P020 Fig1-11 2 x y
mag,
1.4.3 -
0 1
wiki[en.wikipedia.org/wiki/Mathematical_morphology] (http://en.wikipedia.org/wiki/Mathematical_morphology)
sci.ndimage morphology
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from numpy import *
from scipy.ndimage import measurements, morphology
from pylab import *
""" This is the morphology counting objects example in Section 1.4. """
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
# load image and threshold to make sure it is binary
figure()
gray()
im = array(Image.open('../data/houses.png').convert('L'))
subplot(221)
imshow(im)
axis('off')
title(u'原图', fontproperties=font)
im = (im < 128)
labels, nbr_objects = measurements.label(im)
print "Number of objects:", nbr_objects
subplot(222)
imshow(labels)
axis('off')
title(u'标记后的图', fontproperties=font)
# morphology ‐ opening to separate objects better
im_open = morphology.binary_opening(im, ones((9, 5)), iterations=2)
subplot(223)
imshow(im_open)
axis('off')
title(u'开运算后的图像', fontproperties=font)
labels_open, nbr_objects_open = measurements.label(im_open)
print "Number of objects:", nbr_objects_open
subplot(224)
imshow(labels_open)
axis('off')
title(u'开运算后进行标记后的图像', fontproperties=font)
show()
P022 Fig1-12
Number of objects: 45
Number of objects: 48
scipy.ndimage [docs.scipy.org/doc/scipy/reference/ndimage.html]
(http://docs.scipy.org/doc/scipy/reference/ndimage.html)
1.4.4 SciPy
SciPy io misc
.mat
data = scipy.io.loadmat('test.mat')
.mat
savemat()
#创建字典
data = {}
#将变量x保存在字典中
data['x'] = x
scipy.io.savemat('test.mat',data)
scipy.io [docs.scipy.org/doc/scipy/reference/io.html]
(http://docs.scipy.org/doc/scipy/reference/io.html)
scipy.misc imsave()
from scipy.misc import imsave
imsave('test.jpg',im)
scipy.misc "Lena"
lena = scipy.misc.lena()
lena 512*512
1.5
Rudin-Osher-Fatemi de-noising(ROF)
# ‐*‐ coding: utf‐8 ‐*‐
from pylab import *
from numpy import *
from numpy import random
from scipy.ndimage import filters
from scipy.misc import imsave
from PCV.tools import rof
""" This is the de‐noising example using ROF in Section 1.5. """
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
# create synthetic image with noise
im = zeros((500,500))
im[100:400,100:400] = 128
im[200:300,200:300] = 255
im = im + 30*random.standard_normal((500,500))
U,T = rof.denoise(im,im)
G = filters.gaussian_filter(im,10)
# save the result
#imsave('synth_original.pdf',im)
#imsave('synth_rof.pdf',U)
#imsave('synth_gaussian.pdf',G)
# plot
figure()
gray()
subplot(1,3,1)
imshow(im)
#axis('equal')
axis('off')
title(u'原噪声图像', fontproperties=font)
subplot(1,3,2)
imshow(G)
#axis('equal')
axis('off')
title(u'高斯模糊后的图像', fontproperties=font)
subplot(1,3,3)
imshow(U)
#axis('equal')
axis('off')
title(u'ROF降噪后的图像', fontproperties=font)
show()
P025 Fig1-13
10 ROF
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from pylab import *
from numpy import *
from numpy import random
from scipy.ndimage import filters
from scipy.misc import imsave
from PCV.tools import rof
""" This is the de‐noising example using ROF in Section 1.5. """
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
im = array(Image.open('../data/empire.jpg').convert('L'))
U,T = rof.denoise(im,im)
G = filters.gaussian_filter(im,10)
# save the result
#imsave('synth_original.pdf',im)
#imsave('synth_rof.pdf',U)
#imsave('synth_gaussian.pdf',G)
# plot
figure()
gray()
subplot(1,3,1)
imshow(im)
#axis('equal')
axis('off')
title(u'原噪声图像', fontproperties=font)
subplot(1,3,2)
imshow(G)
#axis('equal')
axis('off')
title(u'高斯模糊后的图像', fontproperties=font)
subplot(1,3,3)
imshow(U)
#axis('equal')
axis('off')
title(u'ROF降噪后的图像', fontproperties=font)
show()
P026 Fig1-14
ROF
« (installation.html) » (chapter2.html)
() ()
2.1 Harris
2.1.2
2.2 sift
2.2.1
2.2.2
2.2.3
2.2.4
2.3
2.3.1 Panoramio
2.3.2
2.3.3
2.1 Harris
"""
Example of detecting Harris corner points (Figure 2‐1 in the book).
"""
# 读入图像
im = array(Image.open('../data/empire.jpg').convert('L'))
# 检测harris角点
harrisim = harris.compute_harris_response(im)
# Harris响应函数
harrisim1 = 255 ‐ harrisim
figure()
gray()
#画出Harris响应图
subplot(141)
imshow(harrisim1)
print harrisim1.shape
axis('off')
axis('equal')
threshold = [0.01, 0.05, 0.1]
for i, thres in enumerate(threshold):
filtered_coords = harris.get_harris_points(harrisim, 6, thres)
subplot(1, 4, i+2)
imshow(im)
print im.shape
plot([p[1] for p in filtered_coords], [p[0] for p in filtered_coords], '*')
axis('off')
#原书采用的PCV中PCV harris模块
#harris.plot_harris_points(im, filtered_coords)
# plot only 200 strongest
# harris.plot_harris_points(im, filtered_coords[:200])
show()
P32 :
Harris WIKI
WIKI (http://en.wikipedia.org/wiki/Corner_detection).
2.1.2
Harris
P35
# ‐*‐ coding: utf‐8 ‐*‐
from pylab import *
from PIL import Image
from PCV.localdescriptors import harris
from PCV.tools.imtools import imresize
"""
This is the Harris point matching example in Figure 2‐2.
"""
# Figure 2‐2上面的图
#im1 = array(Image.open("../data/crans_1_small.jpg").convert("L"))
#im2= array(Image.open("../data/crans_2_small.jpg").convert("L"))
# Figure 2‐2下面的图
im1 = array(Image.open("../data/sf_view1.jpg").convert("L"))
im2 = array(Image.open("../data/sf_view2.jpg").convert("L"))
# resize加快匹配速度
im1 = imresize(im1, (im1.shape[1]/2, im1.shape[0]/2))
im2 = imresize(im2, (im2.shape[1]/2, im2.shape[0]/2))
wid = 5
harrisim = harris.compute_harris_response(im1, 5)
filtered_coords1 = harris.get_harris_points(harrisim, wid+1)
d1 = harris.get_descriptors(im1, filtered_coords1, wid)
harrisim = harris.compute_harris_response(im2, 5)
filtered_coords2 = harris.get_harris_points(harrisim, wid+1)
d2 = harris.get_descriptors(im2, filtered_coords2, wid)
print 'starting matching'
matches = harris.match_twosided(d1, d2)
figure()
gray()
harris.plot_matches(im1, im2, filtered_coords1, filtered_coords2, matches)
show()
——SIFT
2.2 sift
2.2.1
2.2.2
2.2.3
SIFT VLFeat Python SIFT
VLFeat www.vlfeat.org (http://www.vlfeat.org/)
C Matlab P40
# ‐*‐ coding: utf‐8 ‐*‐
from PIL import Image
from pylab import *
from PCV.localdescriptors import sift
from PCV.localdescriptors import harris
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
imname = '../data/empire.jpg'
im = array(Image.open(imname).convert('L'))
sift.process_image(imname, 'empire.sift')
l1, d1 = sift.read_features_from_file('empire.sift')
figure()
gray()
subplot(131)
sift.plot_features(im, l1, circle=False)
title(u'SIFT特征',fontproperties=font)
subplot(132)
sift.plot_features(im, l1, circle=True)
title(u'用圆圈表示SIFT特征尺度',fontproperties=font)
# 检测harris角点
harrisim = harris.compute_harris_response(im)
subplot(133)
filtered_coords = harris.get_harris_points(harrisim, 6, 0.1)
imshow(im)
plot([p[1] for p in filtered_coords], [p[0] for p in filtered_coords], '*')
axis('off')
title(u'Harris角点',fontproperties=font)
show()
sift Harris Harris
2.2.4
from PIL import Image
from pylab import *
import sys
from PCV.localdescriptors import sift
if len(sys.argv) >= 3:
im1f, im2f = sys.argv[1], sys.argv[2]
else:
# im1f = '../data/sf_view1.jpg'
# im2f = '../data/sf_view2.jpg'
im1f = '../data/crans_1_small.jpg'
im2f = '../data/crans_2_small.jpg'
# im1f = '../data/climbing_1_small.jpg'
# im2f = '../data/climbing_2_small.jpg'
im1 = array(Image.open(im1f))
im2 = array(Image.open(im2f))
sift.process_image(im1f, 'out_sift_1.txt')
l1, d1 = sift.read_features_from_file('out_sift_1.txt')
figure()
gray()
subplot(121)
sift.plot_features(im1, l1, circle=False)
sift.process_image(im2f, 'out_sift_2.txt')
l2, d2 = sift.read_features_from_file('out_sift_2.txt')
subplot(122)
sift.plot_features(im2, l2, circle=False)
#matches = sift.match(d1, d2)
matches = sift.match_twosided(d1, d2)
print '{} matches'.format(len(matches.nonzero()[0]))
figure()
gray()
sift.plot_matches(im1, im2, l1, l2, matches, show_below=True)
show()
2.3
2.3.1 Panoramio
# ‐*‐ coding: utf‐8 ‐*‐
import json
import os
import urllib
import urlparse
from PCV.tools.imtools import get_imlist
from pylab import *
from PIL import Image
#change the longitude and latitude here
#here is the longitude and latitude for Oriental Pearl
minx = '‐77.037564'
maxx = '‐77.035564'
miny = '38.896662'
maxy = '38.898662'
#number of photos
numfrom = '0'
numto = '20'
url = 'http://www.panoramio.com/map/get_panoramas.php?order=popularity&set=public&from=' +
numfrom + '&to=' + numto + '&minx=' + minx + '&miny=' + miny + '&maxx=' + maxx + '&maxy=' + maxy
+ '&size=medium'
#this is the url configured for downloading whitehouse photos. Uncomment this, run and see.
#url = 'http://www.panoramio.com/map/get_panoramas.php?order=popularity&\
#set=public&from=0&to=20&minx=‐77.037564&miny=38.896662&\
#maxx=‐77.035564&maxy=38.898662&size=medium'
c = urllib.urlopen(url)
j = json.loads(c.read())
imurls = []
for im in j['photos']:
imurls.append(im['photo_file_url'])
for url in imurls:
image = urllib.URLopener()
image.retrieve(url, os.path.basename(urlparse.urlparse(url).path))
print 'downloading:', url
#显示下载到的20幅图像
figure()
gray()
filelist = get_imlist('./')
for i, imlist in enumerate(filelist):
im=Image.open(imlist)
subplot(4,5,i+1)
imshow(im)
axis('off')
show()
numto 20
20
2.3.2
SIFT
# ‐*‐ coding: utf‐8 ‐*‐
from pylab import *
from PIL import Image
from PCV.localdescriptors import sift
from PCV.tools import imtools
import pydot
""" This is the example graph illustration of matching images from Figure 2‐10.
To download the images, see ch2_download_panoramio.py."""
#download_path = "panoimages" # set this to the path where you downloaded the panoramio images
#path = "/FULLPATH/panoimages/" # path to save thumbnails (pydot needs the full system path)
download_path = "F:/dropbox/Dropbox/translation/pcv‐notebook/data/panoimages" # set this to the
path where you downloaded the panoramio images
path = "F:/dropbox/Dropbox/translation/pcv‐notebook/data/panoimages/" # path to save thumbnails
(pydot needs the full system path)
# list of downloaded filenames
imlist = imtools.get_imlist(download_path)
nbr_images = len(imlist)
# extract features
featlist = [imname[:‐3] + 'sift' for imname in imlist]
for i, imname in enumerate(imlist):
sift.process_image(imname, featlist[i])
matchscores = zeros((nbr_images, nbr_images))
for i in range(nbr_images):
for j in range(i, nbr_images): # only compute upper triangle
print 'comparing ', imlist[i], imlist[j]
l1, d1 = sift.read_features_from_file(featlist[i])
l2, d2 = sift.read_features_from_file(featlist[j])
matches = sift.match_twosided(d1, d2)
nbr_matches = sum(matches > 0)
print 'number of matches = ', nbr_matches
matchscores[i, j] = nbr_matches
print "The match scores is: \n", matchscores
# copy values
for i in range(nbr_images):
for j in range(i + 1, nbr_images): # no need to copy diagonal
matchscores[j, i] = matchscores[i, j]
matchscores “
”
662 0 0 2 0 0 0 0 1 0 0 1 2 0 3 0 19 1 0 2
0 901 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 2
0 0 266 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
2 1 0 1481 0 0 2 2 0 0 0 2 2 0 0 0 2 3 2 0
0 0 0 0 1748 0 0 1 0 0 0 0 0 2 0 0 0 0 0 1
0 0 0 0 0 1747 0 0 1 0 0 0 0 0 0 0 0 1 1 0
0 0 0 2 0 0 555 0 0 0 1 4 4 0 2 0 0 5 1 0
0 1 0 2 1 0 0 2206 0 0 0 1 0 0 1 0 2 0 1 1
1 1 0 0 0 1 0 0 629 0 0 0 0 0 0 0 1 0 0 20
0 0 0 0 0 0 0 0 0 829 0 0 1 0 0 0 0 0 0 2
0 0 0 0 0 0 1 0 0 0 1025 0 0 0 0 0 1 1 1 0
1 1 0 2 0 0 4 1 0 0 0 528 5 2 15 0 3 6 0 0
2 0 0 2 0 0 4 0 0 1 0 5 736 1 4 0 3 37 1 0
0 0 1 0 2 0 0 0 0 0 0 2 1 620 1 0 0 1 0 0
3 0 0 0 0 0 2 1 0 0 0 15 4 1 553 0 6 9 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2273 0 1 0 0
19 0 0 2 0 0 0 2 1 0 1 3 3 0 6 0 542 0 0 0
1 0 0 3 0 1 5 0 0 0 1 6 37 1 9 1 0 527 3 0
0 1 0 2 0 1 1 1 0 0 1 0 1 0 1 0 0 3 1139 0
2 2 0 0 1 0 0 1 20 2 0 0 0 0 0 0 0 0 0 499
2.3.3
Pydot
import pydot
g = pydot.Dot(graph_type='graph')
g.add_node(pydot.Node(str(0), fontcolor='transparent'))
for i in range(5):
g.add_node(pydot.Node(str(i + 1)))
g.add_edge(pydot.Edge(str(0), str(i + 1)))
for j in range(5):
g.add_node(pydot.Node(str(j + 1) + '0' + str(i + 1)))
g.add_edge(pydot.Edge(str(j + 1) + '0' + str(i + 1), str(j + 1)))
g.write_png('../images/ch02/ch02_fig2‐9_graph.png', prog='neato')
images/ch02/ ch02fig2-9graph
100*100
# ‐*‐ coding: utf‐8 ‐*‐
from pylab import *
from PIL import Image
from PCV.localdescriptors import sift
from PCV.tools import imtools
import pydot
""" This is the example graph illustration of matching images from Figure 2‐10.
To download the images, see ch2_download_panoramio.py."""
#download_path = "panoimages" # set this to the path where you downloaded the panoramio images
#path = "/FULLPATH/panoimages/" # path to save thumbnails (pydot needs the full system path)
download_path = "F:/dropbox/Dropbox/translation/pcv‐notebook/data/panoimages" # set this to the
path where you downloaded the panoramio images
path = "F:/dropbox/Dropbox/translation/pcv‐notebook/data/panoimages/" # path to save thumbnails
(pydot needs the full system path)
# list of downloaded filenames
imlist = imtools.get_imlist(download_path)
nbr_images = len(imlist)
# extract features
featlist = [imname[:‐3] + 'sift' for imname in imlist]
for i, imname in enumerate(imlist):
sift.process_image(imname, featlist[i])
matchscores = zeros((nbr_images, nbr_images))
for i in range(nbr_images):
for j in range(i, nbr_images): # only compute upper triangle
print 'comparing ', imlist[i], imlist[j]
l1, d1 = sift.read_features_from_file(featlist[i])
l2, d2 = sift.read_features_from_file(featlist[j])
matches = sift.match_twosided(d1, d2)
nbr_matches = sum(matches > 0)
print 'number of matches = ', nbr_matches
matchscores[i, j] = nbr_matches
print "The match scores is: \n", matchscores
# copy values
for i in range(nbr_images):
for j in range(i + 1, nbr_images): # no need to copy diagonal
matchscores[j, i] = matchscores[i, j]
#可视化
threshold = 2 # min number of matches needed to create link
g = pydot.Dot(graph_type='graph') # don't want the default directed graph
for i in range(nbr_images):
for j in range(i + 1, nbr_images):
if matchscores[i, j] > threshold:
# first image in pair
im = Image.open(imlist[i])
im.thumbnail((100, 100))
filename = path + str(i) + '.png'
im.save(filename) # need temporary files of the right size
g.add_node(pydot.Node(str(i), fontcolor='transparent', shape='rectangle',
image=filename))
# second image in pair
im = Image.open(imlist[j])
im.thumbnail((100, 100))
filename = path + str(j) + '.png'
im.save(filename) # need temporary files of the right size
g.add_node(pydot.Node(str(j), fontcolor='transparent', shape='rectangle',
image=filename))
g.add_edge(pydot.Edge(str(i), str(j)))
g.write_png('whitehouse.png')
() ()
3.1
58
# ‐*‐ coding: utf‐8 ‐*‐
from scipy import ndimage
from PIL import Image
from pylab import *
im = array(Image.open('../data/empire.jpg').convert('L'))
H = array([[1.4,0.05,‐100],[0.05,1.5,‐100],[0,0,1]])
im2 = ndimage.affine_transform(im,H[:2,:2],(H[0,2],H[1,2]))
figure()
gray()
subplot(121)
axis('off')
imshow(im)
subplot(122)
axis('off')
imshow(im2)
show()
——
automated testing
refactor
Rails sample_app
$ cd ~/rails_projects
$ rails new sample_app ‐‐skip‐test‐unit
$ cd sample_app
3.1 Gemfile
source 'https://rubygems.org'
gem 'rails', '3.2.13'
group :development, :test do
gem 'sqlite3', '1.3.5'
gem 'rspec‐rails', '2.11.0'
end
# Gems used only for assets and not required
# in production environments by default.
group :assets do
gem 'sass‐rails', '3.2.5'
gem 'coffee‐rails', '3.2.2'
gem 'uglifier', '1.2.3'
end
gem 'jquery‐rails', '2.0.2'
group :test do
gem 'capybara', '1.1.2'
end
group :production do
gem 'pg', '0.12.2'
end
rspec-rails RSpec
RSpec rspec-rails dependency
Capybara (https://github.com/jnicklas/capybara) gem
1 (chapter2.html) PostgreSQL gem
Heroku
group :production do
gem 'pg', '0.12.2'
end
$ bundle install ‐‐without production
-without production gem
Bundler bundle install 2
$ rails generate rspec:install
Git 3
$ git init
$ git add .
$ git commit ‐m "Initial commit"
README 3.2
3.2 README
# Ruby on Rails Tutorial: sample application
This is the sample application for
[*Ruby on Rails Tutorial: Learn Rails by Example*](http://railstutorial.org/)
by [Michael Hartl](http://michaelhartl.com/).
.md Markdown
$ git mv README.rdoc README.md
$ git commit ‐a ‐m "Improve the README"
create_repository_new
3.1 GitHub
GitHub 3.1
$ git remote add origin git@github.com:<username>/sample_app.git
$ git push ‐u origin master
GitHub
4
(https://github.com/railstutorial/sample_app_2nd_ed)
Heroku
$ heroku create ‐‐stack cedar
$ git push heroku master
$ git push
$ git push heroku
Heroku
$ heroku logs
3.1
IDE Rails
Unix .
$ cd ~/rails_projects/sample_app
$ <editor name> .
Sublime Text
$ subl .
3.1.1
public_index_rails_3
3.2 public/index.html
public/index.html 3.2
5
Rails public
index.html URI URI
http://localhost:3000/ http://localhost:3000/index.html
HTML index.html public
6
3.3
$ subl public/hello.html
3.3 HTML
public/hello.html
<!DOCTYPE html>
<html>
<head>
<title>Greeting</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
$ rails server
hello_world
3.3 HTML
$ rm public/hello.html
3.1.2 Rails
HTML Web
Rails action URI 8 Rails
$ git checkout ‐b static‐pages
$ rails generate rspec:install
StaticPages “ ” Home “
” Help “ ” About generate
3.4
3.4 StaticPages
$ rails generate controller StaticPages home help ‐‐no‐test‐framework
create app/controllers/static_pages_controller.rb
route get "static_pages/help"
route get "static_pages/home"
invoke erb
create app/views/static_pages
create app/views/static_pages/home.html.erb
create app/views/static_pages/help.html.erb
invoke helper
create app/helpers/static_pages_helper.rb
invoke assets
invoke coffee
create app/assets/javascripts/static_pages.js.coffee
invoke scss
create app/assets/stylesheets/static_pages.css.scss
3.1 Rails
3.1
Rails Rails
Rails 3.4
routes.rb Rails rails
destroy
(chapter6.html)
(chapter6.html)
(chapter2.html) (chapter6.html)
$ rake db:migrate
$ rake db:rollback
snafu (http://en.wikipedia.org/wiki/SNAFU)
config_directory_rails_3
3.4 config
get "static_pages/home"
3.2 GET
StaticPages 3.6
Users Microposts StaticPages REST
REST
def home
end
def help
end
end
StaticPages
def home
end
def help
end
3.4 home
home.html.erb 3.3 .erb .html HTML
3.7
3.7 “ ”
app/views/static_pages/home.html.erb
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
help 3.8
3.8 “ ”
app/views/static_pages/help.html.erb
<h1>StaticPages#help</h1>
<p>Find me in app/views/static_pages/help.html.erb</p>
h1 p
3.3 Rails
HTML 3.1.1 HTML
HTML
“ ” “ ” 3.1.2 “ ”
Git StaticPages
$ git add .
$ git commit ‐m "Add a StaticPages controller"
3.2
TDD BDD
Behavior-driven Development integration test (unit test)
RSpec request spec Capybara
natural-language syntax
BDD Cucumber 8.3 (chapter8.html#sec-8-3)
TDD
failing test
“ - - ” (http://en.wikipedia.org/wiki/Flow_(psychology))
TDD
(http://en.wikipedia.org/wiki/Extreme_Programming) “ spike ”
TDD
RSpec rspec
3.6
3.2.1
$ rails generate integration_test static_pages
invoke rspec
Python Programming Computer Vision with Python
Rails Ruby
4.1
Ruby Rails
Ruby
Rails 4.1
4.1
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Ruby on Rails Tutorial Sample App | <%= yield(:title) %></title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
4.1
<%= stylesheet_link_tag "application", :media => "all" %>
Rails stylesheet_link_tag Rails API
(http://api.rubyonrails.org/v3.2.0/classes/ActionView/Helpers/AssetTagHelper/StylesheetTagHelpers.html#method-i-
stylesheet_link_tag) (http://www.w3.org/TR/CSS2/media.html) application.css
Rails Ruby Rails
Symbol Hash
Rails
helper 4.1
Ruby on Rails Tutorial Sample App | <%= yield(:title) %>
provide
<% provide(:title, 'Home') %>
<h1>Sample App</h1>
<p>
This is the home page for the
<a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
sample application.
</p>
provide
Ruby on Rails Tutorial Sample App |
full_title full_title
“Ruby on Rails Tutorial Sample App”
4.2 1
4.2 full_title
app/helpers/application_helper.rb
module ApplicationHelper
# Returns the full title on a per‐page basis.
def full_title(page_title)
base_title = "Ruby on Rails Tutorial Sample App"
if page_title.empty?
base_title
else
"#{base_title} | #{page_title}"
end
end
end
<title>Ruby on Rails Tutorial Sample App | <%= yield(:title) %></title>
<title><%= full_title(yield(:title)) %></title>
4.3
4.3
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
“ ” “Home”
4.4 'Home'
4.4 “ ”
spec/requests/static_pages_spec.rb
require 'spec_helper'
describe "Static pages" do
describe "Home page" do
it "should have the h1 'Sample App'" do
visit '/static_pages/home'
page.should have_selector('h1', :text => 'Sample App')
end
it "should have the base title" do
visit '/static_pages/home'
page.should have_selector('title',
:text => "Ruby on Rails Tutorial Sample App")
end
it "should not have a custom page title" do
visit '/static_pages/home'
page.should_not have_selector('title', :text => '| Home')
end
end
.
.
.
end
3.3.1 (chapter3.html#sec-
3-3-1)
$ bundle exec rspec spec/requests/static_pages_spec.rb
“ ” provide 4.5
4.5 “ ”
app/views/static_pages/home.html.erb
<h1>Sample App</h1>
<p>
This is the home page for the
<a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
sample application.
</p>
$ bundle exec rspec spec/requests/static_pages_spec.rb
4.2 Rails
Ruby module
4.2
$ rails console
Loading development environment
>>
Rails
7.1.1
Ctrl-C Ctrl-D
Ruby API (http://ruby-doc.org/core-1.9.3/) API Ruby
String
4.2.1
# Returns the full title on a per‐page basis.
def full_title(page_title)
.
.
.
end
$ rails console
>> 17 + 42 # Integer addition
=> 59
4.2.2
Web
rails c rails console
$ rails c
>> "" # 空字符串
=> ""
>> "foo" # 非空的字符串
=> "foo"
>> "foo" + "bar" # 字符串连接
=> "foobar"
2
"foo" "bar" "foobar"
3
#{}
>> first_name = "Michael" # 变量赋值
=> "Michael"
>> "#{first_name} Hartl" # 字符串插值
=> "Michael Hartl"
>> first_name = "Michael"
=> "Michael"
>> last_name = "Hartl"
=> "Hartl"
>> first_name + " " + last_name # 字符串连接 中间加了空格
=> "Michael Hartl"
>> "#{first_name} #{last_name}" # 作用相同的插值
=> "Michael Hartl"
" "
>> puts "foo" # 打印字符串
foo
=> nil
puts side-effect puts "foo"
(http://www.answers.com/nil) nil Ruby “ ” => nil
puts \n print
Ruby
>> 'foo' # 单引号创建的字符串
=> "foo"
>> 'foo' + 'bar'
=> "foobar"
Ruby
>> '#{foo} bar' # 单引号字符串不能进行插值操作
=> "\#{foo} bar"
\n
>> '\n' # 反斜线和 n 字面值
=> "\\n"
# Ruby
>> 'Newlines (\n) and tabs (\t) both use the backslash character \.'
=> "Newlines (\\n) and tabs (\\t) both use the backslash character \\."
4.2.3
length
>> "foobar".length # 把 length 消息传递给字符串
=> 6
4
empty?
>> "foobar".empty?
=> false
>> "".empty?
=> true
>> s = "foobar"
>> if s.empty?
>> "The string is empty"
>> else
>> "The string is nonempty"
>> end
=> "The string is nonempty"
&& || !
>> x = "foo"
=> "foo"
>> y = ""
=> ""
>> puts "Both strings are empty" if x.empty? && y.empty?
=> nil
>> puts "One of the strings is empty" if x.empty? || y.empty?
"One of the strings is empty"
=> nil
>> puts "x is not empty" if !x.empty?
"x is not empty"
=> nil
>> nil.to_s
=> ""
chain
>> nil.empty?
NoMethodError: You have a nil object when you didn\'t expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.empty?
>> nil.to_s.empty? # 消息串联
=> true
>> "foo".nil?
=> false
>> "".nil?
=> false
>> nil.nil?
=> true
puts "x is not empty" if !x.empty?
if if
unless
>> string = "foobar"
>> puts "The string '#{string}' is nonempty." unless string.empty?
The string 'foobar' is nonempty.
=> nil
>> if nil
>> true
>> else
>> false # nil 是假值
>> end
=> false
Ruby “ ” 0
>> if 0
>> true # 0 除了 nil 和 false 之外的一切对象 是真值
>> else
>> false
>> end
=> true
4.2.4
>> def string_message(string)
>> if string.empty?
>> "It's an empty string!"
>> else
>> "The string is nonempty."
>> end
>> end
=> nil
>> puts string_message("")
It\'s an empty string!
>> puts string_message("foobar")
The string is nonempty.
Ruby
Ruby
>> def string_message(string)
>> return "It's an empty string!" if string.empty?
>> return "The string is nonempty."
>> end
return return
"The string is nonempty." return
4.2.5
5
4.2 full_title
module ApplicationHelper
# 根据所在页面返回完整的标题 # 在文档中显示的注释
def full_title(page_title) # 方法定义
base_title = "Ruby on Rails Tutorial Sample App" # 变量赋值
if page_title.empty? # 布尔测试
base_title # 非显式返回值
else
"#{base_title} | #{page_title}" # 字符串插值
end
end
end
——
module ApplicationHelper module
include Ruby module
module Rails full_title
(http://catb.org/jargon/html/A/automagically.html)
4.3
Web Rails
Ruby
4.3.1 Range
Hash 4.3.3
Rails 2.3.3 (chapter2.html#sec-2-3-3) has_many 10.1.3
(chapter10.html#sec-10-1-3)
split
>> "foo bar baz".split # 把字符串分割成有三个元素的数组
=> [
Python Programming Computer Vision with Python
5.1
Web Web
CSS CSS Bootstrap
(http://twitter.github.com/bootstrap/) Twitter Web
Web
mockup Web “ wireframe ” 2
home_page_mockup_bootstrap
5.1 “ ”
Git
$ git checkout ‐b filling‐in‐layout
5.1.1
application.html.erb 4.3
HTML CSS class 5.1
5.2
5.1
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag "application", media: "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
<!‐‐[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]‐‐>
</head>
<body>
<header class="navbar navbar‐fixed‐top">
<div class="navbar‐inner">
<div class="container">
<%= link_to "sample app", '#', id: "logo" %>
<nav>
<ul class="nav pull‐right">
<li><%= link_to "Home", '#' %></li>
<li><%= link_to "Help", '#' %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
</div>
</div>
</header>
<div class="container">
<%= yield %>
</div>
</body>
</html>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= stylesheet_link_tag "application", media: "all" %>
Hash
<!‐‐[if lt IE 9]>
IE 9 if lt IE 9 [if lt IE 9] Rails
IE (http://en.wikipedia.org/wiki/Conditional_comment)
conditional comment IE9 HTML5 shim
Firefox Chrome Safari
<header class="navbar navbar‐fixed‐top">
<div class="navbar‐inner">
<div class="container">
<%= link_to "sample app", '#', id: "logo" %>
<nav>
<ul class="nav pull‐right">
<li><%= link_to "Home", '#' %></li>
<li><%= link_to "Help", '#' %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
</div>
</div>
</header>
<header class="navbar navbar‐fixed‐top">
<div class="navbar‐inner">
<div class="container">
div ERb
<%= link_to "sample app", '#', id: "logo" %>
<nav>
<ul class="nav pull‐right">
<li><%= link_to "Home", '#' %></li>
<li><%= link_to "Help", '#' %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
div ul li
<nav>
<ul class="nav pull‐right">
<li><%= link_to "Home", '#' %></li>
<li><%= link_to "Help", '#' %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
<nav>
<ul class="nav pull‐right">
<li><a href="#">Home</a></li>
<li><a href="#">Help</a></li>
<li><a href="#">Sign in</a></li>
</ul>
</nav>
div
<div class="container">
<%= yield %>
</div>
5.1.3 “ ”
home.html.erb 5.2
5.2 “ ”
app/views/static_pages/home.html.erb
<div class="center hero‐unit">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", '#', class: "btn btn‐large btn‐primary" %>
</div>
<%= link_to image_tag("rails.png", alt: "Rails"), 'http://rubyonrails.org/' %>
link_to (chapter7.html)
<a href="#" class="btn btn‐large btn‐primary">Sign up now!</a>
<img alt="Rails" src="/assets/rails.png" />
alt alt
HTML Rails alt image_tag
Rails alt “Rails”
5.2
HTML class CSS
rails.png Rails
app/assets/images/ image_tag Rails asset pipeline
5.2
layout_no_logo_or_custom_css_bootstrap
source 'https://rubygems.org'
gem 'rails', '3.2.13'
gem 'bootstrap‐sass', '2.0.4'
.
.
.
$ bundle install
CSS CSS
app/assets/stylesheets/custom.css.scss
IDE
app/assets/stylesheets
5.4 Bootstrap
app/assets/stylesheets/custom.css.scss
@import "bootstrap";
sample_app_only_bootstrap
5.5 CSS
app/assets/stylesheets/custom.css.scss
@import "bootstrap";
/* universal */
html {
overflow‐y: scroll;
}
body {
padding‐top: 60px;
}
section {
overflow: auto;
}
textarea {
resize: vertical;
}
.center {
text‐align: center;
}
.center h1 {
margin‐bottom: 10px;
}
sample_app_universal
5.4
body {
padding‐top: 60px;
}
Bootstrap 5.6
“ ” 5.6 5.5
5.6
app/assets/stylesheets/custom.css.scss
@import "bootstrap";
.
.
.
/* typography */
h1, h2, h3, h4, h5, h6 {
line‐height: 1;
}
h1 {
font‐size: 3em;
letter‐spacing: ‐2px;
margin‐bottom: 30px;
text‐align: center;
}
h2 {
font‐size: 1.7em;
letter‐spacing: ‐1px;
margin‐bottom: 30px;
text‐align: center;
font‐weight: normal;
color: #999;
}
p {
font‐size: 1.1em;
line‐height: 1.7em;
}
sample_app_typography
5.5
Python Programming Computer Vision with Python
6.1 K-Means
6.1.1 SciPy
6.1.2
6.1.3
6.1.4
6.2
6.2.1
6.3
6.1 K-Means
K-means k K-means
6.1.1 SciPy
2
# coding=utf‐8
"""
Function: figure 6.1
An example of k‐means clustering of 2D points
"""
from pylab import *
from scipy.cluster.vq import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
class1 = 1.5 * randn(100, 2)
class2 = randn(100, 2) + array([5, 5])
features = vstack((class1, class2))
centroids, variance = kmeans(features, 2)
code, distance = vq(features, centroids)
figure()
ndx = where(code == 0)[0]
plot(features[ndx, 0], features[ndx, 1], '*')
ndx = where(code == 1)[0]
plot(features[ndx, 0], features[ndx, 1], 'r.')
plot(centroids[:, 0], centroids[:, 1], 'go')
title(u'2维数据点聚类', fontproperties=font)
axis('off')
show()
k-means 14 selectedfontimages.zip 66
40
# ‐*‐ coding: utf‐8 ‐*‐
from PCV.tools import imtools
import pickle
from scipy import *
from pylab import *
from PIL import Image
from scipy.cluster.vq import *
from PCV.tools import pca
# Uses sparse pca codepath.
imlist = imtools.get_imlist('../data/selectedfontimages/a_selected_thumbs/')
# 获取图像列表和他们的尺寸
im = array(Image.open(imlist[0])) # open one image to get the size
m, n = im.shape[:2] # get the size of the images
imnbr = len(imlist) # get the number of images
print "The number of images is %d" % imnbr
# Create matrix to store all flattened images
immatrix = array([array(Image.open(imname)).flatten() for imname in imlist], 'f')
# PCA降维
V, S, immean = pca.pca(immatrix)
# 保存均值和主成分
#f = open('./a_pca_modes.pkl', 'wb')
f = open('./a_pca_modes.pkl', 'wb')
pickle.dump(immean,f)
pickle.dump(V,f)
f.close()
# get list of images
imlist = imtools.get_imlist('../data/selectedfontimages/a_selected_thumbs/')
imnbr = len(imlist)
# load model file
with open('../data/selectedfontimages/a_pca_modes.pkl','rb') as f:
immean = pickle.load(f)
V = pickle.load(f)
# create matrix to store all flattened images
immatrix = array([array(Image.open(im)).flatten() for im in imlist],'f')
# project on the 40 first PCs
immean = immean.flatten()
projected = array([dot(V[:40],immatrix[i]‐immean) for i in range(imnbr)])
# k‐means
projected = whiten(projected)
centroids,distortion = kmeans(projected,4)
code,distance = vq(projected,centroids)
# plot clusters
for k in range(4):
ind = where(code==k)[0]
figure()
gray()
for i in range(minimum(len(ind),40)):
subplot(4,10,i+1)
imshow(immatrix[ind[i]].reshape((25,25)))
axis('off')
show()
6.1.3
# ‐*‐ coding: utf‐8 ‐*‐
from PCV.tools import imtools, pca
from PIL import Image, ImageDraw
from pylab import *
from PCV.clustering import hcluster
imlist = imtools.get_imlist('../data/selectedfontimages/a_selected_thumbs')
imnbr = len(imlist)
# Load images, run PCA.
immatrix = array([array(Image.open(im)).flatten() for im in imlist], 'f')
V, S, immean = pca.pca(immatrix)
# Project on 2 PCs.
projected = array([dot(V[[0, 1]], immatrix[i] ‐ immean) for i in range(imnbr)]) # P131 Fig6‐3左
图
#projected = array([dot(V[[1, 2]], immatrix[i] ‐ immean) for i in range(imnbr)]) # P131 Fig6‐3右
图
# height and width
h, w = 1200, 1200
# create a new image with a white background
img = Image.new('RGB', (w, h), (255, 255, 255))
draw = ImageDraw.Draw(img)
# draw axis
draw.line((0, h/2, w, h/2), fill=(255, 0, 0))
draw.line((w/2, 0, w/2, h), fill=(255, 0, 0))
# scale coordinates to fit
scale = abs(projected).max(0)
scaled = floor(array([(p/scale) * (w/2 ‐ 20, h/2 ‐ 20) + (w/2, h/2)
for p in projected])).astype(int)
# paste thumbnail of each image
for i in range(imnbr):
nodeim = Image.open(imlist[i])
nodeim.thumbnail((25, 25))
ns = nodeim.size
box = (scaled[i][0] ‐ ns[0] // 2, scaled[i][1] ‐ ns[1] // 2,
scaled[i][0] + ns[0] // 2 + 1, scaled[i][1] + ns[1] // 2 + 1)
img.paste(nodeim, box)
tree = hcluster.hcluster(projected)
hcluster.draw_dendrogram(tree,imlist,filename='fonts.png')
figure()
imshow(img)
axis('off')
img.save('../images/ch06/pca_font.png')
show()
P131 6-3
6.1.4
“ ”
k-means RGB
( )
# ‐*‐ coding: utf‐8 ‐*‐
"""
Function: figure 6.4
Clustering of pixels based on their color value using k‐means.
"""
from scipy.cluster.vq import *
from scipy.misc import imresize
from pylab import *
import Image
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
def clusterpixels(infile, k, steps):
im = array(Image.open(infile))
dx = im.shape[0] / steps
dy = im.shape[1] / steps
# compute color features for each region
features = []
for x in range(steps):
for y in range(steps):
R = mean(im[x * dx:(x + 1) * dx, y * dy:(y + 1) * dy, 0])
G = mean(im[x * dx:(x + 1) * dx, y * dy:(y + 1) * dy, 1])
B = mean(im[x * dx:(x + 1) * dx, y * dy:(y + 1) * dy, 2])
features.append([R, G, B])
features = array(features, 'f') # make into array
# 聚类 k是聚类数目
centroids, variance = kmeans(features, k)
code, distance = vq(features, centroids)
# create image with cluster labels
codeim = code.reshape(steps, steps)
codeim = imresize(codeim, im.shape[:2], 'nearest')
return codeim
k=3
infile_empire = '../data/empire.jpg'
im_empire = array(Image.open(infile_empire))
infile_boy_on_hill = '../data/boy_on_hill.jpg'
im_boy_on_hill = array(Image.open(infile_boy_on_hill))
steps = (50, 100) # image is divided in steps*steps region
print steps[0], steps[‐1]
#显示原图empire.jpg
figure()
subplot(231)
title(u'原图', fontproperties=font)
axis('off')
imshow(im_empire)
# 用50*50的块对empire.jpg的像素进行聚类
codeim= clusterpixels(infile_empire, k, steps[0])
subplot(232)
title(u'k=3,steps=50', fontproperties=font)
#ax1.set_title('Image')
axis('off')
imshow(codeim)
# 用100*100的块对empire.jpg的像素进行聚类
codeim= clusterpixels(infile_empire, k, steps[‐1])
ax1 = subplot(233)
title(u'k=3,steps=100', fontproperties=font)
#ax1.set_title('Image')
axis('off')
imshow(codeim)
#显示原图empire.jpg
subplot(234)
title(u'原图', fontproperties=font)
axis('off')
imshow(im_boy_on_hill)
# 用50*50的块对empire.jpg的像素进行聚类
codeim= clusterpixels(infile_boy_on_hill, k, steps[0])
subplot(235)
title(u'k=3,steps=50', fontproperties=font)
#ax1.set_title('Image')
axis('off')
imshow(codeim)
# 用100*100的块对empire.jpg的像素进行聚类
codeim= clusterpixels(infile_boy_on_hill, k, steps[‐1])
subplot(236)
title(u'k=3 steps=100', fontproperties=font)
axis('off')
imshow(codeim)
show()
steps*steps
k-means P133 6-4
6.2
( )
from pylab import *
from PCV.clustering import hcluster
class1 = 1.5 * randn(100,2)
class2 = randn(100,2) + array([5,5])
features = vstack((class1,class2))
tree = hcluster.hcluster(features)
clusters = tree.extract_clusters(5)
print 'number of clusters', len(clusters)
for c in clusters:
print c.get_cluster_elements()
2
number of clusters 2
[197, 107, 176, 123, 173, 189, 154, 136, 183, 113, 109, 199, 178, 129, 163, 100, 148, 111, 143,
118, 162, 169, 138, 182, 193, 116, 134, 198, 184, 181, 131, 166, 127, 185, 161, 171, 152, 157,
112, 186, 128, 156, 108, 158, 120, 174, 102, 137, 117, 194, 159, 105, 155, 132, 188, 125, 180,
151, 192, 164, 195, 126, 103, 196, 179, 146, 147, 135, 139, 110, 140, 106, 104, 115, 149, 190,
170, 172, 121, 145, 114, 150, 119, 142, 122, 144, 160, 187, 153, 167, 130, 133, 165, 191, 175,
177, 101, 141, 124, 168]
[0, 39, 32, 87, 40, 48, 28, 8, 26, 12, 94, 5, 1, 61, 24, 59, 83, 10, 99, 50, 23, 58, 51, 16, 71,
25, 11, 37, 22, 46, 60, 86, 65, 2, 21, 4, 41, 72, 80, 84, 33, 56, 75, 77, 29, 85, 93, 7, 73, 6,
82, 36, 49, 98, 79, 43, 91, 14, 47, 63, 3, 97, 35, 18, 44, 30, 13, 67, 62, 20, 57, 89, 88, 9, 54,
19, 15, 92, 38, 64, 45, 70, 52, 95, 69, 96, 42, 53, 27, 66, 90, 81, 31, 34, 74, 76, 17, 78, 55,
68]
6.2.1
# ‐*‐ coding: utf‐8 ‐*‐
import os
import Image
from PCV.clustering import hcluster
from matplotlib.pyplot import *
from numpy import *
# create a list of images
path = '../data/sunsets/flickr‐sunsets‐small/'
imlist = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.jpg')]
# extract feature vector (8 bins per color channel)
features = zeros([len(imlist), 512])
for i, f in enumerate(imlist):
im = array(Image.open(f))
# multi‐dimensional histogram
h, edges = histogramdd(im.reshape(‐1, 3), 8, normed=True, range=[(0, 255), (0, 255), (0,
255)])
features[i] = h.flatten()
tree = hcluster.hcluster(features)
# visualize clusters with some (arbitrary) threshold
clusters = tree.extract_clusters(0.23 * tree.distance)
# plot images for clusters with more than 3 elements
for c in clusters:
elements = c.get_cluster_elements()
nbr_elements = len(elements)
if nbr_elements > 3:
figure()
for p in range(minimum(nbr_elements,20)):
subplot(4, 5, p + 1)
im = array(Image.open(imlist[elements[p]]))
imshow(im)
axis('off')
show()
hcluster.draw_dendrogram(tree,imlist,filename='sunset.pdf')
P140 6-6
tree = hcluster.hcluster(projected)
hcluster.draw_dendrogram(tree,imlist,filename='fonts.png')
6.3
k-means k-means
# ‐*‐ coding: utf‐8 ‐*‐
from PCV.tools import imtools, pca
from PIL import Image, ImageDraw
from pylab import *
from scipy.cluster.vq import *
imlist = imtools.get_imlist('../data/selectedfontimages/a_selected_thumbs')
imnbr = len(imlist)
# Load images, run PCA.
immatrix = array([array(Image.open(im)).flatten() for im in imlist], 'f')
V, S, immean = pca.pca(immatrix)
# Project on 2 PCs.
projected = array([dot(V[[0, 1]], immatrix[i] ‐ immean) for i in range(imnbr)]) # P131 Fig6‐3左
图
#projected = array([dot(V[[1, 2]], immatrix[i] ‐ immean) for i in range(imnbr)]) # P131 Fig6‐3右
图
n = len(projected)
# compute distance matrix
S = array([[ sqrt(sum((projected[i]‐projected[j])**2))
for i in range(n) ] for j in range(n)], 'f')
# create Laplacian matrix
rowsum = sum(S,axis=0)
D = diag(1 / sqrt(rowsum))
I = identity(n)
L = I ‐ dot(D,dot(S,D))
# compute eigenvectors of L
U,sigma,V = linalg.svd(L)
k = 5
# create feature vector from k first eigenvectors
# by stacking eigenvectors as columns
features = array(V[:k]).T
# k‐means
features = whiten(features)
centroids,distortion = kmeans(features,k)
code,distance = vq(features,centroids)
# plot clusters
for c in range(k):
ind = where(code==c)[0]
figure()
gray()
for i in range(minimum(len(ind),39)):
im = Image.open(imlist[ind[i]])
subplot(4,10,i+1)
imshow(array(im))
axis('equal')
axis('off')
show()
k-means
k-means
44
48
# ‐*‐ coding: utf‐8 ‐*‐
from PCV.tools import imtools, pca
from PIL import Image, ImageDraw
from PCV.localdescriptors import sift
from pylab import *
import glob
from scipy.cluster.vq import *
#download_path = "panoimages" # set this to the path where you downloaded the panoramio images
#path = "/FULLPATH/panoimages/" # path to save thumbnails (pydot needs the full system path)
download_path = "F:/dropbox/Dropbox/translation/pcv‐notebook/data/panoimages" # set this to the
path where you downloaded the panoramio images
path = "F:/dropbox/Dropbox/translation/pcv‐notebook/data/panoimages/" # path to save thumbnails
(pydot needs the full system path)
# list of downloaded filenames
imlist = imtools.get_imlist('../data/panoimages/')
nbr_images = len(imlist)
# extract features
#featlist = [imname[:‐3] + 'sift' for imname in imlist]
#for i, imname in enumerate(imlist):
# sift.process_image(imname, featlist[i])
featlist = glob.glob('../data/panoimages/*.sift')
matchscores = zeros((nbr_images, nbr_images))
for i in range(nbr_images):
for j in range(i, nbr_images): # only compute upper triangle
print 'comparing ', imlist[i], imlist[j]
l1, d1 = sift.read_features_from_file(featlist[i])
l2, d2 = sift.read_features_from_file(featlist[j])
matches = sift.match_twosided(d1, d2)
nbr_matches = sum(matches > 0)
print 'number of matches = ', nbr_matches
matchscores[i, j] = nbr_matches
print "The match scores is: \n", matchscores
# copy values
for i in range(nbr_images):
for j in range(i + 1, nbr_images): # no need to copy diagonal
matchscores[j, i] = matchscores[i, j]
n = len(imlist)
# load the similarity matrix and reformat
S = matchscores
S = 1 / (S + 1e‐6)
# create Laplacian matrix
rowsum = sum(S,axis=0)
D = diag(1 / sqrt(rowsum))
I = identity(n)
L = I ‐ dot(D,dot(S,D))
# compute eigenvectors of L
U,sigma,V = linalg.svd(L)
k = 2
# create feature vector from k first eigenvectors
# by stacking eigenvectors as columns
features = array(V[:k]).T
# k‐means
features = whiten(features)
centroids,distortion = kmeans(features,k)
code,distance = vq(features,centroids)
# plot clusters
for c in range(k):
ind = where(code==c)[0]
figure()
gray()
for i in range(minimum(len(ind),39)):
im = Image.open(imlist[ind[i]])
subplot(5,4,i+1)
imshow(array(im))
axis('equal')
axis('off')
show()
() ()
7.0 CherryPy
7.1
7.2
7.3
7.4 Web
7.5 service.conf
7.0 CherryPy
CherryPy web
7.1
SIFT
# ‐*‐ coding: utf‐8 ‐*‐
import pickle
from PCV.imagesearch import vocabulary
from PCV.tools.imtools import get_imlist
from PCV.localdescriptors import sift
#获取图像列表
imlist = get_imlist('./first500/')
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:‐3]+'sift' for i in range(nbr_images)]
#提取文件夹下图像的sift特征
for i in range(nbr_images):
sift.process_image(imlist[i], featlist[i])
#生成词汇
voc = vocabulary.Vocabulary('ukbenchtest')
voc.train(featlist, 1000, 10)
#保存词汇
# saving vocabulary
with open('./first500/vocabulary.pkl', 'wb') as f:
pickle.dump(voc, f)
print 'vocabulary is:', voc.name, voc.nbr_words
ch07_cocabulary.py (https://github.com/willard-yuan/pcv-book-code/tree/master/ch07)
first500 (http://yuanyong.org/pcvwithpython/) first1000
first500 first1000 500 first500
7.2
# ‐*‐ coding: utf‐8 ‐*‐
import pickle
from PCV.imagesearch import imagesearch
from PCV.localdescriptors import sift
from sqlite3 import dbapi2 as sqlite
from PCV.tools.imtools import get_imlist
#获取图像列表
imlist = get_imlist('./first500/')
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:‐3]+'sift' for i in range(nbr_images)]
# load vocabulary
#载入词汇
with open('./first500/vocabulary.pkl', 'rb') as f:
voc = pickle.load(f)
#创建索引
indx = imagesearch.Indexer('testImaAdd.db',voc)
indx.create_tables()
# go through all images, project features on vocabulary and insert
#遍历所有的图像 并将它们的特征投影到词汇上
for i in range(nbr_images)[:500]:
locs,descr = sift.read_features_from_file(featlist[i])
indx.add_to_index(imlist[i],descr)
# commit to database
#提交到数据库
indx.db_commit()
con = sqlite.connect('testImaAdd.db')
print con.execute('select count (filename) from imlist').fetchone()
print con.execute('select * from imlist').fetchone()
testImaAdd.db
7.3
# ‐*‐ coding: utf‐8 ‐*‐
import pickle
from PCV.imagesearch import imagesearch
from PCV.localdescriptors import sift
from sqlite3 import dbapi2 as sqlite
from PCV.tools.imtools import get_imlist
#获取图像列表
imlist = get_imlist('./first500/')
nbr_images = len(imlist)
#获取特征列表
featlist = [imlist[i][:‐3]+'sift' for i in range(nbr_images)]
#载入词汇
f = open('./first500/vocabulary.pkl', 'rb')
voc = pickle.load(f)
f.close()
src = imagesearch.Searcher('testImaAdd.db',voc)
locs,descr = sift.read_features_from_file(featlist[0])
iw = voc.project(descr)
print 'ask using a histogram...'
#获取imlist[0]的前十幅候选图像
print src.candidates_from_histogram(iw)[:10]
src = imagesearch.Searcher('testImaAdd.db',voc)
print 'try a query...'
nbr_results = 12
res = [w[1] for w in src.query(imlist[0])[:nbr_results]]
imagesearch.plot_results(src,res)
7.4 Web
# ‐*‐ coding: utf‐8 ‐*‐
import cherrypy
import pickle
import urllib
import os
from numpy import *
#from PCV.tools.imtools import get_imlist
from PCV.imagesearch import imagesearch
"""
This is the image search demo in Section 7.6.
"""
class SearchDemo:
def __init__(self):
# 载入图像列表
self.path = './first500/'
#self.path = 'D:/python_web/isoutu/first500/'
self.imlist = [os.path.join(self.path,f) for f in os.listdir(self.path) if
f.endswith('.jpg')]
#self.imlist = get_imlist('./first500/')
#self.imlist = get_imlist('E:/python/isoutu/first500/')
self.nbr_images = len(self.imlist)
self.ndx = range(self.nbr_images)
# 载入词汇
f = open('./first500/vocabulary.pkl', 'rb')
self.voc = pickle.load(f)
f.close()
# 显示搜索返回的图像数
self.maxres = 49
# header and footer html
self.header = """
<!doctype html>
<head>
<title>Image search</title>
</head>
<body>
"""
self.footer = """
</body>
</html>
"""
def index(self, query=None):
self.src = imagesearch.Searcher('testImaAdd.db', self.voc)
html = self.header
html += """
<br />
Click an image to search. <a href='?query='> Random selection </a> of images.
<br /><br />
"""
if query:
# query the database and get top images
#查询数据库 并获取前面的图像
res = self.src.query(query)[:self.maxres]
for dist, ndx in res:
imname = self.src.get_filename(ndx)
html += "<a href='?query="+imname+"'>"
html += "<img src='"+imname+"' width='200' />"
html += "</a>"
# show random selection if no query
# 如果没有查询图像则随机显示一些图像
else:
random.shuffle(self.ndx)
for i in self.ndx[:self.maxres]:
imname = self.imlist[i]
html += "<a href='?query="+imname+"'>"
html += "<img src='"+imname+"' width='200' />"
html += "</a>"
html += self.footer
return html
index.exposed = True
#conf_path = os.path.dirname(os.path.abspath(__file__))
#conf_path = os.path.join(conf_path, "service.conf")
#cherrypy.config.update(conf_path)
#cherrypy.quickstart(SearchDemo())
cherrypy.quickstart(SearchDemo(), '/', config=os.path.join(os.path.dirname(__file__),
'service.conf'))
7.5 service.conf
[global]
server.socket_host = "127.0.0.1"
server.socket_port = 8080
server.thread_pool = 10
tools.sessions.on = True
[/]
tools.staticdir.root = "E:/python/isoutu"
[/first500]
tools.staticdir.on = True
tools.staticdir.dir = "first500"
() ()
8.1 K
8.1.1
# ‐*‐ coding: utf‐8 ‐*‐
from numpy.random import randn
import pickle
from pylab import *
# create sample data of 2D points
n = 200
# two normal distributions
class_1 = 0.6 * randn(n,2)
class_2 = 1.2 * randn(n,2) + array([5,1])
labels = hstack((ones(n),‐ones(n)))
# save with Pickle
#with open('points_normal.pkl', 'w') as f:
with open('points_normal_test.pkl', 'w') as f:
pickle.dump(class_1,f)
pickle.dump(class_2,f)
pickle.dump(labels,f)
# normal distribution and ring around it
class_1 = 0.6 * randn(n,2)
r = 0.8 * randn(n,1) + 5
angle = 2*pi * randn(n,1)
class_2 = hstack((r*cos(angle),r*sin(angle)))
labels = hstack((ones(n),‐ones(n)))
# save with Pickle
#with open('points_ring.pkl', 'w') as f:
with open('points_ring_test.pkl', 'w') as f:
pickle.dump(class_1,f)
pickle.dump(class_2,f)
pickle.dump(labels,f)
# ‐*‐ coding: utf‐8 ‐*‐
import pickle
from pylab import *
from PCV.classifiers import knn
from PCV.tools import imtools
pklist=['points_normal.pkl','points_ring.pkl']
figure()
# load 2D points using Pickle
for i, pklfile in enumerate(pklist):
with open(pklfile, 'r') as f:
class_1 = pickle.load(f)
class_2 = pickle.load(f)
labels = pickle.load(f)
# load test data using Pickle
with open(pklfile[:‐4]+'_test.pkl', 'r') as f:
class_1 = pickle.load(f)
class_2 = pickle.load(f)
labels = pickle.load(f)
model = knn.KnnClassifier(labels,vstack((class_1,class_2)))
# test on the first point
print model.classify(class_1[0])
#define function for plotting
def classify(x,y,model=model):
return array([model.classify([xx,yy]) for (xx,yy) in zip(x,y)])
# lot the classification boundary
subplot(1,2,i+1)
imtools.plot_2D_boundary([‐6,6,‐6,6],[class_1,class_2],classify,[1,‐1])
titlename=pklfile[:‐4]
title(titlename)
show()
8.1.2 (dense)sift )
# ‐*‐ coding: utf‐8 ‐*‐
from PCV.localdescriptors import sift, dsift
from pylab import *
from PIL import Image
dsift.process_image_dsift('../data/empire.jpg','empire.dsift',90,40,True)
l,d = sift.read_features_from_file('empire.dsift')
im = array(Image.open('../data/empire.jpg'))
sift.plot_features(im,l,True)
title('dense SIFT')
show()
8.1.3 ——
# ‐*‐ coding: utf‐8 ‐*‐
import os
from PCV.localdescriptors import sift, dsift
from pylab import *
from PIL import Image
imlist=['../data/gesture/train/A‐uniform01.ppm','../data/gesture/train/B‐uniform01.ppm',
'../data/gesture/train/C‐uniform01.ppm','../data/gesture/train/Five‐uniform01.ppm',
'../data/gesture/train/Point‐uniform01.ppm','../data/gesture/train/V‐uniform01.ppm']
figure()
for i, im in enumerate(imlist):
dsift.process_image_dsift(im,im[:‐3]+'.dsift',90,40,True)
l,d = sift.read_features_from_file(im[:‐3]+'dsift')
dirpath, filename=os.path.split(im)
im = array(Image.open(im))
#显示手势含义title
titlename=filename[:‐14]
subplot(2,3,i+1)
sift.plot_features(im,l,True)
title(titlename)
show()
# ‐*‐ coding: utf‐8 ‐*‐
from PCV.localdescriptors import dsift
import os
from PCV.localdescriptors import sift
from pylab import *
from PCV.classifiers import knn
def get_imagelist(path):
""" Returns a list of filenames for
all jpg images in a directory. """
return [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.ppm')]
def read_gesture_features_labels(path):
# create list of all files ending in .dsift
featlist = [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.dsift')]
# read the features
features = []
for featfile in featlist:
l,d = sift.read_features_from_file(featfile)
features.append(d.flatten())
features = array(features)
# create labels
labels = [featfile.split('/')[‐1][0] for featfile in featlist]
return features,array(labels)
def print_confusion(res,labels,classnames):
n = len(classnames)
# confusion matrix
class_ind = dict([(classnames[i],i) for i in range(n)])
confuse = zeros((n,n))
for i in range(len(test_labels)):
confuse[class_ind[res[i]],class_ind[test_labels[i]]] += 1
print 'Confusion matrix for'
print classnames
print confuse
filelist_train = get_imagelist('../data/gesture/train')
filelist_test = get_imagelist('../data/gesture/test')
imlist=filelist_train+filelist_test
# process images at fixed size (50,50)
for filename in imlist:
featfile = filename[:‐3]+'dsift'
dsift.process_image_dsift(filename,featfile,10,5,resize=(50,50))
features,labels = read_gesture_features_labels('../data/gesture/train/')
test_features,test_labels = read_gesture_features_labels('../data/gesture/test/')
classnames = unique(labels)
# test kNN
k = 1
knn_classifier = knn.KnnClassifier(labels,features)
res = array([knn_classifier.classify(test_features[i],k) for i in
range(len(test_labels))])
# accuracy
acc = sum(1.0*(res==test_labels)) / len(test_labels)
print 'Accuracy:', acc
print_confusion(res,test_labels,classnames)
Accuracy: 0.813471502591
Confusion matrix for
['A' 'B' 'C' 'F' 'P' 'V']
[[ 26. 0. 2. 0. 1. 1.]
[ 0. 26. 0. 1. 1. 1.]
[ 0. 0. 26. 0. 0. 1.]
[ 0. 3. 0. 37. 0. 0.]
[ 0. 1. 2. 0. 17. 1.]
[ 3. 1. 3. 0. 14. 25.]]
(chapter7.html)
“ ” “ ”
id
(chapter9.html)
(chapter9.html)
Cucumber Behavior-driven
Development, BDD Cucumber RSpec
$ git checkout ‐b sign‐in‐out
8.1 session
[session](http://en.wikipedia.org/wiki/Session(computerscience))
Rails “ ” session
session “ ” session
1
“ ”
session 8.2.1 “ ”
8.1.1 Sessions
Sessions new
create POST 8.1 8.2 destroy DELETE 8.2.6
HTTP REST 7.1 (chapter7.html#sec-7-1) Sessions
$ rails generate controller Sessions ‐‐no‐test‐framework
$ rails generate integration_test authentication_pages
“ ” signin_path 8.1
7.6 “ ”
signin_mockup_bootstrap
8.1
8.1 new
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
subject { page }
describe "signin page" do
before { visit signin_path }
it { should have_selector('h1', text: 'Sign in') }
it { should have_selector('title', text: 'Sign in') }
end
end
$ bundle exec rspec spec/
8.1 Sessions “ ”
Sessions new Users resources REST
resources :sessions, only: [:new, :create, :destroy]
8.2 session
config/routes.rb
SampleApp::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
match '/signup', to: 'users#new'
match '/signin', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
.
.
.
end
HTTP URI
8.3 Sessions
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
end
def destroy
end
end
“ ” “ ” session
app/views/sessions/new.html.erb 8.4
8.4 “ ”
app/views/sessions/new.html.erb
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
8.1
$ bundle exec rspec spec/
8.1.2
TDD
8.2
signin_failure_mockup_bootstrap
8.2
8.2 “ ”
Flash
it { should have_selector('div.alert.alert‐error', text: 'Invalid') }
(chapter7.html) 7.32
div.alert.alert‐error
<div class="alert alert‐error">Invalid...</div>
8.5
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
.
.
.
describe "signin" do
before { visit signin_path }
describe "with invalid information" do
before { click_button "Sign in" }
it { should have_selector('title', text: 'Sign in') }
it { should have_selector('div.alert.alert‐error', text: 'Invalid') }
end
end
end
1.
2. “ ”
3. “ ”
signin_success_mockup_bootstrap
8.3
8.6
8.6
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
.
.
.
describe "signin" do
before { visit signin_path }
.
.
.
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before do
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
end
end
end
it { should have_link('Profile', href: user_path(user)) }
a URI
8.1.3
7.17 form_for
@user
<%= form_for(@user) do |f| %>
.
.
.
<% end %>
Session @user
form_for
form_for(@user)
form_for(:session, url: sessions_path)
8.7
app/views/sessions/new.html.erb
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(:session, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Sign in", class: "btn btn‐large btn‐primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
“ ” 8.7 8.4
signin_form_bootstrap
Rails HTML
HTML 8.8
8.1.4
session
8.5
8.2 Email 8.2
class SessionsController < ApplicationController
.
.
.
def create
render 'new'
end
.
.
.
end
initial_failed_signin_rails_3_bootstrap
{ session: { password: "", email: "" } }
params[:session]
Hash
{ password: "", email: "" }
params[:session][:email]
params[:session][:password]
def create
user = User.find_by_email(params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
# Sign the user in and redirect to the user's show page.
else
# Create an error message and re‐render the signin form.
end
end
create Email Ruby
user && user.authenticate(params[:session][:password])
a && b
8.1.5 Flash
8.10
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
# Sign the user in and redirect to the user's show page.
else
flash[:error] = 'Invalid email/password combination' # Not quite right!
render 'new'
end
end
def destroy
end
end
Flash Flash
Bootstrap 8.6
8.6 Flash
8.10
Flash render 7.27
Flash
Flash 8.6 “ ”
Flash 8.7
8.7 Flash
Flash bug
$ bundle exec rspec spec/requests/authentication_pages_spec.rb \
> ‐e "signin with invalid information"
describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_selector(
Python Programming Computer Vision with Python
9.1
9.1.1
9.1.2
9.1.3
9.2
9.2.1
9.2.2
9.2.3
9.3
9.3.1
9.3.2
9.3.3
9.3.4
9.4
9.4.1
9.4.2 destroy
9.5
9.6
from pygraph.classes.digraph import digraph
from pygraph.algorithms.minmax import maximum_flow
gr = digraph()
gr.add_nodes([0,1,2,3])
gr.add_edge((0,1), wt=4)
gr.add_edge((1,2), wt=3)
gr.add_edge((2,3), wt=5)
gr.add_edge((0,2), wt=3)
gr.add_edge((1,3), wt=4)
flows,cuts = maximum_flow(gr,0,3)
print 'flow is:', flows
print 'cut is:', cuts
flow is: {(0, 1): 4, (1, 2): 0, (1, 3): 4, (2, 3): 3, (0, 2): 3}
cut is: {0: 0, 1: 1, 2: 1, 3: 1}
from scipy.misc import imresize
from PCV.tools import graphcut
from PIL import Image
from pylab import *
im = array(Image.open("../data/empire.jpg"))
im = imresize(im, 0.07)
size = im.shape[:2]
# add two rectangular training regions
labels = zeros(size)
labels[3:18, 3:18] = ‐1
labels[‐18:‐3, ‐18:‐3] = 1
# create graph
g = graphcut.build_bayes_graph(im, labels, kappa=1)
# cut the graph
res = graphcut.cut_graph(g, size)
figure()
graphcut.show_labeling(im, labels)
figure()
imshow(res)
gray()
axis('off')
show()
P203
from PCV.tools import rof
from pylab import *
from PIL import Image
import scipy.misc
#im = array(Image.open('../data/ceramic‐houses_t0.png').convert("L"))
im = array(Image.open('../data/flower32_t0.png').convert("L"))
figure()
gray()
subplot(131)
axis('off')
imshow(im)
U, T = rof.denoise(im, im, tolerance=0.001)
subplot(132)
axis('off')
imshow(U)
#t = 0.4 # ceramic‐houses_t0 threshold
t = 0.8 # flower32_t0 threshold
seg_im = U < t*U.max()
#scipy.misc.imsave('ceramic‐houses_t0_result.pdf', seg_im)
scipy.misc.imsave('flower32_t0_result.pdf', seg_im)
subplot(133)
axis('off')
imshow(seg_im)
show()
7.1 (chapter7.html#table-7-1) Users edit update index destroy
(chapter8.html)
updating-users
$ git checkout ‐b updating‐users
9.1
(chapter7.html) new
edit create POST update
PUT HTTP 3.2 (chapter3.html#sec-3-2)
9.1.1
1
9.1 Gravatar
Gravatar http://gravatar.com/emails
2
edit_user_mockup_bootstrap
9.1
7.31
9.1
9.1
spec/requests/user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
.
.
.
describe "edit" do
let(:user) { FactoryGirl.create(:user) }
before { visit edit_user_path(user) }
describe "page" do
it { should have_selector('h1', text: "Update your profile") }
it { should have_selector('title', text: "Edit user") }
it { should have_link('change', href: 'http://gravatar.com/emails') }
end
describe "with invalid information" do
before { click_button "Save changes" }
it { should have_content('error') }
end
end
end
class UsersController < ApplicationController
.
.
.
def edit
@user = User.find(params[:id])
end
end
9.3 7.17
9.6
9.3
app/views/users/edit.html.erb
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(@user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save changes", class: "btn btn‐large btn‐primary" %>
<% end %>
<%= gravatar_for @user %>
<a href="http://gravatar.com/emails">change</a>
</div>
</div>
$ bundle exec rspec spec/requests/user_pages_spec.rb ‐e "edit page"
edit_page_bootstrap
9.2 Email
form 9.4
9.4 HTML
<form action="/users/1" class="edit_user" id="edit_user_1" method="post">
<input name="_method" type="hidden" value="put" />
.
.
.
</form>
<input name="_method" type="hidden" value="put" />
$ rails console
>> User.new.new_record?
=> true
>> User.first.new_record?
=> false
“ Settings ”
“ ” 9.5
“ ” 9.6
9.5 “ ”
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
.
.
.
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before { sign_in user }
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Settings', href: edit_user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
.
.
.
end
end
end
9.6
spec/support/utilities.rb
.
.
.
def sign_in(user)
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
# Sign in when not using Capybara as well.
cookies[:remember_token] = user.remember_token
end
Capybara
Capybara cookies
# Sign in when not using Capybara as well.
cookies[:remember_token] = user.remember_token
HTTP 9.47
cookies cookies 8.19 cookies.permanent
sing_in 9.6
<%= link_to "Settings", edit_user_path(current_user) %>
9.7
9.7 “ ”
app/views/layouts/_header.html.erb
<header class="navbar navbar‐fixed‐top">
<div class="navbar‐inner">
<div class="container">
<%= link_to "sample app", root_path, id: "logo" %>
<nav>
<ul class="nav pull‐right">
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<% if signed_in? %>
<li><%= link_to "Users", '#' %></li>
<li id="fat‐menu" class="dropdown">
<a href="#" class="dropdown‐toggle" data‐toggle="dropdown">
Account <b class="caret"></b>
</a>
<ul class="dropdown‐menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings", edit_user_path(current_user) %></li>
<li class="divider"></li>
<li>
<%= link_to "Sign out", signout_path, method: "delete" %>
</li>
</ul>
</li>
<% else %>
<li><%= link_to "Sign in", signin_path %></li>
<% end %>
</ul>
</nav>
</div>
</div>
</header>
9.1.2
9.1 Users update
update_attributes params Hash 9.8
false else
create 7.21
9.8 update
app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
def edit
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
if @user.update_attributes(params[:user])
# Handle a successful update.
else
render 'edit'
end
end
end
9.3
$ bundle exec rspec spec/
edit_with_invalid_information_bootstrap
9.3
9.1.3
Gravatar
9.2 “change” 9.4
gravatar_cropper
9.4 Gravatar
describe "User pages" do
.
.
.
describe "edit" do
let(:user) { FactoryGirl.create(:user) }
before { visit edit_user_path(user) }
.
.
.
describe "with valid information" do
let(:new_name) { "New Name" }
let(:new_email) { "new@example.com" }
before do
fill_in "Name", with: new_name
fill_in "Email", with: new_email
fill_in "Password", with: user.password
fill_in "Confirm Password", with: user.password
click_button "Save changes"
end
it { should have_selector('title', text: new_name) }
it { should have_selector('div.alert.alert‐success') }
it { should have_link('Sign out', href: signout_path) }
specify { user.reload.name.should == new_name }
specify { user.reload.email.should == new_email }
end
end
end
reload
specify { user.reload.name.should == new_name }
specify { user.reload.email.should == new_email }
flash[:success] = "Profile updated"
sign_in @user
redirect_to @user
8.18 session
8.22
class UsersController < ApplicationController
.
.
.
def update
@user = User.find(params[:id])
if @user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in @user
redirect_to @user
else
render 'edit'
end
end
end
9.2
$ bundle exec rspec spec/
9.2
(chapter8.html)
9.5
signin_page_protected_mockup_bootstrap
9.5
9.2.1
describe "Authentication" do
.
.
.
describe "authorization" do
describe "for non‐signed‐in users" do
let(:user) { FactoryGirl.create(:user) }
describe "in the Users controller" do
describe "visiting the edit page" do
before { visit edit_user_path(user) }
it { should have_selector('title', text: 'Sign in') }
end
describe "submitting to the update action" do
before { put user_path(user) }
specify { response.should redirect_to(signin_path) }
end
end
end
end
end
describe "submitting to the update action" do
before { put user_path(user) }
specify { response.should redirect_to(signin_path) }
end
specify { response.should redirect_to(signin_path) }
before_filter
signed_in_user before_filter :signed_in_user
9.12
9.12 signed_in_user
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:edit, :update]
.
.
.
private
def signed_in_user
redirect_to signin_path, notice: "Please sign in." unless signed_in?
end
end
:only edit
update
flash[:notice] = "Please sign in."
redirect_to signin_path
flash[:error] flash[:success]
protected_sign_in_bootstrap
9.6
9.11 9.1
describe "edit" do
let(:user) { FactoryGirl.create(:user) }
before { visit edit_user_path(user) }
.
.
.
9.6 sign_in
9.13
9.13 edit update
spec/requests/user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
.
.
.
describe "edit" do
let(:user) { FactoryGirl.create(:user) }
before do
sign_in user
visit edit_user_path(user)
end
.
.
.
end
end
$ bundle exec rspec spec/
9.2.2
describe "Authentication" do
.
.
.
describe "authorization" do
.
.
.
describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
before { sign_in user }
describe "visiting Users#edit page" do
before { visit edit_user_path(wrong_user) }
it { should_not have_selector('title', text: full_title('Edit user')) }
end
describe "submitting a PUT request to the Users#update action" do
before { put user_path(wrong_user) }
specify { response.should redirect_to(root_path) }
end
end
end
end
FactoryGirl.create(:user, email: "wrong@example.com")
Email edit
update
correct_user 9.15
def update
if @user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in @user
redirect_to @user
else
render 'edit'
end
end
.
.
.
private
def signed_in_user
redirect_to signin_path, notice: "Please sign in." unless signed_in?
end
def correct_user
@user = User.find(params[:id])
redirect_to(root_path) unless current_user?(@user)
end
end
9.16 current_user?
app/helpers/sessions_helper.rb
module SessionsHelper
.
.
.
def current_user
@current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def current_user?(user)
user == current_user
end
.
.
.
end
def edit
@user = User.find(params[:id])
end
$ bundle exec rspec spec/
9.2.3
/users/1
/users/1/edit
9.17
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
.
.
.
describe "authorization" do
describe "for non‐signed‐in users" do
let(:user) { FactoryGirl.create(:user) }
describe "when attempting to visit a protected page" do
before do
visit edit_user_path(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
describe "after signing in" do
it "should render the desired protected page" do
page.should have_selector('title', text: 'Edit user')
end
end
end
end
.
.
.
end
end
9.18
app/helpers/sessions_helper.rb
module SessionsHelper
.
.
.
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
session.delete(:return_to)
end
def store_location
session[:return_to] = request.fullpath
end
end
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:edit, :update]
before_filter :correct_user, only: [:edit, :update]
.
.
.
def edit
end
.
.
.
private
def signed_in_user
unless signed_in?
store_location
redirect_to signin_path, notice: "Please sign in."
end
end
def correct_user
@user = User.find(params[:id])
redirect_to(root_path) unless current_user?(@user)
end
end
Sessions create redirect_back_or
9.20 redirect_back_or
9.20 create
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
.
.
.
def create
user = User.find_by_email(params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_back_or user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
.
.
.
end
redirect_back_or “ ” ||
session[:return_to] || default
9.17
$ bundle exec rspec spec/
9.3
index index
user_index_mockup_bootstrap
9.7 “Users”
9.3.1
index users_path
9.21
9.21 index
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
.
.
.
describe "authorization" do
describe "for non‐signed‐in users" do
.
.
.
describe "in the Users controller" do
.
.
.
describe "visiting the user index" do
before { visit users_path }
it { should have_selector('title', text: 'Sign in') }
end
end
.
.
.
end
end
end
9.22 index
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update]
.
.
.
def index
end
.
.
.
end
li 9.23
9.23
spec/requests/user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "index" do
before do
sign_in FactoryGirl.create(:user)
FactoryGirl.create(:user, name: "Bob", email: "bob@example.com")
FactoryGirl.create(:user, name: "Ben", email: "ben@example.com")
visit users_path
end
it { should have_selector('title', text: 'All users') }
it { should have_selector('h1', text: 'All users') }
it "should list each user" do
User.all.each do |user|
page.should have_selector('li', text: user.name)
end
end
end
.
.
.
end
2.4 User.all
@users 9.24
9.3.3
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update]
.
.
.
def index
@users = User.all
end
.
.
.
end
li each
Gravatar ul 9.25
9.25 7.6 (chapter7.html#sec-7-6) 7.29 Gravatar
7.29 Users
9.25
app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>
<ul class="users">
<% @users.each do |user| %>
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
</li>
<% end %>
</ul>
9.26 CSS
app/assets/stylesheets/custom.css.scss
.
.
.
/* users index */
.users {
list‐style: none;
margin: 0;
li {
overflow: auto;
padding: 10px 0;
border‐top: 1px solid $grayLighter;
&:last‐child {
border‐bottom: 1px solid $grayLighter;
}
}
}
users_path 7.1
(chapter7.html#table-7-1) 9.27 9.28
9.27 “Users”
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
.
.
.
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before { sign_in user }
it { should have_selector('title', text: user.name) }
it { should have_link('Users', href: users_path) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Settings', href: edit_user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
.
.
.
end
end
end
9.28 “Users”
app/views/layouts/_header.html.erb
<header class="navbar navbar‐fixed‐top">
<div class="navbar‐inner">
<div class="container">
<%= link_to "sample app", root_path, id: "logo" %>
<nav>
<ul class="nav pull‐right">
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<% if signed_in? %>
<li><%= link_to "Users", users_path %></li>
<li id="fat‐menu" class="dropdown">
<a href="#" class="dropdown‐toggle" data‐toggle="dropdown">
Account <b class="caret"></b>
</a>
<ul class="dropdown‐menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings", edit_user_path(current_user) %></li>
<li class="divider"></li>
<li>
<%= link_to "Sign out", signout_path, method: "delete" %>
</li>
</ul>
</li>
<% else %>
<li><%= link_to "Sign in", signin_path %></li>
<% end %>
</ul>
</nav>
</div>
</div>
</header>
$ bundle exec rspec spec/
9.8
user_index_only_one_bootstrap
9.8
9.3.2
Ruby Rake
source 'https://rubygems.org'
gem 'rails', '3.2.13'
gem 'bootstrap‐sass', '2.0.0'
gem 'bcrypt‐ruby', '3.0.1'
gem 'faker', '1.0.1'
.
.
.
$ bundle install
9.30 Rake
lib/tasks/sample_data.rake
namespace :db do
desc "Fill database with sample data"
task populate: :environment do
User.create!(name: "Example User",
email: "example@railstutorial.org",
password: "foobar",
password_confirmation: "foobar")
99.times do |n|
name = Faker::Name.name
email = "example‐#{n+1}@railstutorial.org"
password = "password"
User.create!(name: name,
email: email,
password: password,
password_confirmation: password)
end
end
end
db:populate Rake 99
task populate: :environment do
:db
$ bundle exec rake db:reset
$ bundle exec rake db:populate
$ bundle exec rake db:test:prepare
100 9.9
Gravatar
user_index_all_bootstrap
9.3.3
100
30
source 'https://rubygems.org'
gem 'rails', '3.2.13'
gem 'bootstrap‐sass', '2.0.0'
gem 'bcrypt‐ruby', '3.0.1'
gem 'faker', '1.0.1'
gem 'will_paginate', '3.0.3'
gem 'bootstrap‐will_paginate', '0.0.6'
.
.
.
$ bundle install
Web gem
will_paginate gem
CSS class pagination div will_paginate
paginate
FactoryGirl.define do
factory :user do
name "Michael Hartl"
email "michael@example.com"
password "foobar"
password_confirmation "foobar"
end
end
sequence Email
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}@example.com"}
.
.
.
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}@example.com"}
password "foobar"
password_confirmation "foobar"
end
end
30 30
before(:all) { 30.times { FactoryGirl.create(:user) } }
after(:all) { User.delete_all }
before(:all) 30
30 after(:all)
9.33
spec/requests/user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "index" do
let(:user) { FactoryGirl.create(:user) }
before(:each) do
sign_in user
visit users_path
end
it { should have_selector('title', text: 'All users') }
it { should have_selector('h1', text: 'All users') }
describe "pagination" do
before(:all) { 30.times { FactoryGirl.create(:user) } }
after(:all) { User.delete_all }
it { should have_selector('div.pagination') }
it "should list each user" do
User.paginate(page: 1).each do |user|
page.should have_selector('li', text: user.name)
end
end
end
end
.
.
.
end
Rails index
User.all will_paginate 9.34
9.34
app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>
<ul class="users">
<% @users.each do |user| %>
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
</li>
<% end %>
</ul>
<%= will_paginate %>
$ rails console
>> User.all.class
=> Array
>> User.paginate(page: 1).class
=> ActiveRecord::Relation
9.35 index
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update]
.
.
.
def index
@users = User.paginate(page: params[:page])
end
.
.
.
end
9.10 Rails
will_paginate
user_index_pagination_rails_3_bootstrap
user_index_page_two_rails_3_bootstrap
$ bundle exec rspec spec/
9.3.4
Rails
9.36
app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>
<ul class="users">
<% @users.each do |user| %>
<%= render user %>
<% end %>
</ul>
<%= will_paginate %>
6
render User user Rails
_user.html.erb 9.37
9.37
app/views/users/_user.html.erb
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
</li>
9.38
app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>
<ul class="users">
<%= render @users %>
</ul>
<%= will_paginate %>
$ bundle exec rspec spec/
9.4
REST Users destroy
9.12 destroy
user_index_delete_links_mockup_bootstrap
9.12
9.4.1
9.39 admin
spec/models/user_spec.rb
require 'spec_helper'
describe User do
.
.
.
it { should respond_to(:admin) }
it { should respond_to(:authenticate) }
it { should be_valid }
it { should_not be_admin }
describe "with admin attribute set to 'true'" do
before { @user.toggle!(:admin) }
it { should be_admin }
end
.
.
.
end
admin boolean
$ rails generate migration add_admin_to_users admin:boolean
user_model_admin_31
class AddAdminToUsers < ActiveRecord::Migration
def change
add_column :users, :admin, :boolean, default: false
end
end
“ ” “ ”
$ bundle exec rake db:migrate
$ bundle exec rake db:test:prepare
$ rails console ‐‐sandbox
>> user = User.first
>> user.admin?
=> false
>> user.toggle!(:admin)
=> true
>> user.admin?
=> true
admin
$ bundle exec rspec spec/models/user_spec.rb
9.41
9.41
lib/tasks/sample_data.rake
namespace :db do
desc "Fill database with sample data"
task populate: :environment do
admin = User.create!(name: "Example User",
email: "example@railstutorial.org",
password: "foobar",
password_confirmation: "foobar")
admin.toggle!(:admin)
.
.
.
end
end
$ bundle exec rake db:reset
$ bundle exec rake db:populate
$ bundle exec rake db:test:prepare
attr_accessible
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
.
.
.
end
:admin
PUT 7
put /users/17?admin=1
id 17
:admin 9.6
9.4.2 destroy
Users destroy
:admin
9.43
9.43
spec/factories.rb
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}@example.com"}
password "foobar"
password_confirmation "foobar"
factory :admin do
admin true
end
end
end
FactoryGirl.create(:admin)
it { should_not have_link('delete') }
it { should have_link('delete', href: user_path(User.first)) }
it "should be able to delete another user" do
expect { click_link('delete') }.to change(User, :count).by(‐1)
end
it { should_not have_link('delete', href: user_path(admin)) }
9.44
9.44
spec/requests/user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "index" do
let(:user) { FactoryGirl.create(:user) }
before do
sign_in user
visit users_path
end
it { should have_selector('title', text: 'All users') }
it { should have_selector('h1', text: 'All users') }
describe "pagination" do
.
.
.
end
describe "delete links" do
it { should_not have_link('delete') }
describe "as an admin user" do
let(:admin) { FactoryGirl.create(:admin) }
before do
sign_in admin
visit users_path
end
it { should have_link('delete', href: user_path(User.first)) }
it "should be able to delete another user" do
expect { click_link('delete') }.to change(User, :count).by(‐1)
end
it { should_not have_link('delete', href: user_path(admin)) }
end
end
end
end
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %>
<% end %>
</li>
index_delete_links_rails_3_bootstrap
9.46 destroy
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update, :destroy]
before_filter :correct_user, only: [:edit, :update]
.
.
.
def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
.
.
.
end
User.find(params[:id]).destroy
DELETE
destroy
9.47 9.11 put delete
user_path 7.1 (chapter7.html#table-7-1) DELETE
9.47 destroy
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
.
.
.
describe "authorization" do
.
.
.
describe "as non‐admin user" do
let(:user) { FactoryGirl.create(:user) }
let(:non_admin) { FactoryGirl.create(:user) }
before { sign_in non_admin }
describe "submitting a DELETE request to the Users#destroy action" do
before { delete user_path(user) }
specify { response.should redirect_to(root_path) }
end
end
end
end
DELETE
9.6
destroy 9.48
9.48 destroy
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update, :destroy]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
.
.
.
private
.
.
.
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
Users
$ bundle exec rspec spec/
9.5
Users (chapter10.html)
Twitter (chapter11.html) Rails
has_many has_many through
$ git add .
$ git commit ‐m "Finish user edit, update, index, and destroy actions"
$ git checkout master
$ git merge updating‐users
“ ” pg:reset “ ”
$ git push heroku
$ heroku pg:reset DATABASE
$ heroku run rake db:migrate
$ heroku run rake db:populate
9.49 Gemfile
source 'https://rubygems.org'
gem 'rails', '3.2.13'
gem 'bootstrap‐sass', '2.0.0'
gem 'bcrypt‐ruby', '3.0.1'
gem 'faker', '1.0.1'
gem 'will_paginate', '3.0.3'
gem 'bootstrap‐will_paginate', '0.0.6'
group :development do
gem 'sqlite3', '1.3.5'
gem 'annotate', '˜> 2.4.1.beta'
end
# Gems used only for assets and not required
# in production environments by default.
group :assets do
gem 'sass‐rails', '3.2.4'
gem 'coffee‐rails', '3.2.2'
gem 'uglifier', '1.2.3'
end
gem 'jquery‐rails', '2.0.0'
group :test, :development do
gem 'rspec‐rails', '2.10.0'
gem 'guard‐rspec', '0.5.5'
gem 'guard‐spork', '0.3.2'
gem 'spork', '0.9.0'
end
group :test do
gem 'capybara', '1.1.2'
gem 'factory_girl_rails', '1.4.0'
gem 'cucumber‐rails', '1.2.1', require: false
gem 'database_cleaner', '0.7.0'
end
group :production do
gem 'pg', '0.12.2'
end
9.6
4. 9.6 sign_in
5. 9.50 new.html.erb edit.html.erb f
9.51
9.50
app/views/users/_fields.html.erb
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
9.51
app/views/users/new.html.erb
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(@user) do |f| %>
<%= render 'fields', f: f %>
<%= f.submit "Create my account", class: "btn btn‐large btn‐primary" %>
<% end %>
</div>
</div>
9.52
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
.
.
.
describe "authorization" do
describe "for non‐signed‐in users" do
.
.
.
describe "when attempting to visit a protected page" do
before do
visit edit_user_path(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
describe "after signing in" do
it "should render the desired protected page" do
page.should have_selector('title', text: 'Edit user')
end
describe "when signing in again" do
before do
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
it "should render the default (profile) page" do
page.should have_selector('title', text: user.name)
end
end
end
end
end
.
.
.
end
end
« (http://yongyuan.name/pcvwithpython//chapter8.html)
» (http://yongyuan.name/pcvwithpython//chapter10.html)
1. http://www.flickr.com/photos/sashawolff/4598355045/
(http://www.flickr.com/photos/sashawolff/4598355045/) ↩
2. Gravatar http://en.gravatar.com/emails en
↩
3. Rails Rails ↩
4. thoughtbot Clearance gem ↩
5. ↩
6. user @users.each do |foobar| render foobar
User ↩
7. curl PUT ↩
8. http://api.rubyonrails.org/v3.2.0/classes/ActionDispatch/Request.html
(http://api.rubyonrails.org/v3.2.0/classes/ActionDispatch/Request.html) ↩
() ()
OpenCV
import cv2
import cv2.cv
10.2 OpenCV
OpenCV
10.2.1
.png
# ‐*‐ coding: utf‐8 ‐*‐
import cv2
# 读入图像
im = cv2.imread('../data/empire.jpg')
# 打印图像尺寸
h, w = im.shape[:2]
print h, w
# 保存原jpg格式的图像为png格式图像
cv2.imwrite('../images/ch10/ch10_P210_Reading‐and‐Writing‐Images.png',im)
10.2.2
import cv2
im = cv2.imread('../data/empire.jpg')
# create a grayscale version
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
10.2.3
OpenCV OpenCV
# ‐*‐ coding: utf‐8 ‐*‐
import cv2
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
# 读入图像
im = cv2.imread('../data/fisherman.jpg')
# 转换颜色空间
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 显示积分图像
fig = plt.figure()
subplot(121)
plt.gray()
imshow(gray)
title(u'灰度图', fontproperties=font)
axis('off')
# 计算积分图像
intim = cv2.integral(gray)
# 归一化
intim = (255.0*intim) / intim.max()
#显示积分图像
subplot(122)
plt.gray()
imshow(intim)
title(u'积分图', fontproperties=font)
axis('off')
show()
# 用OpenCV显示图像
#cv2.imshow("Image", intim)
#cv2.waitKey()
# 用OpenCV保存积分图像
#cv2.imwrite('../images/ch10/ch10_P211_Displaying‐Images‐and‐Results‐cv2.jpg',intim)
# 保存figure中的灰度图像和积分图像
fig.savefig("../images/ch10/ch10_P211_Displaying‐Images‐and‐Results.png")
/images/ch10/
( )
# ‐*‐ coding: utf‐8 ‐*‐
import cv2
import numpy
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
# 读入图像
filename = '../data/fisherman.jpg'
im = cv2.imread(filename)
# 转换颜色空间
rgbIm = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
# 显示原图
fig = plt.figure()
subplot(121)
plt.gray()
imshow(rgbIm)
title(u'原图', fontproperties=font)
axis('off')
# 获取图像尺寸
h, w = im.shape[:2]
# 泛洪填充
diff = (6, 6, 6)
mask = zeros((h+2, w+2), numpy.uint8)
cv2.floodFill(im, mask, (10, 10), (255, 255, 0), diff, diff)
# 显示泛洪填充后的结果
subplot(122)
imshow(im)
title(u'泛洪填充', fontproperties=font)
axis('off')
show()
#fig.savefig("../images/ch10/floodFill.png")
# 在OpenCV窗口中显示泛洪填充后的结果
# cv2.imshow('flood fill', im)
# cv2.waitKey()
# 保存结果
# cv2.imwrite('../images/ch10/floodFill.jpg',im)
matplotlib OpenCV
OpenCV
SURF( )
(http://zh.wikipedia.org/wiki/%E5%8A%A0%E9%80%9F%E7%A8%B3%E5%81%A5%E7%89%B9%E5%BE%81)
SURF SIFT OpenCV
# ‐*‐ coding: utf‐8 ‐*‐
import cv2
import numpy
from pylab import *
# 读入图像
im = cv2.imread('../data/empire.jpg')
# 下采样
im_lowres = cv2.pyrDown(im)
# 转化为灰度图像
gray = cv2.cvtColor(im_lowres, cv2.COLOR_RGB2GRAY)
# 检测特征点
s = cv2.SURF()
mask = numpy.uint8(ones(gray.shape))
keypoints = s.detect(gray, mask)
# 显示图像及特征点
vis = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
for k in keypoints[::10]:
cv2.circle(vis, (int(k.pt[0]), int(k.pt[1])), 2, (0, 255, 0), ‐1)
cv2.circle(vis, (int(k.pt[0]), int(k.pt[1])), int(k.size), (0, 255, 0), 2)
cv2.imshow('local descriptors', vis)
cv2.waitKey()
cv2.imwrite('../images/ch10/ch10_P261_Fig10‐3.jpg',vis)
pyrDown im_lowres
SURF SURF
10.3
Python
Python Python OpenCV
10.3.1
OpenCV OpenCV
import cv2
# setup video capture
cap = cv2.VideoCapture(0)
while True:
ret,im = cap.read()
cv2.imshow('video test',im)
key = cv2.waitKey(10)
if key == 27:
break
if key == ord(' '):
cv2.imwrite('vid_result.jpg',im)
VideoCapture ID
ID 0 read() waitKey() “Esc”( ASCII
27) “space”
OpenCV
import cv2
# setup video capture
cap = cv2.VideoCapture(0)
# get frame, apply Gaussian smoothing, show result
while True:
ret,im = cap.read()
blur = cv2.GaussianBlur(im,(0,0),10)
cv2.imshow('camera blur',blur)
if cv2.waitKey(10) == 27:
break
GaussianBlur()
10.3.2 NumPy
OpenCV NumPy
NumPy
import cv2
from pylab import *
# setup video capture
cap = cv2.VideoCapture(0)
frames = []
# get frame, store in array
while True:
ret,im = cap.read()
cv2.imshow('video',im)
frames.append(im)
if cv2.waitKey(10) == 27:
break
frames = array(frames)
# check the sizes
print im.shape
print frames.shape
(480, 640, 3)
(40, 480, 640, 3)
40
10.4
10.4.1
10.4.2 Lucas-Kanade
Lucas-Kanade
import lktrack
imnames = ['../data/bt/bt.003.pgm', '../data/bt/bt.002.pgm', '../data/bt/bt.001.pgm',
'../data/bt/bt.000.pgm']
# create tracker object
lkt = lktrack.LKTracker(imnames)
# detect in first frame, track in the remaining
lkt.detect_points()
lkt.draw()
for i in range(len(imnames)‐1):
lkt.track_points()
lkt.draw()