HOG(Histograms of Oriented Gradients) 代码

Source from

http://hi.baidu.com/timehandle/blog/item/9a395c370e69980591ef3943.html

function F = hogcalculator(img, cellpw, cellph, nblockw, nblockh,...
nthet, overlap, isglobalinterpolate, issigned, normmethod)
% HOGCALCULATOR calculate R-HOG feature vector of an input image using the
% procedure presented in Dalal and Triggs's paper in CVPR 2005.
%

% Author:   timeHandle
% Time:     March 24, 2010
%           May 12,2010 update.
%
%       this copy of code is written for my personal interest, which is an
%       original and inornate realization of [Dalal CVPR2005]'s algorithm
%       without any optimization. I just want to check whether I understand
%       the algorithm really or not, and also do some practices for knowing
%       matlab programming more well because I could be called as 'novice'.
%       OpenCV 2.0 has realized Dalal's HOG algorithm which runs faster
%       than mine without any doubt, ╮(╯▽╰)╭ . Ronan pointed a error in
%       the code,thanks for his correction. Note that at the end of this
%       code, there are some demonstration code,please remove in your work.
%
% F = hogcalculator(img, cellpw, cellph, nblockw, nblockh,
%    nthet, overlap, isglobalinterpolate, issigned, normmethod)
%
% IMG:
%       IMG is the input image.
%
% CELLPW, CELLPH:
%       CELLPW and CELLPH are cell's pixel width and height respectively.
%
% NBLOCKW, NBLCOKH:
%       NBLOCKW and NBLCOKH are block size counted by cells number in x and
%       y directions respectively.
%
% NTHET, ISSIGNED:
%       NTHET is the number of the bins of the histogram of oriented
%       gradient. The histogram of oriented gradient ranges from 0 to pi in
%       'unsigned' condition while to 2*pi in 'signed' condition, which can
%       be specified through setting the value of the variable ISSIGNED by
%       the string 'unsigned' or 'signed'.
%
% OVERLAP:
%       OVERLAP is the overlap proportion of two neighboring block.
%
% ISGLOBALINTERPOLATE:
%       ISGLOBALINTERPOLATE specifies whether the trilinear interpolation
%       is done in a single global 3d histogram of the whole detecting
%       window by the string 'globalinterpolate' or in each local 3d
%       histogram corresponding to respective blocks by the string
%       'localinterpolate' which is in strict accordance with the procedure
%       proposed in Dalal's paper. Interpolating in the whole detecting
%       window requires the block's sliding step to be an integral multiple
%       of cell's width and height because the histogram is fixing before
%       interpolate. In fact here the so called 'global interpolation' is
%       a notation given by myself. at first the spatial interpolation is
%       done without any relevant to block's slide position, but when I was
%       doing calculation while OVERLAP is 0.75, something occurred and
%       confused me o__O"… . This let me find that the operation I firstly
%       did is different from which mentioned in Dalal's paper. But this
%       does not mean it is incorrect ^◎^, so I reserve this. As for name,
%       besides 'global interpolate', any others would be all ok, like 'Lady GaGa'
%       or what else, :-).
%
% NORMMETHOD:
%       NORMMETHOD is the block histogram normalized method which can be
%       set as one of the following strings:
%               'none', which means non-normalization;
%               'l1', which means L1-norm normalization;
%               'l2', which means L2-norm normalization;
%               'l1sqrt', which means L1-sqrt-norm normalization;
%               'l2hys', which means L2-hys-norm normalization.
% F:
%       F is a row vector storing the final histogram of all of the blocks
%       one by one in a top-left to bottom-right image scan manner, the
%       cells histogram are stored in the same manner in each block's
%       section of F.
%
% Note that CELLPW*NBLOCKW and CELLPH*NBLOCKH should be equal to IMG's
% width and height respectively.
%
% Here is a demonstration, which all of parameters are set as the
% best value mentioned in Dalal's paper when the window detected is 128*64
% size(128 rows, 64 columns):
%       F = hogcalculator(window, 8, 8, 2, 2, 9, 0.5,
%                               'localinterpolate', 'unsigned', 'l2hys');
% Also the function can be called like:
%       F = hogcalculator(window);
% the other parameters are all set by using the above-mentioned "dalal's
% best value" as default.
%

