AI笔记: 计算机视觉之角点检测示例

Harris 角点检测示例

1 ) 相关函数

  • C++版

    • void cornerHarris(InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType=BORDER_DEFAULT );
    • src,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位或者浮点型图像。
    • dst,函数调用后的运算结果存在这里,即这个参数用于存放Harris角点检测的输出结果,和源图片有一样的尺寸和类型。
    • blockSize,表示邻域的大小,更多的详细信息在cornerEigenValsAndVecs中有讲到。
    • ksize,表示Sobel()算子的孔径大小。
    • kHarris参数。
    • borderType,图像像素的边界模式,注意它有默认值BORDER_DEFAULT。更详细的解释,参考borderInterpolate函数。
  • Python版

    • dst = cv.cornerHarris( src, blockSize, ksize, k[, dst[, borderType]] )

2 ) cornerHarris 原始结果

  • OpenCV3中提供的函数并不能直接应用到你自己的代码之中 要想在一幅图之中框选出角点,我们还需要做一些其他的工作
  • 首先,我们来看一下这个函数中产生的 OutputArray 是一个什么样的存在,我们以下面这张图片作为样例
  • 由此可见,此函数我们需要进一步进行调整,才能达到想要的效果

3 ) 程序示例 (C++)

  • 为了使我们可以很好的使用这个函数,我们首先要对得到的结果进行下一步处理
  • 此步处理中,我们消除掉了可能出现的角点聚集在一起的情况
cv::cornerHarris(image, cornerStrength,
    neighbourhood, // neighborhood size
    aperture, // 孔径大小
    k);  // Harris 参数
cv::imshow("ini", cornerStrength);
// 内部阈值计算
// 配合函数minMaxLoc设置的变量, 但后续并没有用处,只为配合函数使用
double minStrength;
cv::minMaxLoc(cornerStrength, &minStrength, &maxStrength);
// 局部最大值检测,使得减少出现角点聚集的情况出现
cv::Mat dilated;
cv::dilated(cornerStrength, dilated, cv::Mat());
cv::compare(cornerStrength, dilated, localMax, cv::CMP_EQ);
  • 这一步处理中,我们将图像进一步处理,再一次削减角点数量,以便得到最正确的角点
  • 并将角点强度所形成的图像进行返回,我们可以得到以下的效果
cv::Mat cornerMap;
// 对角点图像进行阈值化
threshold = qualityLevel * maxStrength;
cv::threshold(cornerStrength, cornerTh, threshold, 255, cv::THRESH_BINARY);
// 转换为8位图像
cv::Mat result;
cornerTh.convertTo(cornerMap, CV_8U);
// 非极大值抑制
cv::bitwise_and(cornerMap, localMax, cornerMap);

// cv::imshow("bitandbef", result);
cv::bitwise_and(result, cornerMap, result);
// cv:imshow("bitand", result);

/*
std::cout << cornerMap.type() << "cornerMap_type" << std::endl;
std:cout << cornerTh.type() << "cornerTh_type" << std::endl;
*/
return cornerMap;
  • 最后,我们将要把角点用o的方式画出,以便进行效果的测试
for(int y=0; y < cornerMap.rows; y++) {
    const uchar* rowPtr = cornerMap.ptr<uchar> (y);
    for(int x=0; x < cornerMap.cols; x++) {
        // 如果是特征点
        if(rowPtr[x]) {
            points.push_back(cv::Point(x,y));
        }
    }
}
std::vector<cv::Point>::const_iterator it = points.begin();
// 对于所有角点
while(it != points.end()) {
    cv::circle(image, *it, radius, color, thickness);
    ++it;
}

4 ) 程序示例 (Python)

  • 使用Harris算子检测角点,并首先消除掉了可能出现的角点聚集在一起的情况
def detect(self, image):
    self.cornerStrength = cv2.cornerHarris(image, self.neighbourhood, self.aperture, self.k)
    cv2.imshow('ini', self.cornerStrength)
    min_val, self.maxStrength, min_indx, max_indx = cv2.minMaxLoc(self.cornerStrength)
    dilated = cv2.dilate(self.cornerStrength, cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)))
  • 这一步处理中,我们将图像进一步处理,再一次削减角点数量,以便得到最正确的角点
