时间为友,记录点滴。
如果真真得跑过Harris,你肯定会有这样的抱怨:太**的慢了。是的,J.Shi和C.Tomasi也是这么想的,所以,他们俩1994年在其论文“Good Features to Track”中,提出了一种对Harris角点检测算子的改进算法——Shi-Tomasi角点检测算子。
优化思路是什么?
既然是优化,我们先回忆一下Harris怎么做到的?
- 先上数据集:
2. 从数据集中,引申出来Harris
核心思想是:
- 特征值都比较大时,即窗口中含有角点
- 特征值一个较大,一个较小,窗口中含有边缘
- 特征值都比较小,窗口处在平坦区域
所以,Harris引入了公式:
3. 简化算法
从数据集上看,角点的
都是比较大的,如果我们选择特征值中较小的一个大于最小阈值,是不是也会得到强角点?答案是肯定的。
Harris 算法最原始的定义是将黑塞矩阵
的行列式值与 M 的迹相减,再将差值同预先给定的阈值进行比较。所以shi-tomas提出来的公式就为:
好了,有了Harris做铺垫,shi-tomas就好理解多了。
老规矩,OpenCV也实现了shi-tomas算法:
CV_EXPORTS_W void goodFeaturesToTrack( InputArray image, OutputArray corners,
int maxCorners, double qualityLevel, double minDistance,
InputArray mask = noArray(), int blockSize = 3,
bool useHarrisDetector = false, double k = 0.04 );
(API没有用人名,而是用了他们发表的论文名称,这个纪念也是有意思)
- srcGray,原灰度图像
- corners检测到的角点vector<Point>
- maxCorners设置最大角点数
- qualityLevel最小可接受的向量值,常取0.01
- minDistance两点之间的最小距离
- Mat()未设置感兴趣区域
- blockSize计算导数的窗口大小
- useHarrisDetector是否使用Harris角点检测
- k使用Harris角点检测时的k值,使用Harris角点检测时才有意义
好了,就这么多,让我们看看shi-tomas是不是要比Harris快。
C++
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
#include<time.h>
using namespace std;
using namespace cv;
static bool shiTomas(Mat imgOri);
static bool harrisTest(Mat imgOri);
RNG rng(12345);
int main()
{
Mat imgOri = imread("right13.jpg");
if (imgOri.empty())
{
cout << "Cannot load this picture!" << endl;
return false;
}
clock_t start, harrisTime, shiTomasTime;
double totaltime;
Mat imgHarris = imgOri.clone();
Mat imgShiTomas = imgOri.clone();
start = clock();
harrisTest(imgHarris);
harrisTime = clock();
shiTomas(imgShiTomas);
shiTomasTime = clock();
imshow("imgOri", imgOri);
cout << "Harris takes [" << (double)(harrisTime - start) / CLOCKS_PER_SEC << "] s" << endl;
cout << "shiTomas takes [" << (double)(shiTomasTime - harrisTime) / CLOCKS_PER_SEC << "] s" << endl;
waitKey(0);
return true;
}
static bool harrisTest(Mat imgOri)
{
int blockSize = 2;
int apertureSize = 3;
double k = 0.04;
Mat imgGray, imgHarris;
//showImgPara(imgGray);
cvtColor(imgOri, imgGray, COLOR_BGR2GRAY);
imgHarris = Mat::zeros(imgOri.size(), imgOri.type());
cornerHarris(imgGray, imgHarris, blockSize, apertureSize, k);
Mat imgDst, imgDstScale;
imgDst = Mat::zeros(imgHarris.size(), imgHarris.type());
normalize(imgHarris, imgDst, 0, 255, NORM_MINMAX);
convertScaleAbs(imgDst, imgDstScale);
for (int row = 0; row < imgDstScale.rows; row++)
{
for (int col = 0; col < imgDstScale.cols; col++)
{
int rsp = (int)imgDstScale.at<uchar>(row, col);
if (rsp > 85)
{
int b = rng.uniform(0, 256);
int g = rng.uniform(0, 256);
int r = rng.uniform(0, 256);
circle(imgOri, Point(col, row), 5, Scalar(b, g, r), 2);
}
}
}
imshow("imgHarris", imgOri);
return true;
}
static bool shiTomas(Mat imgOri)
{
int maxCorners = 500;
double quality_level = 0.01;
double minDistance = 0.04;
Mat imgGray, imgShiTomas;
cvtColor(imgOri, imgGray, COLOR_BGR2GRAY);
vector<Point2f> corners;
goodFeaturesToTrack(imgGray, corners, maxCorners, quality_level, minDistance, Mat(), 3, false);
for (int i = 0; i < corners.size(); i++) {
int b = rng.uniform(0, 256);
int g = rng.uniform(0, 256);
int r = rng.uniform(0, 256);
circle(imgOri, corners[i], 5, Scalar(b, g, r), 3, 8, 0);
}
imshow("imgShiTomas", imgOri);
return true;
}
Python:
注意:
1. 获取进程时间的接口:time.process_time()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author:lowkeyway time:10/22/2019
import sys
import numpy as np
import cv2 as cv
import time
def shiTomasTest(imgOri):
maxCorners = 500;
quality_level = 0.01;
minDistance = 0.04;
imgGary = cv.cvtColor(imgOri, cv.COLOR_BGR2GRAY)
corners = cv.goodFeaturesToTrack(imgGary, maxCorners, quality_level, minDistance)
for corner in corners:
b = np.random.randint(0, 256)
g = np.random.randint(0, 256)
r = np.random.randint(0, 256)
cv.circle(imgOri, (int(corner[0][0]), int(corner[0][1])), 2, (int(b), int(g), int(r)), 2)
cv.imshow("imgShiTomas", imgOri)
def harrisTest(imgOri):
blockSize = 2
apertureSize = 3
k = 0.04
imgGary = cv.cvtColor(imgOri, cv.COLOR_BGR2GRAY)
imgHarris = cv.cornerHarris(imgGary, blockSize, apertureSize, k)
imgDst = np.zeros(imgHarris.shape, dtype=np.float32)
cv.normalize(imgHarris, imgDst, 0, 255, cv.NORM_MINMAX)
imgDstScale = cv.convertScaleAbs(imgDst)
for row in range(imgDstScale.shape[0]):
for col in range(imgDstScale.shape[1]):
if int(imgDstScale[row, col]) > 85:
b = np.random.randint(0, 256)
g = np.random.randint(0, 256)
r = np.random.randint(0, 256)
cv.circle(imgOri, (col, row), 2, (int(b), int(g), int(r)), 2)
cv.imshow("imgHarrisDst", imgOri)
def main_func(argv):
imgOri = cv.imread("right13.jpg")
if imgOri is None:
print("Cannot load this picture!")
return False
imgHarris = np.copy(imgOri)
imgShiTomas = np.copy(imgOri)
start = time.process_time()
harrisTest(imgHarris)
harrisTime = time.process_time()
shiTomasTest(imgShiTomas)
shiTomasTime = time.process_time()
print("Harris takes {:.2f} s" .format(harrisTime - start))
print("Harris takes {:.2f} s" .format(shiTomasTime - harrisTime))
cv.imshow("imgOri", imgOri)
cv.waitKey(0)
if __name__ == '__main__':
main_func(sys.argv)