if nargin < 2
% set default parameters value.
cellpw = 8;
cellph = 8;
nblockw = 2;
nblockh = 2;
nthet = 9;
overlap = 0.5;
isglobalinterpolate = 'localinterpolate';
issigned = 'unsigned';
normmethod = 'l2hys';
else
if nargin < 10
error('Input parameters are not enough.');
end
end

% check parameters's validity.
[M, N, K] = size(img);
if mod(M,cellph*nblockh) ~= 0
error('IMG''s height should be an integral multiple of CELLPH*NBLOCKH.');
end
if mod(N,cellpw*nblockw) ~= 0
error('IMG''s width should be an integral multiple of CELLPW*NBLOCKW.');
end
if mod((1-overlap)*cellpw*nblockw, cellpw) ~= 0 ||...
mod((1-overlap)*cellph*nblockh, cellph) ~= 0
str1 = 'Incorrect OVERLAP or ISGLOBALINTERPOLATE parameter';
str2 = ', slide step should be an intergral multiple of cell size';
error([str1, str2]);
end

% set the standard deviation of gaussian spatial weight window.
delta = cellpw*nblockw * 0.5;

% calculate gradient scale matrix.
hx = [-1,0,1];
hy = -hx';
gradscalx = imfilter(double(img),hx);
gradscaly = imfilter(double(img),hy);

%
if K > 1
%    gradscalx = max(max(gradscalx(:,:,1),gradscalx(:,:,2)), gradscalx(:,:,3));
%    gradscaly = max(max(gradscaly(:,:,1),gradscaly(:,:,2)), gradscaly(:,:,3));
maxgrad = sqrt(double(gradscalx.*gradscalx + gradscaly.*gradscaly));
[gradscal, gidx] = max(maxgrad,[],3);
gxtemp = zeros(M,N);
gytemp = gxtemp;
for kn = 1:K
[rowidx, colidx] = ind2sub(size(gidx),find(gidx==kn));
gxtemp(rowidx, colidx) = gradscalx(rowidx,colidx,kn);
gytemp(rowidx, colidx) =gradscaly(rowidx,colidx,kn);
end
gradscalx = gxtemp;
gradscaly = gytemp;
else
gradscal = sqrt(double(gradscalx.*gradscalx + gradscaly.*gradscaly));
end

% calculate gradient orientation matrix.
% plus small number for avoiding dividing zero.
gradscalxplus = gradscalx+ones(size(gradscalx))*0.0001;
gradorient = zeros(M,N);
% unsigned situation: orientation region is 0 to pi.
if strcmp(issigned, 'unsigned') == 1
gradorient =...
atan(gradscaly./gradscalxplus) + pi/2;
or = 1;
else
% signed situation: orientation region is 0 to 2*pi.
if strcmp(issigned, 'signed') == 1
idx = find(gradscalx >= 0 & gradscaly >= 0);
gradorient(idx) = atan(gradscaly(idx)./gradscalxplus(idx));
idx = find(gradscalx < 0);
gradorient(idx) = atan(gradscaly(idx)./gradscalxplus(idx)) + pi;
idx = find(gradscalx >= 0 & gradscaly < 0);
gradorient(idx) = atan(gradscaly(idx)./gradscalxplus(idx)) + 2*pi;
or = 2;
else
error('Incorrect ISSIGNED parameter.');
end
end

% calculate block slide step.
xbstride = cellpw*nblockw*(1-overlap);
ybstride = cellph*nblockh*(1-overlap);
xbstridend = N - cellpw*nblockw + 1;
ybstridend = M - cellph*nblockh + 1;

% calculate the total blocks number in the window detected, which is
% ntotalbh*ntotalbw.
ntotalbh = ((M-cellph*nblockh)/ybstride)+1;
ntotalbw = ((N-cellpw*nblockw)/xbstride)+1;

% generate the matrix hist3dbig for storing the 3-dimensions histogram. the
% matrix covers the whole image in the 'globalinterpolate' condition or
% covers the local block in the 'localinterpolate' condition. The matrix is
% bigger than the area where it covers by adding additional elements
% (corresponding to the cells) to the surround for calculation convenience.
if strcmp(isglobalinterpolate, 'globalinterpolate') == 1
ncellx = N / cellpw;
ncelly = M / cellph;
hist3dbig = zeros(ncelly+2, ncellx+2, nthet+2);
F = zeros(1, (M/cellph-1)*(N/cellpw-1)*nblockw*nblockh*nthet);
glbalinter = 1;
else
if strcmp(isglobalinterpolate, 'localinterpolate') == 1
hist3dbig = zeros(nblockh+2, nblockw+2, nthet+2);
F = zeros(1, ntotalbh*ntotalbw*nblockw*nblockh*nthet);
glbalinter = 0;
else
error('Incorrect ISGLOBALINTERPOLATE parameter.')
end
end