def getCornerMap(self, qualityLevel):
    self.threshold = qualityLevel * self.maxStrength
    _, self.cornerTh = cv2.threshold(self.cornerStrength, self.threshold, 255, cv2.THRESH_BINARY)
    self.cornerTh = np.array(self.cornerTh)
    
    self.cornerMap = self.cornerTh.astype(np.uint8)
    result = self.cornerTh.astype(np.uint8)
    cv2.bitwise_and(self.cornerMap, self.localMax, self.cornerMap)

    cv2.bitwise_and(result, self.cornerMap, result)
    cv2.imshow('bitand', result)
  • 最后,我们将要把角点用圆圈的方式画出,以便进行效果的测试
def drawOnImage(self, image, points, color, radius, thickness):
    print(len(points))
    for i in points:
        print(i)
        cv2.circle(image, i, radius, color, thickness)

5 ) 运行效果

通用角点检测示例

1 )角点检测一般流程(C++)

OpenCV3支持SIFT/SURF/ORB/KAZE/FAST/BRISK/AKAZE等角点检测,均为Feature2D的子类, 一般使用流程如下: 检测算子创建、检测、 提取描述子、匹配

  • 创建

    • cv::Ptr<cv::算子> 给算子起的名字 = cv::算子::create(阈值);
    • e.g. cv::Ptr<cv::ORB> orb = cv::ORB::create(nkeypoint);
  • 检测

    • 上一步给算子起的名字-> detect(图片, 内容为KeyPoints的vector向量);
    • e.g. orb->detect(img_1, keypoints_1);
  • 提取描述子

    • 上一步给算子起的名字->compute(图片, 上一步中得到的向量, Mat类矩阵);
    • e.g. orb->compute(img_1, keypoints_1, descriptors_1);
  • 匹配

    • BFMatcher类对象.match(描述子1,描述子2,内容为DMatch的vector向量);
    • e.g. matcher.match(descriptors_1, descriptors_2, matcshes);

2 )角点检测一般流程(Python)

OpenCV3支持SIFT/SURF/ORB/KAZE/FAST/BRISK/AKAZE等角点检测,均为Feature2D的子类, 一般使用流程如下: 检测算子创建、检测、提取描述子、匹配

  • 创建

    • 给算子起的名字 = cv2.算子名_create()
    • e.g. orb = cv2.orb_create();
  • 检测

    • 内容为KeyPoints的vector向量 = 上一步给算子起的名字.detect(图片)
    • e.g. keypoints = orb.detect( img, None )
  • 描述子

    • 上一步给算子起的名字.compute(图片, 上一步中得到的KeyPoints向量)
    • e.g. keypoints, descriptors = orb.compute( img, keypoints )
  • 匹配

    • BFMatcher类对象.match(描述子1, 描述子2, 内容为DMatch的向量);
    • e.g. matches = matcher.match(descriptors_1, descriptors_2)

OpenCV3实现 FAST(C++)

核心函数

  • FAST角点检测算法在OpenCV3中以虚类的方式呈现,因此在使用上与SURF算法有一定的区别, 我们在调用时一般使用如下方法
vector<cv::KeyPoint>keypoints;
cv::Ptr<cv::FeatureDetector> fast = cv::FastFeatureDetector::create(40);
  • 之后,再使用OpenCV3中提供的角点检测函数,即可找到图片中的角点
fast -> detect(image, keypoints);
cv::drawKeypoints(image, keypoints, image, cv::Scalar(255,255,255,))
    cv::DrawMatchesFlags::DRAW_OVER_OUTING);

OpenCV3实现 SURF(C++)

核心函数

  • SURF算法是SIFT算法的高效变种,其计算速度远快于SIFT,因此我们在这里介绍SURF
CV_WRAP static Ptr<SURF> create(double hessianThreshold=100, int nOctaves = 4, int nOctaveLayers = 3,
bool extended = false, bool upright = false);
  • 在这个函数中,我们唯一需要了解的即为 hessianThreshold 这个参数
  • 这个参数代表着 Hessisan 矩阵行列式所计算出的曲率强度
  • 此数值越高,代表着区分匹配点的要求越高
  • 当然,在OpenCV3中其给出了默认值100,不过一般推荐在1000 ~ 2500之间,如下面这样
Ptr<xfeatures2d::SURF> detector = xfeatures2d::SURF::create(minHessian);
Ptr<DescriptorExtractor> descriptor = xfeatures2d::SURF::create();
Ptr<DescriptorMatcher> Matcher1 = DescriptorMatcher::create("BruteForce");

