Understanding Harris corner detector
Let’s first go over Harris detector a little bit. For a basic idea about Harris detector, check textbooks or opencv or blogs. For its intuition, check its precursor Movarec operator, which explains why we want to maximize the variation within a window to find a corner. The key to Harris detector is the variation of intensity within a sliding window (with displacement
in the x direction and
in the y direction)
where:
is the window weighting function at position
is the intensity at (x,y)
is the intensity at the moved window
The aim is to maximize . Applying Taylor expansion and some arithmetic operations, we can get
where is the gradient at
. Matrix
is known as structure tensor of a pixel. It actually a characterization of information of all pixels within the window. Then we calculate the eigenvalues
and
of matrix
to determine if window corresponds to a corner. (I)
- If
and
then this pixel
has no features of interest.
- If
and
has some large positive value, then an edge is found.
- If
and
have large positive values, then a corner is found.
[Note: to avoid computing the eigenvalues which is computationally expensive, in original Harris detector, the authors suggested using the following score:
![]()
to determine if a point is a corner.]
The question is WHY? Why does the matrix have the capacity to determine the cornerness? Here, we look around to the covariance matrix
of gradient
at a pixel. Let
. By definition of covariance matrix, we have
The last step is derived based on the the assumption that the mean of derivatives and
is zeros, i.e.
.
On the other hand, the structure tensor is as follows if we apply an averaging filter over the time dimension (= we give uniform weight over the pixels within the pixels):
where is total number of pixels within the window, and
is the average of
.
It can be seen that structure tensor is actually an unbiased estimate of the covariance matrix of the gradients for the pixels within the window. Therefore, any findings/conclusions about covariance matrix could be used to analyze structure tensors.
Let’s look at an example showing how the derivatives are distributed for different types of image patches (i.e. the window). The following figures are adapted from Robert Collins‘s slides. In this example, the image patches are from three different types: linear edge, flat area and corner. You can image that we are testing if the pixel at the center is a corner (feature point).
The first step is calculating the derivatives and
for each pixel in the image, then the distributions of (
,
) are shown in the figure below. Obviously, the distributions are discriminative fro these three different type of pixels (on the edge, on flat area and a corner).(II)
- For corners, the ranges in both
and
are large.
- For points on an edge, one derivative has wide distribution while the other is almost all near zeros.
- For points of a flat area, both derivatives are around zeros.
This observation is indeed the reason behind (I) we discussed above.
In Relationship between eigenvectors and directions of data distribution, we have shown that the eigenvectors of a covariance matrix are the same as the directions of principle component (i.e. the axes of a ellipsoid enclosing the data points), and the eigenvalues measure the variances of date points along eigenvectors. (Click Read more to see the relationship between eigenvalues and the semi-axes) Therefore, if the smallest eigenvalue is big enough, then it means the data have large variance along all different directions–it’s a corner!
In a word, the structure tensor is actually the covariance matrix of gradients for pixels around the pixel investigated, the the reason for current eigenvalue-based analysis is based on the property of covariance matrices.
[OPENCV] Feature detectors and descriptors
For a simple example of how to setup and use them, see [OPENCV] OpenCV+Eclipse|Qt|VS2010
For many computer vision tasks, the first step is usually extracting features from images. It consists of two parts: feature detection and description. By feature detection, we mean to find the pixels (or regions, objects) of interest in an image, which are represented by cv::KeyPoint. They are corresponding to the corners of objects in the image. OpenCV implements many popular feature points detection methods, such as SIFT, SURF, ORB, GoodFeatureToTrack and so on.
After these feature points are located, the next step is to describe them. An intuitive description of a feature point could be its intensity/color value. But a single intensity/color value does not provide sufficiently discriminative information so that this feature point can be uniquely matched to feature points in another image. Usually we use the information around a feature point to represent it, i.e. we use information of many pixels to represent one feature point. Based on Hubel & Wiesel’s research on information processing, orientation is the most sensitive factor to visual system. That’s why most feature techniques are based on orientation to describe feature points. For example, SIFT descriptor uses the normalized orientation histogram to describe a feature point. See figure below. Since this post is not about how the descriptors are designed, interested readers should read their papers.
To provide consistent programming interface, OpenCV designs the feature detectors and descriptor extractors following OO principle. Below is the class hierarchy of most detectors and descriptors for version 2.4.1. FeatureDetector and DescriptorExtractor are the base class for detectors and descriptors, respectively. Feature2d simplifies detection and extraction by deriving from FeatureDetector and DescriptorExtractor. But Feature2d is still an abstract class because it doesn’t implement the virtual function detectImpl() and computeImpl().
Classes SURF, SIFT, BRISK and ORB (and others) are concrete classes which are both detectors and descriptor extractors. In order to explicitly use them as detectors or descriptor extractors, aliases are defined. For example,
typedef SURF SurfFeatureDetector; typedef SURF SurfDescriptorExtractor; typedef SIFT SiftFeatureDetector; typedef SIFT SiftDescriptorExtractor; typedef ORB OrbFeatureDetector; typedef ORB OrbDescriptorExtractor;
From the perspective of functionality, there’s no distinction between SurfFeatureDetector and SurfDescriptorExtractor. They are exactly the same thing except they have different names. The same is true for SiftFeatureDetecor and SiftDescriptorExtractor, and others.
From this class hierarchy diagram, it can also be seen that FAST, GFTTDetector and DenseFeatureDetector are only feature point detectors. After obtaining the feature points (std::vector<cv::KeyPoint>), we can use SURF, SIFT or any other descriptor extractors to get a description for these feature points. std::vector<cv::KeyPoint> is the data structure for data passing.
Relationship between eigenvectors and directions of data distribution
For approaches based on dimension reduction, such as Principle Component Analysis, one critical question is “To which direction should we project the data?” Given observations of variable
, we might compute the covariance matrix, and then use its eigenvectors as the direction of projection. Lots of approaches use this technique (e.g. Harris corner detector), but WHY? What’s the reason behind? This posts explains.