% generate the matrix for storing histogram of one block;
sF = zeros(1, nblockw*nblockh*nthet);

% generate gaussian spatial weight.
[gaussx, gaussy] = meshgrid(0:(cellpw*nblockw-1), 0:(cellph*nblockh-1));
weight = exp(-((gaussx-(cellpw*nblockw-1)/2)...
.*(gaussx-(cellpw*nblockw-1)/2)+(gaussy-(cellph*nblockh-1)/2)...
.*(gaussy-(cellph*nblockh-1)/2))/(delta*delta));

% vote for histogram. there are two situations according to the interpolate
% condition('global' interpolate or local interpolate). The hist3d which is
% generated from the 'bigger' matrix hist3dbig is the final histogram.
if glbalinter == 1
xbstep = nblockw*cellpw;
ybstep = nblockh*cellph;
else
xbstep = xbstride;
ybstep = ybstride;
end
% block slide loop
for btly = 1:ybstep:ybstridend
for btlx = 1:xbstep:xbstridend
for bi = 1:(cellph*nblockh)
for bj = 1:(cellpw*nblockw)

i = btly + bi - 1;
j = btlx + bj - 1;
gaussweight = weight(bi,bj);

gs = gradscal(i,j);
go = gradorient(i,j);

if glbalinter == 1
jorbj = j;
iorbi = i;
else
jorbj = bj;
iorbi = bi;
end

% calculate bin index of hist3dbig
binx1 = floor((jorbj-1+cellpw/2)/cellpw) + 1;
biny1 = floor((iorbi-1+cellph/2)/cellph) + 1;
binz1 = floor((go+(or*pi/nthet)/2)/(or*pi/nthet)) + 1;

if gs < 1E-5
continue;
end

binx2 = binx1 + 1;
biny2 = biny1 + 1;
binz2 = binz1 + 1;

x1 = (binx1-1.5)*cellpw + 0.5;
y1 = (biny1-1.5)*cellph + 0.5;
z1 = (binz1-1.5)*(or*pi/nthet);

% trilinear interpolation.
hist3dbig(biny1,binx1,binz1) =...
hist3dbig(biny1,binx1,binz1) + gs*gaussweight...
* (1-(jorbj-x1)/cellpw)*(1-(iorbi-y1)/cellph)...
*(1-(go-z1)/(or*pi/nthet));
hist3dbig(biny1,binx1,binz2) =...
hist3dbig(biny1,binx1,binz2) + gs*gaussweight...
* (1-(jorbj-x1)/cellpw)*(1-(iorbi-y1)/cellph)...
*((go-z1)/(or*pi/nthet));
hist3dbig(biny2,binx1,binz1) =...
hist3dbig(biny2,binx1,binz1) + gs*gaussweight...
* (1-(jorbj-x1)/cellpw)*((iorbi-y1)/cellph)...
*(1-(go-z1)/(or*pi/nthet));
hist3dbig(biny2,binx1,binz2) =...
hist3dbig(biny2,binx1,binz2) + gs*gaussweight...
* (1-(jorbj-x1)/cellpw)*((iorbi-y1)/cellph)...
*((go-z1)/(or*pi/nthet));
hist3dbig(biny1,binx2,binz1) =...
hist3dbig(biny1,binx2,binz1) + gs*gaussweight...
* ((jorbj-x1)/cellpw)*(1-(iorbi-y1)/cellph)...
*(1-(go-z1)/(or*pi/nthet));
hist3dbig(biny1,binx2,binz2) =...
hist3dbig(biny1,binx2,binz2) + gs*gaussweight...
* ((jorbj-x1)/cellpw)*(1-(iorbi-y1)/cellph)...
*((go-z1)/(or*pi/nthet));
hist3dbig(biny2,binx2,binz1) =...
hist3dbig(biny2,binx2,binz1) + gs*gaussweight...
* ((jorbj-x1)/cellpw)*((iorbi-y1)/cellph)...
*(1-(go-z1)/(or*pi/nthet));
hist3dbig(biny2,binx2,binz2) =...
hist3dbig(biny2,binx2,binz2) + gs*gaussweight...
* ((jorbj-x1)/cellpw)*((iorbi-y1)/cellph)...
*((go-z1)/(or*pi/nthet));
end
end