实际应用

  • 在SURF算法中,为了执行匹配,我们首先检测待匹配的两幅图中的特征点
// 检测特征点
detector -> detect(img1, keyPoint1);
detector ->detect(img2, keyPoint2);
  • 之后,我们提取描述这些特征点的描述子
// 提取特征点描述子
descriptor -> compute(img1, keyPoint1, descriptors1);
descriptor -> compute(img1, keyPoint2, descriptors2);
  • 最后,我们将两幅图像中的描述子进行匹配
// 匹配图像中的描述子
matcher1 -> match(descriptors1, descriptors2, matcches);
  • 在将我们的结果展示在电脑屏幕前,我们还需要进行最后一步
  • 即为将对应的匹配点之间通过连线的方式画在图像上
  • 为了使我们的结果看起来更加清晰,我们将匹配到的点的数量进行削减
std::nth_element(matches.begin(), matches.begin()+24, matches.end());
matches.erase(matches.begin()+25, matches.end());
  • 之后,我们将相互之间能构成匹配的点画在图像上
// 画匹配点
Mat img_matches;
drawMatches(img1, keyPoint1, img2, keyPoint2, matches, img_matches);
imshow("img_matches", img_matches);

OpenCV3实现 FAST(Python)

核心函数

  • FAST角点检测算法在OpenCV3中以虚类的方式呈现,因此在创建上与SURF算法有一定的区别, 其它相同,具体如下:
fast = cv2.FastFeatureDector_create(threshold=40,nonmaxSuppression=True, type=cv2.FAST_FEATURE_DETECTOR_TYPE_9_16)
kp = fast.detect(image, None)
cv2.drawKeypoints(image, kp, image, color=(255, 255, 255))

OpenCV3实现 SURF(Python)

  • 根据前述步骤,首先创建:
minHessian = 1000

detector = cv.xfeatures2d.SURF_create(minHessian)
descriptor = cv.xfeatures2d.SURF_create()
matcher1 = cv.DescriptorMatcher_create("BruteForce")
  • 然后按照检测->计算->绘制的过程进行:
# 检测特征点
keyPoint1 = detector.detect(img1)
keyPoint2 = detector.detect(img2)

# 计算特征点对应描述子
_, descriptors1 = descriptor.compute(img1, keyPoint1)
_, descriptors2 = descriptor.compute(img2, keyPoint2)

# 描述子匹配
matches = matcher1.match(descriptors1, descriptors2)
  • 最后完成匹配并画出
img_matches = np.empty(img2.shape)
img_matches1 = cv.drawMatches(img1, keyPoint1, img2, keyPoint2, matches, img_matches)
cv.imshow("img_matches", img_matches1)
cv.waitKey();
print("keyPoint1.size = ", len(keyPoint1))
print("keyPoint2.size = ", len(keyPoint2))

OpenCV3实现 FAST 效果图

OpenCV3实现 SURF 效果图

OpenCV3实现 ORB(C++)

核心函数

  • 与SURF的功能相同,ORB算法也是对两幅图片进行特征点匹配
CV_WRAP static Ptr<ORB> create(int nfeatures=500, float scaleFactor=1.2f, int nlevels=8, int edgeThreshold=31,
int firstLevel=0, int WTA_K=2, int scoreType=ORB::HARRIS_SCORE, int patchSize=31, int fastThreshold=20);
  • 就像上述函数所声明的,在绝大多数情况下,我们需要改变的只是第一个参数 nfeatures 其代表了算法将会在图片中找到匹配点的对数

  • 在OpenCV3中,我们可以如下使用这个函数

int nkeypoint = 50;
cv::Ptr<cv::ORB> orb = cv::ORB::create(nkeypoint);

OpenCV3实现 ORB(Python)

  • 与前述检测与匹配过程类似
orb = cv2.ORB_create()
kp1 = orb.detect(image1, None)
kp2 = orb.detect(image2, None)

kp1, des1 = orb.compute(image1, kp1)
kp2, des2 = orb.compute(image2, kp2)

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

OpenCV3实现 ORB 效果图

发布了431 篇原创文章 · 获赞 251 · 访问量 71万+

猜你喜欢

转载自blog.csdn.net/Tyro_java/article/details/104702984