一直想写个个人总结神马的,以告慰这一年多自己的所做所为,所学所获。今天终于开动了。
在研一上捣鼓了几个月的FPGA之后,接到导师的一个任务,做一个视觉定位软件,当然主要还是为他们公司服务。先上一张软件的界面图,毕竟 不是美工出身,界面长的可能比较抽象。
图1定位软件
图2 标刻软件中 待标刻文字ABCD的位置
由于该定位系统涉及到很多的图像处理算法,为此使用了开源的计算机视觉库opencv来辅助自己的一些算法。
既然是定位啦,那肯定要对相机进行标定了,以图通过物体上某点的像素坐标获得其真实的世界坐标。
对于相机标定我选择了保留一阶径向畸变的非线性模型,通过SVD求解模型的参数矩阵。同时为了提高标定精度,还特意在原来标定的基础上又加了一次标定,实验结果表明精度大大的提高啊。
标定完成后,我们就要进行采集一个标准的,位置正确的工件作为模板了,如上图所示。
接着,我们就通过相机获得待定位工件的图像,并进行定位如下图所示:
图3 待定位工件
图4 定位后ABCD的位置
好吧,上面几个图太抽象了,但总的来说定位的效果达到了。
其实说来说去,在这种学到了什么东西才是最重要的。
让我印象最深刻的一个问题就是,我居然一不小心将临时变量作为了函数的返回值,这直接导致最后得到的定位数据古怪的很。当时看到出来的甚是奇怪的定位结果,硬是将定位的那段代码检查了一遍又一遍,语法没错啊,逻辑关系也没错啊。怎么就是得不到正确的数据呢,最后,我想是不是代码中的某些警告也得重视下呢?于是问题就逮出来了,我居然将一个临时内存的地址作为函数的返回值了。可想而知,一旦这个函数执行完了,这个临时开辟的内存也将被收回,这内存里的有用的值早就无影无踪了。哪儿还等着你来取呢?
还有个问题就是在实现相机标定功能时候,用到了排序。刚开始想着,毕竟定位的要求是要实时,于是就想都没想弄了个快速排序上去,结果发现程序在运行时老是出错,提示栈溢出,定位错误后恍然大悟,原来快速排序也是有死穴的,由于它是递归调用,一直在排序完成之前所有数据都往栈里塞,可想而知系统给函数分配的栈就那么大点,这数据量要是大的话,哪里还放得下呢,不溢出都不正常了。好吧,只能舍弃快速排序了,弄了个稳定空间复杂度较小的插入排序,时间复杂度先忍忍吧。
大家都知道,相机标定涉及到大量的数学计算,刚开始的时候我把标定的代码放到主线程里执行,结果好啊,一点那个相机标定,软件就死了,界面动弹不得,只是当时还不清楚多线程编程这回事儿,于是问同学,同学说你把标定的功能单独开个线程执行看看。真的是一语点醒梦中人啦,于是乎我将标定的功能单独开了个线程执行,从此,软件界面再也不用担心动弹不得了。
总之呢,在做的过程问题还是很多的,还是待我慢慢阅读自己的笔记吧。
二:多线程编程再续前缘与网络编程
数来惭愧,标题可能有点大,但真的只是做了个小小的东西,都有点不好意思了,有图由真相。
图5 服务器端
图6 客户端
先说说两个端的功能吧,客户端首先将标刻软件要标刻的条码传到另台电脑上的服务器端,服务器端得到条码后,访问数据库查询,看该条码是否已经被标刻过,如果不是就将该条码存入本地数据库,并告知客户端此条码可以标刻。如果是,就放弃该条码并告知客户端此条码之前已经被标刻过,让客户端通知本地标刻软件改变条码值。
由于客户端的数量不是很多,因此我选择了较为简单的多线程服务器模型,以提高服务器的并发响应能力。同时使用事件对象对数据库的读写进行保护,防止多个客户端对数据的访问发生冲突。
三:真的是膜拜机器学习,膜拜那些高大上的算法
一直觉得懂几个机器学习的算法,懂些个计算机视觉的算法是多么厉害的事儿。于是那个暑假,买了本机器学习实战的书看了起来,一时兴起,在网上翻天倒海的搜那些人脸库,在此挂上来。,有需要的人可以下载去用用,哈哈。(ORL人脸库)
下面是代码:SMO算法参考的是<<机器学习实战>>
faceRecong.py
# _*_ coding: utf-8 _*_
import SMO
import numpy as np
from os import listdir#listdir获取指定目录里的文件名称并存在列表中
import cv2
import math
trainfilelist = []
def vectortoimg(matrix,H,W):
img = np.zeros((H,W),np.uint8)
for i in xrange(H):
for j in xrange(W):
img[i,j] = int(np.abs(matrix[i*W + j]))
return img
def extractFiture(Xinput,W):
alpha = W.T*Xinput
return alpha
def faceRebuld(W,y):
face = W*y
return face
def calcos(alpha1,alpha2):
inproduct = alpha1.T*alpha2
longalpha1 = math.sqrt(alpha1.T*alpha1)
longalpha2 = math.sqrt(alpha2.T*alpha2)
cos = float(inproduct)/(longalpha1*longalpha2)
return cos
def caloujiDis(alpha1,alpha2):
return math.sqrt((alpha1 - alpha2).T*(alpha1 - alpha2))
def imgtovector(img):
c=[]
for i in xrange(img.shape[0]):
for j in xrange(img.shape[1]):
c.append(img[i,j,1])
img_vector = np.mat(c).transpose()
return img_vector
def pca(dirname):
global trainfilelist
trainfilelist = listdir(dirname)
number = len(trainfilelist)
img = cv2.imread("%s/%s" %(dirname,trainfilelist[0]))
Height = img.shape[0]
Width = img.shape[1]
c=[]
matrix = np.mat(np.zeros((Height*Width,1)))
for n in range(number):
filenamestr = trainfilelist[n]
img = cv2.imread("%s/%s" %(dirname,filenamestr))
for i in range(Height):
for j in range(Width):
c.append(img[i,j,1])
matrix += np.mat(c).transpose()
c=[]
average_matrix = matrix/float(number)
A = np.mat(np.zeros((Height*Width,number)))
for n in xrange(number):
filenamestr = trainfilelist[n]
img = cv2.imread("%s/%s" %(dirname,filenamestr))
for i in xrange(Height):
for j in xrange(Width):
c.append(img[i,j,1])
A[:,n] = (np.mat(c).transpose() - average_matrix)
c= []
u,s,v = np.linalg.svd(A,False)
alpha = u[:,0:15].T*A#矩阵alpha的每一列为每张图片的特征,利用这些特征进行分类
return alpha,average_matrix,u[:,0:15]#u为特征空间,alpha为提取的图像特征
fiture,aver_img,w = pca("E:/yaleB02/label2")
labelclass = [1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]
b1,alphas1 = SMO.smoSimple(fiture.T,labelclass,0.7,0.001,40)
#求权值向量W
W1 = np.mat(np.zeros((15,1)))
for i in xrange(15):
W1 += alphas1[i,0]*labelclass[i]*fiture[:,i]
labelclass = [-1,-1,-1,-1,-1,1,1,1,1,1,-1,-1,-1,-1,-1]
b2,alphas2 = SMO.smoSimple(fiture.T,labelclass,0.7,0.001,40)
#求权值向量W
W2 = np.mat(np.zeros((15,1)))
for i in xrange(15):
W2 += alphas2[i,0]*labelclass[i]*fiture[:,i]
labelclass = [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1]
b3,alphas3 = SMO.smoSimple(fiture.T,labelclass,0.7,0.001,40)
#求权值向量W
W3 = np.mat(np.zeros((15,1)))
for i in xrange(15):
W3 += alphas3[i,0]*labelclass[i]*fiture[:,i]
#测试
test_img = cv2.imread("E:/yaleB02/test.bmp")
test_imgvec = imgtovector(test_img)
fiture_test = w.T*(test_imgvec - aver_img)
if (W1.T*fiture_test - b1) > 1:
print u"属于第一类人脸"
elif (W2.T*fiture_test - b2) > 1:
print u"属于第二类人脸"
else:
print u"属于第三类人脸"
SMO.py
#_*_ coding:utf-8 _*_
from random import *
from numpy import *
import math
def selectJrand(i,m):#生成一个不为i 的随机数,随机选取一个不同的a值
j=i
while (j==i):
j = int(random.uniform(0,m))
return j
def clipAlpha(aj,H,L):
if aj > H:
aj = H
if L > aj:
aj = L
return aj
def kernel(X,A):#X是所有的样本,A是一个样本,内积在单个样本与所有样本之间计算是行向量
delta = 1
m = X.shape[0]
K = mat(zeros((m,1)))
for i in xrange(m):
deltarow = A - X[i,:]
K[i] = deltarow*deltarow.T
K = exp(-K/(2*delta**2))
return K
def smoSimple(dataMatrix, classLabels, C, toler, maxIter):
labelMat = mat(classLabels).transpose()#列表转化为矩阵可以相乘
#transpose()将行向量变成列向量
b =0; m,n = shape(dataMatrix)
alphas = mat(zeros((m,1)))#产生alpha列向量行数为alpha的个数即数据点的个数
iter = 0
while (iter < maxIter):
alphaPairsChanged = 0
for i in range(m):
fXi = float(multiply(alphas,labelMat).T*\
kernel(dataMatrix,dataMatrix[i,:])) - b
Ei = fXi - float(labelMat[i])
if((labelMat[i]*Ei < -toler) and (alphas[i] < C) or\
(labelMat[i]*Ei >toler) and (alphas[i] >0)):
j = selectJrand(i,m)
fXj = float(multiply(alphas,labelMat).T*\
kernel(dataMatrix,dataMatrix[j,:])) - b
Ej = fXj - float(labelMat[j])
alphaIold = alphas[i].copy()
alphaJold = alphas[j].copy()
if(labelMat[i] != labelMat[j]):
L = max(0, alphas[j] - alphas[i])
H = max(C, C + alphas[j] - alphas[i])
else:
L = max(0, alphas[j] + alphas[i] - C)
H = min(C, alphas[j] + alphas[i])
if L==H: print "L==H"; continue
eta = 2.0 * kernel(dataMatrix[i,:],dataMatrix[j,:])-\
kernel(dataMatrix[i,:],dataMatrix[i,:]) - \
kernel(dataMatrix[j,:],dataMatrix[j,:])
if eta >=0: print "eta>=0"; continue
alphas[j] -= labelMat[j]*(Ei - Ej)/eta
alphas[j] = clipAlpha(alphas[j],H,L)
if(abs(alphas[j] - alphaJold) < 0.00001):
print "j not moving enough"; continue
alphas[i] +=labelMat[j]*labelMat[i]*\
(alphaJold - alphas[j])
b1 = b - Ei -labelMat[i]*(alphas[i]-alphaIold)*\
kernel(dataMatrix[i,:],dataMatrix[i,:]) -\
labelMat[j]*(alphas[j] -alphaJold)*\
kernel(dataMatrix[i,:],dataMatrix[j,:])
b2 = b - Ej -labelMat[i]*(alphas[i]-alphaIold)*\
kernel(dataMatrix[i,:],dataMatrix[j,:])-\
labelMat[j]*(alphas[j] -alphaJold)*\
kernel(dataMatrix[j,:],dataMatrix[j,:])
if(0 < alphas[i]) and (C > alphas[i]): b = b1
elif (0 < alphas[j]) and (C > alphas[j]): b = b2
else: b = (b1 + b2)/2.0
alphaPairsChanged += 1
print "iter: %d i:%d, pairs changed %d" %\
(iter,i,alphaPairsChanged)
if(alphaPairsChanged == 0):
iter += 1
else:
iter = 0
print "iteration number: %d" % iter
return b,alphas
我只用了三类人脸样本来训练,每类只是5个样本,估计没啥精度,下面是运行的结果,居然是对的,哈哈,虽然没啥精度,但作为理解人脸识别的相关算法还是有用的。
四:再说FPGA
说起FPGA一直是心中的痛,大约在本科大四的时候就开始接触了,但那时啥也不懂,稀里糊涂。思维还纯粹停留在简简单单 的编程上面,完全没有将FPGA这块硬件融入到自己的思维里,更别谈什么时序优化了。
直到最近想搞基于FPGA的jpeg编解码,(只是做了个一维DCT变换就放假回家了),总算是体会到了那种时序优化带来的乐趣,看着时序报告中红色的数字变黑还是很有成就感的,
只能说时序余量都变正了,再也不用忍受红色的负余量了。时序不满足,究其原因,确实是我设计有问题,DCT变换实际上也就是一系列的乘累加,问题就出在累加上,刚开始的时候我直接把N多个乘的结果用assign送到一个组合逻辑进行加了,导致加法链太长,从而引起建立时间得不到满足。为此我就试着加了一级寄存器,再看时序报告,负的时序余量再减小了,于是欣喜若狂,好吧那我继续用寄存器分割加法链,哈哈,终于时序得到满足了,可以跑到50M了。
下面是仿真结果,就是输出迟滞还是有点大
未完待续........
记录点滴