% In the local interpolate condition. F is generated in this block
% slide loop. hist3dbig should be cleared in each loop.
if glbalinter == 0
if or == 2
hist3dbig(:,:,2) = hist3dbig(:,:,2)...
+ hist3dbig(:,:,nthet+2);
hist3dbig(:,:,(nthet+1)) =...
hist3dbig(:,:,(nthet+1)) + hist3dbig(:,:,1);
end
hist3d = hist3dbig(2:(nblockh+1), 2:(nblockw+1), 2:(nthet+1));
for ibin = 1:nblockh
for jbin = 1:nblockw
idsF = nthet*((ibin-1)*nblockw+jbin-1)+1;
idsF = idsF:(idsF+nthet-1);
sF(idsF) = hist3d(ibin,jbin,:);
end
end
iblock = ((btly-1)/ybstride)*ntotalbw +...
((btlx-1)/xbstride) + 1;
idF = (iblock-1)*nblockw*nblockh*nthet+1;
idF = idF:(idF+nblockw*nblockh*nthet-1);
F(idF) = sF;
hist3dbig(:,:,:) = 0;
end
end
end

% In the global interpolate condition. F is generated here outside the
% block slide loop
if glbalinter == 1
ncellx = N / cellpw;
ncelly = M / cellph;
if or == 2
hist3dbig(:,:,2) = hist3dbig(:,:,2) + hist3dbig(:,:,nthet+2);
hist3dbig(:,:,(nthet+1)) = hist3dbig(:,:,(nthet+1)) + hist3dbig(:,:,1);
end
hist3d = hist3dbig(2:(ncelly+1), 2:(ncellx+1), 2:(nthet+1));

iblock = 1;
for btly = 1:ybstride:ybstridend
for btlx = 1:xbstride:xbstridend
binidx = floor((btlx-1)/cellpw)+1;
binidy = floor((btly-1)/cellph)+1;
idF = (iblock-1)*nblockw*nblockh*nthet+1;
idF = idF:(idF+nblockw*nblockh*nthet-1);
for ibin = 1:nblockh
for jbin = 1:nblockw
idsF = nthet*((ibin-1)*nblockw+jbin-1)+1;
idsF = idsF:(idsF+nthet-1);
sF(idsF) = hist3d(binidy+ibin-1, binidx+jbin-1, :);
end
end
F(idF) = sF;
iblock = iblock + 1;
end
end
end

% adjust the negative value caused by accuracy of floating-point
% operations.these value's scale is very small, usually at E-03 magnitude
% while others will be E+02 or E+03 before normalization.
F(F<0) = 0;

% block normalization.
e = 0.001;
l2hysthreshold = 0.2;
fslidestep = nblockw*nblockh*nthet;
switch normmethod
case 'none'
case 'l1'
for fi = 1:fslidestep:size(F,2)
div = sum(F(fi:(fi+fslidestep-1)));
F(fi:(fi+fslidestep-1)) = F(fi:(fi+fslidestep-1))/(div+e);
end
case 'l1sqrt'
for fi = 1:fslidestep:size(F,2)
div = sum(F(fi:(fi+fslidestep-1)));
F(fi:(fi+fslidestep-1)) = sqrt(F(fi:(fi+fslidestep-1))/(div+e));
end
case 'l2'
for fi = 1:fslidestep:size(F,2)
sF = F(fi:(fi+fslidestep-1)).*F(fi:(fi+fslidestep-1));
div = sqrt(sum(sF)+e*e);
F(fi:(fi+fslidestep-1)) = F(fi:(fi+fslidestep-1))/div;
end
case 'l2hys'
for fi = 1:fslidestep:size(F,2)
sF = F(fi:(fi+fslidestep-1)).*F(fi:(fi+fslidestep-1));
div = sqrt(sum(sF)+e*e);
sF = F(fi:(fi+fslidestep-1))/div;
sF(sF>l2hysthreshold) = l2hysthreshold;
div = sqrt(sum(sF.*sF)+e*e);
F(fi:(fi+fslidestep-1)) = sF/div;
end
otherwise
error('Incorrect NORMMETHOD parameter.');
end