In the figure above, we illustrate a distribution of a 2D dataset. It’s already demeaned. The discussion below applies to any dimension size. Suppose each data point is -dimensional
. Intuitively, we want to find linear functions of
, which project
into a new space. Since the data is already demeaned,
which means the origin of the axes is now at the center of the data, and the linear function has no intercept part.
We start by defining the first linear function (or projection): , where
is the coefficients of the linear function (see the figure above for 2D projection where
. Looking at the data plot above, the line of
should pass through the data points, and the projected points should have largest span. Mathematically speaking, we want to maximize the data variance after projecting them to a line
, i.e. to find
so that
Example: For 2D data, ,
.
. It’s easy to show that the expectation
. The variance
where is the covariance matrix of the original data. It is worth noticing that the finding
can be extended to any higher dimensional variable
. So right now our aim becomes
Without any constraint, we could always pick a larger so there’s no solution to
. We choose normalized
, which means
.
Solution: Now our problem becomes a optimization problem subject to a constraint. We use Lagrange multipliers to maximize the function
with respect to . This results in
Suppose the solution to this equation is and
.
It can be easily seen that the is the eigenvector of
. When the line (represented by
) is in the same direction as the eigenvector associated with largest eigenvalue, the variance will be the largest when we project the original data onto this line, and the variable is:
Therefore, we should choose the eigenvector of the covariance matrix with largest eigenvalue as the basis of first dimension (first principle component), and the corresponding eigenvalue is indeed the variance of that projected data in that dimension.
__________________
Following the same deduction, we can conclude that the -th eigenvector
is the $k$-th principle component, and
. For example, for
,
(The second due to .)
Use Lagrange multiplier again, you will get
___________________
If you read here, I hopeit is clear now the reason why the eigenvector with largest eigenvalue coincide with the direction of biggest variance and why the eigenvectors of a covariance matrix are used as the directions of principle components.
Note: One more question in my mind is why we are so furtunate to have such a simple yet powerful solution, but I want to stop here today.
Statistical Data Mining Basics
Statistical Data Mining Tutorials
by Andrew Moore
The following links point to a set of tutorials on many aspects of statistical data mining, including the foundations of probability, the foundations of statistical data analysis, and most of the classic machine learning and data mining algorithms.
Articles on Doctoral Education
A deeper look into the “80% of PhDs who do not become professors”
Doctorate recipients holding tenure and tenure-track appointments at academic institutions
Improving Graduate Education to Support a Branching Career Pipeline
[OPENGL]Some OpenGL Examples
Here are some OpenGL programs written for course assignments, from the very basic one to some advanced application. The codes are hosted on github:https://github.com/gccheng/openGL-tutorials
1. Rotating pendulum
2. Hand & fingers
3. Solar System
基于线框模型的简单物体绘制与操作。
4. Array operation (Rotation)
绘制一个函数的图像,基于Array进行绘制。下面的图形是函数实时绘制的结果。
function from gc-cheng@hotmail.com on Vimeo.
5. Quaternion algebra
使用quaternion表示旋转、缩放等操作。由于使用了Quaternion,极大地简化了操作和代码:
planet-quaternion algebra from gc-cheng@hotmail.com on Vimeo.
6. 分段贝塞尔(Bezier)曲线
一段Bezier曲线是由四个点确定的,两段Bezier曲线是将7个点组成的一条连续可导的Bezier曲线,的原理可以查询Wikipedia中的文章。
实现代码:prog6_cheng.cpp
实现效果:
Last week I attended the commencement ceremony, and I really found most of the graduates were females.
http://usat.ly/MBiBha Women’s colleges struggle to keep enrollment As enrollment numbers drop, women’s colleges are forced to make decisions about their admission policies. To view this story, click the link or paste it into your browser.
温故知新:CXX/JAVA
上周花了点时间把《The C++ Standard Library: A Totorial and Reference》浏览了一下,有段时间没有写长的C++程序了,温习知新。天天捣腾那么点Matlab程序,要不是CV领域最强大的程序库是C++写的,不然编程能力真的要倒退好几年了。会继续在闲暇之余温习温习基本的数据结构和算法。
Project STL: http://compilr.com/gccheng/stl
1. 使用迭代器适配器(Iterator Adapter)进行容器拷贝: container_copy
2. 使用流迭代器: stream_iterator
3. 函数对象(Function Object)如何实现和使用: my_foreach
4. C++11中新增的array容器,提供了cbegin(), cend(),没深研究如何以前的容器没提供: it_traverse
Project JavaAlgorithm: http://compilr.com/gccheng/javaalgorithm
1. 树的四种遍历: TreeTraversal
2. 统计词频: WordCount
Office VBA二次开发
看到两篇文章:《为什么我们不重视Office开发——与郭安定谈话想到的 》 和《也谈为什么我们不重视Office开发--看孟岩说有感 》,结论似乎是基于Office的二次开发主要适用于一些内部的小项目,对于商业化开发,似乎就不太合适。
联想到以前自己大概做过三四个Excel的VBA开发,使用自动化以后,确实提高了工作效率,这包括以前给老婆单位做的一个通过,手工统计每个员工的工时,这可能需要很多时间:每个人每天上几个小时(每天可能不同,小时制),一个月来了几天,几百号人。第二个是去年帮一个同学弄的基于Excel的员工自动签到。第三个是一个从该表格中提取数据,按照规定格式,自动打印的功能。
对于第三个,小册子是由上级部门打印好分发下来的,数据则是每个乡镇自己统计的Excel表格数据,现在要做的工作就是把表格里的每一行使用打印机打印到预制好的小册子上。由于工作是在基层乡镇,打印室一半可能就是用Word或Excel设置要每一行数据在纸上的位置(模板),然后把每一行中的各列数据添加到这个Word或Excel中,然后打印到小册子上。这种工作对每一行都要重复一下。如果有几万人,就算每个用2分钟,这个工作量也是很大的。而且小册子上的有些位置的数据可能不是直接从数据表中得到的(例如是多项的求和等)。
所以当时就根据已有的经验,设置了一个Excel表格数据格式化自动打印的程序,其实程序非常简单:只要打印室的人员根据小册子的要求设计好模板(这个是一次性工作,而且是他们非常擅长的),然后按一下“打印”按钮,剩下的工作就是等待打印完成了。
就是这个简单的程序,节省了大量的时间和精力,而且这种工作每年都有,每年都可以用,即使有小改动,也是很轻易完成的。
从这里可以获得一份示意Excel。
如何从任意分布采样How to sample from arbitrary standard distributions
The topic of this article is about how to produce data following the specified simple distribution. For example, the question we want to answer is like “can you generate 1000 data points from the exponential distribution?”.
Prior to the discussion of today’s topic, let’s first look at the random number generation methods available in prevalent programming languages. Almost every popular languange provides the pseudo-random number generation, most of which have methods to produce data from uniform distribution. For example, to generate an integral number uniformly from {0, 1, 2, …, 9}, we have
/* C style */ int randInt = random (10); // C++ style srand((unsigned)time(0)); int randInt = rand() % 10; // Java style Random randomGenerator = new Random(); int randInt = randomGenerator.nextInt(10);
Why do we need random numbers in these languages? Part of the reasons is random numbers can be used to simulate different scenaria in which realistic data are hard to obtain. For example, in Mahattan project, it’s almost impossible to use real nuclear explosion data to verify the system so that Markov chain Monte Carlo sampling method was proposed to generate simulation data. For software test, we also need looooooots of different inputs to test the target software, and the random inputs can be used based on random numbers.
Why is uniform distribtion usually implmented? I guess it is because of its simplicity: itself (the distributoin and its implementation) is simple, and it’s relatively simple to generate other distribution using uniform distribution. Interested reader can learn how the implementation are implemented in C/C++/Java.
Here, we will learn how to transform uniform distribution to other simple distributions. (Actullay the idea can be applied to the transformation from one distribution to another) These distribution are “simple” in terms that the inverse of its cumulative distribution function (CDF) can be easily obtained. You will see this later. Suppose we’ve already known how to sample from uniform distribution (*), i.e. we can generate data over the interval (0,1) from a uniform distribution. Now we want to sample
from the probability distribution of
(f(y) for continuous variable and P(y) for discrete).
Let’s look at a discrete example. Let , and
,
,
,
. We want to generate 100 values from
so that these values have the same (similar) distribution as
. Firstly, the interval (0,1) is divided into 4 intervals [F(0)=0, F(1)], [F(1), F(2)], [F(2), F(3)], [F(3), F(4)] as shown in the figure below where
:
The width of interval is
. We then draw one point
from (0, 1) uniformly (since we know how to draw samples from uniform distribution (*) ), and search the index
using
and assign
which has the probability
. Repeat this procedure for 100 times, we can get 100
values, which have the distribution
.
Think more about this simple example and we can find the procedure is: (1) sample from uniform distribution to get a value ; (2) solve
from
using the probability distribution funciton
:
or its generalized form
. In this way, we can sample from any discrete distributions whose probability desitribution functions are known.
Extend this to continuous distributions, this basic idea is similar. Suppose we want to sample from distribution , and its cumulative distribution function (or distribution function) is
as shown in the following figure. Here the vertical axis is three-in-one:
,
and
. Because the range of
is always in (0,1), we can treat it as an interval from which we uniformly draw samples
. Following the same procedure as for discrete case, we draw a point
over (0,1) uniformly, and treat it as the value of
for some unknown
(analogous to
in discrete case), i.e.
(1)
Now the problem is “can we get a unique from
?” or “is
inversible?”. Simply put, “Maybe. There might be several
‘s which satisfy the equation”.

We know that the CDF () of a distribution is monotone non-decreasing. Because
, it is easy to see from equation (1) that
cannot decrease as
increases.
- If CDF
is strict increasing (or
), then
is inversible, and we can get
;
- If CDF
is not strict increasing (or
), then
is not inversible. One may define a generalized inverse distribution function:
, and then assign it to
.
Repeat this process, we can get as many values as we want.
One can verify that the probability distribution function of is
and thus the probability distribution is
. We transform the value of
to
using equation (1), and thus the distribution function of
will be
(2)
where the last equation is because is a uniform distribution over (0,1), which means
One can also “feel” from the curve of and
. For
‘s whose probability
are big, the corresponding
is steep, which results in large occupation of interval (0, 1) on the vertical axis. Therefore, with large chance the
values will fall in this occupation when we draw samples from (0,1) uniformly, and thus we have larger probability to obtain
s whose probabilities
are large. Readers can try to associate this idea with the discrete example above.
Thus far, we can see the core of the sampling from arbitrary distribution is how to transform from one distribution to the other. The article only talks about “simple” distributions, which mean it’s easy to get the CDF and its inverse, or it’s impossble to apply the method above.
***********************************************************************************
To answer the question we asked at the very beginning, we want to sample from an exponential distribtuion
(3)
where . In this case the lower limit of the integreal in (1) is 0, and so
. Thus, if we transform our uniformly distributed varable
using
, then
will have an exponential distribution.
***
Image histogram equalization is another application of the distribution transformation. One difference of histogram equalization compared with the discussion above is it tries its best to transform a non-uniform distribution (histogram) to a near-uniform distribution (histogram) while keeping the relative order of pixels at different scales. Therefore,
- Compute histogram (probability distribution) of pixels in original image
- Set
- Convert the range of
from (0, 1) to (0, 255). This step is because it’s the target domain is not within (0,1).
Refer to Histogram Equalization in wikipedia and Gonzalez’s DIP for more information.
One limitation of the method discussed above is the computation of inverse of CDF, which in many cases doesn’t have an easy form or easy to compute. We will see how to solve this problem in next blog.