关于计算梯度方向角的:
首先用[-1,0,1]梯度算子对原图像做卷积运算,得到x方向(水平方向,以向右为正方向)的梯度分量gradscalx,然后用[1,0,-1]’梯度算子对原图像做卷积运算,得到y方向(竖直方向,以向上为正方向)的梯度分量gradscaly。然后当gradscalx>=0, gradscaly>=0时,说明梯度方向是朝向第一象限的,当gradscalx>=0, gradscaly<0时,说明梯度方向是朝向第二象限的,诸如此类,结合象限信息,就可以利用反正切函数atan求出在signed和unsigned各自情况下正确的梯度角度.

关于扫描循环(四层for循环…有没有快一点的?有!但是我功力不够。。当时没编出来,就只好还是来四层for):

假设检测窗为64(列)*128(行)大小,block为16*16大小,每个block划分为4个cell,block每次滑动8个像素(也就是一个cell的宽),以及梯度方向划分为9个区间,在0~180度范围内统计,以下的说明都以上述假设为例.

btly与btlx分别表示block所在位置左上角点处的坐标。对于前述假设,一个检测窗内会有105个block存在,因此第一个block左上角的坐标是(1,1),第二个是(9,1)…,此行最后一个是block的左上角坐标是(49,1),然后下一个block就需要向下滑动8个像素,并回到最左边,此时的block左上角坐标为(1,9),接着block重新开始新的横向滑动…如此这般,在检测窗内最后一个block的坐标就是(49,113).

block每滑动到一个新的位置,就需要停下来计算它内部的那四个cell中的梯度方向直方图.(bj,bi)就是来存储cell左上角的坐标的(cell的坐标以block左上角为原点).

(j,i)就表示cell中的像素在整个检测窗(64*128的图像)中的坐标.另外,我在程序里有个jorbj与iorbi,这在Localinterpolate的情况下(也就是标准的原始HOG情况),就是bj与bi.

关于hist3dbig:

这是一个三维的矩阵,用来存储三维直方图。最常见的一维的直方图是这个样子,

二维直方图呢?是这个样子,一个一个的柱子是一个统计bin,柱子的高低代表统计值的大小


三维直方图呢?是这个样子,立体的一个一个的小格子,每个小格子是一个统计bin, 小格子用来装统计值。以上面的例子,那么对一个block来说,它的直方图是下面这样的:

再来说线性插值,线性插值时,一个统计值需被“按一定比例分配”到这个统计点最邻近的区间中去,下面的图显示了一维直方图时,落在虚线标记范围内的统计点,它最近邻的区间就是标有红色圆点的两个区间

若是二维直方图,那落在如下虚线矩形中的统计点,周围的这四个统计区间就是它最近邻的区间。这个虚线矩形由四个统计区间各自的1/4组成。

三维直方图,对一个统计点来说,它的最近邻的区间有八个,如下图,可以想象一下,只有当这个统计点落在由如下八个统计区间各自的1/8组成的一个立方体内内时,这八个区间才是对统计点最近邻的。

统计时如何分配权重呢?以一维直方图简单说一下线性插值的意思,对于下面绿色小方点(x)的统计值来说,假设标红点的两个bin的中心位置分别为x1,x2,那么对于x,它的分配权重为左边bin: 1-(x-x1)/s, 即 1-a/s = b/s, 右边bin: 1-(x2-x)/s, 即1-b/s = a/s.

类似,那么对三维直方图来说,统计时的累积式(从Dalal的论文里截来的)就是:

上面,w 就是准备被分配的统计值。(x1,y1,z1)…共八个点表示八个统计区间的中心位置坐标,上式用h(x1,y1,z1)这样的标记来表示所要累积的统计区间。我在编程时就使用的这个式子,只不过我用bin的下标号来表示bin块,就像前面三维直方图示意中(binx=1,biny=2,binθ=9),不过在程序中θ轴是用z轴表示了。

binx1 = floor((jorbj-1+cellpw/2)/cellpw) + 1;
biny1 = floor((iorbi-1+cellph/2)/cellph) + 1;
binz1 = floor((go+(or*pi/nthet)/2)/(or*pi/nthet)) + 1;
binx2 = binx1 + 1;
biny2 = biny1 + 1;
binz2 = binz1 + 1;

这几句,就是用来计算八个统计区间中心点的坐标的。

在计算前面所讲的统计区间的中心坐标,分配权值之前,我为了处理边缘时程序简洁点,就给那个2*2*9的立体直方图外边又包了一层,形成了一个4*4*11的三维直方图(示意图如下),原来的2*2*9直方图就是被包在中间的部分。这样,在原来直方图里坐标为(binx=1,biny=2,binz=9)的bin,在新的直方图里坐标为(binx=2,biny=3,binz=10)。

对上面的4*4*11的直方图来个与xoy平面平行的剖面图:

粗实线框就是原三维直方图的剖面,也就是一个block,对于像落在粗实线框与粗虚线框之间的点,其最近邻区间是不够8个的,我为了写程序时省点脑力。。。,就用外扩了的这一圈bin,这样落在粗实线框与粗虚线框之间的统计点有了8个区间,用matlab编程时,那个四层for循环中的部分就只用把那八个累积公式写上,也不用判断是不是在落在像上面粗实线框与粗虚线框之间的那种区域。在程序中2*2*9的直方图为hist3d,4*4*11的直方图为hist3dbig.当在这个hist3dbig中计算都结束后,我把外层这一圈剥去,就是hist3d了。

有了这些准备,我就可以计算出当前像素点的梯度方向幅值应该往hist3dbig中的哪八个bin块累积了。binx1,biny1,binz1 在这里就是那个八个bin块之中离  当前要统计的像素点在直方图中对应的位置  最接近的bin块的下标。binx2,biny2,binz2对应就是最远的bin块的下标了。x1,y1,z1就是bin块(binx1,biny1,binz1)中心点对应的实际像素所在的位置(x1,y1)与梯度方向的角度(z1). 我仍然以原block(即没扩前的block)左上角处作为x1,y1的原点,因为matlab以1作为图像像素索引的开始,我把原点就认为是(1,1),那(1,1)左边外扩出来的部分,就给以0,-1,-2,-3…这样的坐标,向上也类似,如下图所示,(1,1)位置为红点所示,蓝点处坐标就是(-3,1).

扩展出来的绿块的下标是(binx=1,biny=1,binz1=1),由于像素坐标在红点处为(1,1),而黄块才是block的第一个cell,对应bin块的下标(2,2).因为下标设计的原因,我在求x1,y1,z1时减了1.5而非0.5.

x1 = (binx1-1.5)*cellpw + 0.5;
y1 = (biny1-1.5)*cellph + 0.5;
z1 = (binz1-1.5)*(or*pi/nthet);

上面的式子中x1,y1还加了0.5,因为像素坐标是离散的,而第一个坐标总是从1开始,这样对如图中第一个cell的中心(黑点)处应该是4.5. z1没加0.5,是因为角度值是从0开始的,并且是连续的。

在signed(即梯度方向从0度到360度)情况下,因为实际上角度的投票区间是首尾相接环形的,若统计间隔是40度,那么0-40度和320-360度就是相邻区间,那么在4*4*11的直方图中,投给binz==11区间(相当于360-380度)的值应该返给binz==2(0-40度),投给binz==1区间的值应该返给binz==10区间,如4*4*11直方图中所示,对应在程序中就是

if or == 2
hist3dbig(:,:,2) = hist3dbig(:,:,2) + hist3dbig(:,:,nthet+2);
hist3dbig(:,:,(nthet+1)) = hist3dbig(:,:,(nthet+1)) + hist3dbig(:,:,1);
end
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

生活在西班牙

自己动手丰衣足食

BlueAsteroid

Just another WordPress.com site

Jing's Blog

Just another WordPress.com site

Start from here......

我的心情魔方

天才遠私廚

希望能做一個分享各種資訊的好地方

语义噪声

西瓜大丸子汤的博客

笑对人生,傲立寰宇

Just another WordPress.com site

Where On Earth Is Waldo?

A Project By Melanie Coles

the Serious Computer Vision Blog

A blog about computer vision and serious stuff

Cauthy's Blog

paper review...

Cornell Computer Vision Seminar Blog

Blog for CS 7670 - Special Topics in Computer Vision

datarazzi

Life through nerd-colored glasses

Luciana Haill

Brainwaves Augmenting Consciousness

槑烎

1,2,∞

Dr Paul Tennent

and the university of nottingham

turn off the lights, please

A bunch of random, thinned and stateless thoughts around the Web

%d bloggers like this: