PS:
1,本文博文的matlab代码分析自:SIFT算法的“始作俑者”-----lowe,
2,网址为:http://www.cs.ubc.ca/~lowe/keypoints/
3,下面的代码均来自于他的SIFT算法(改写了一部分代码),此算法有其专利,专利拥有者为英属哥伦比亚大学。

4,本文只是感性的认知和使用SIFT算法,对深入的数学原理未做详尽探讨。

1,SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。

a,不变性:
——对图像的旋转和尺度变化具有不变性;
——对三维视角变化和光照变化具有很强的适应性;
——局部特征,在遮挡和场景杂乱时仍保持不变性;

b,辨别力强:
——特征之间相互区分的能力强,有利于匹配;

c,数量较多:
——Lowe原话:一般500*500的图像能提取约2000个特征点(这个数字依赖于图像内容和几个参数的选择)。

在高斯差分(Difference of Gaussian,DOG)尺度空间中提取极值点并进行优化,从而获取特征点。

2,SIFT算法点检测的具体步骤:
——构建尺度空间;
——构造高斯差分尺度空间;
——DoG尺度空间极值点检测;
——特征点精确定位;
——去除不稳定点;

3,OpenCV下SIFT特征点提取与匹配的大致流程如下:

读取图片-》特征点检测(位置,角度,层)-》特征点描述的提取(16*8维的特征向量)-》匹配-》显示
其中,特征点提取主要有两个步骤,下面做具体分析。

1、使用opencv内置的库读取两幅图片
2、生成一个SiftFeatureDetector的对象,这个对象顾名思义就是SIFT特征的探测器,用它来探测一副图片中SIFT点的特征,存到一个KeyPoint类型的vector中。这里有必要说keypoint的数据结构,涉及内容较多,具体分析查看opencv中keypoint数据结构分析,里面讲的自认为讲的还算详细(表打我……)。简而言之最重要的一点在于:
keypoint只是保存了opencv的sift库检测到的特征点的一些基本信息,但sift所提取出来的特征向量其实不是在这个里面,特征向量通过SiftDescriptorExtractor 提取,结果放在一个Mat的数据结构中。这个数据结构才真正保存了该特征点所对应的特征向量。具体见后文对SiftDescriptorExtractor 所生成的对象的详解。
就因为这点没有理解明白耽误了一上午的时间。哭死!
3、对图像所有KEYPOINT提取其特征向量:
得到keypoint只是达到了关键点的位置,方向等信息,并无该特征点的特征向量,要想提取得到特征向量就还要进行SiftDescriptorExtractor 的工作,建立了SiftDescriptorExtractor 对象后,通过该对象,对之前SIFT产生的特征点进行遍历,找到该特征点所对应的128维特征向量。具体方法参见opencv中SiftDescriptorExtractor所做的SIFT特征向量提取工作简单分析。通过这一步后,所有keypoint关键点的特征向量被保存到了一个MAT的数据结构中,作为特征。
4、对两幅图的特征向量进行匹配,得到匹配值。
两幅图片的特征向量被提取出来后,我们就可以使用BruteForceMatcher对象对两幅图片的descriptor进行匹配,得到匹配的结果到matches中,这其中具体的匹配方法暂没细看,过段时间补上。
至此,SIFT从特征点的探测到最后的匹配都已经完成,虽然匹配部分不甚了解,只扫对于如何使用OPENCV进行sift特征的提取有了一定的理解。接下来可以开始进行下一步的工作了。

一,源代码中三个主要函数

1,共有三段Matlab代码源文件
1)match.m:测试程序
功能:该函数读入两幅(灰度)图像,找出各自的 SIFT 特征, 并显示两连接两幅图像中被匹配的特征点(关键特征点(the matched keypoints)直线(将对应特征点进行连接)。判断匹配的准则是匹配距离小于distRatio倍于下一个最近匹配的距离( A match is accepted only if its distance is less than distRatio times the distance to the second closest match.
该程序返回显示的匹配对的数量。( It returns the number of matches displayed.)

调用实例: match('desk.jpg','book.jpg');
( 假如,想测试一个含有一本书的桌面的图像 和一本书的图像之间特征匹配)
调用方法和参数描述:略。
注意:

(a)图像为灰度图像,如果是彩色图像,应该在调用前利用rgb2gray转换为灰度图像。
(b)参数distRatio 为控制匹配点数量的系数,这里取 0.6,该参数决定了匹配点的数量,在Match.m文件中调整该参数,获得最合适的匹配点数量。

2)sift.m :尺度不变特征变换(SIFT算法)的核心算法程序
具体原理详见David G. Lowe发表于2004年Int Journal of Computer Vision,2(60):91-110的那篇标题为“Distivtive Image Features from Scale -Invariant Keypoints" 的论文

功能:该函数读入灰度图像,返回SIFT 特征关键点( SIFT keypoints.)
调用方法和参数描述:
调用方式:[image, descriptors, locs] = sift(imageFile)
输入参数( Input parameters): imageFile: 图像文件名.
输出或返回参数( Returned): image: 是具有double format格式的图像矩阵

descriptors: 一个 K-by-128 的矩阵x, 其中每行是针对找到的K个关键特征点(the K keypoints)的不变量描述子. 这个描述子(descriptor)是一个拥有128个数值并归一化为单位长度向量.

locs: 是K-by-4 矩阵, 其中的每一行具有四个数值,表示关键点位置信息 (在图像中的行坐标,列坐标(row, column) ,注意,一般图像的左上角为坐标原点), 尺度scale,高斯尺度空间的参数,其中该参数也决定了frame(结构)确定的图像disk的大小, 最后一个参数是方向orientation). 方向参数的范围是[-PI, PI] 单位为弧度.

3)appendimages.m: 该函数创建一个新的图像分别包含两个匹配的图像和他们之间的匹配对的连接直线.

二,小应用

SIFT算法解决图像平移的小应用:

[cpp] view plain copy
  1. close all;
  2. clear all;
  3. clc;
  4. %读取自用图片,(如果是彩色图像将会被sift函数自动转换成灰度图处理)
  5. i1=imread('image2_1.jpg');
  6. i2=imread('a2.jpg');
  7. imwrite(i1,'v1.jpg','quality',80);
  8. imwrite(i2,'v2.jpg','quality',80);
  9. %找到每一幅图的“SIFT关键点”
  10. [im1, des1, loc1] = sift('v1.jpg');
  11. [im2, des2, loc2] = sift('v2.jpg');
  12. %显示关键点及其方向矢量信息
  13. showkeys(im1, loc1);
  14. showkeys(im2, loc2);
  15. %  For efficiency in Matlab, it is cheaper to compute dot products between
  16. %  unit vectors rather than Euclidean distances.  Note that the ratio of
  17. %  angles (acos of dot products of unit vectors) is a close approximation
  18. %  to the ratio of Euclidean distances for small angles.
  19. %
  20. %  distRatio: Only keep matches in which the ratio of vector angles from the
  21. %  nearest to second nearest neighbor is less than distRatio.
  22. distRatio = 0.6;%控制匹配点数量的系数,这里取 0.6,该参数决定了匹配点的数量。
  23. % For each descriptor in the first image, select its match to second image.
  24. des2t = des2';                          % Precompute matrix transpose
  25. len=size(des1,1);
  26. for i = 1 : len
  27. dotprods = des1(i,:) * des2t;        % Computes vector of dot products
  28. [vals,indx] = sort(acos(dotprods));  % Take inverse cosine and sort results
  29. %   Check if nearest neighbor has angle less than distRatio times 2nd.
  30. %   检查是否最近邻域有角度小于二倍distratio。
  31. if (vals(1) < distRatio * vals(2))
  32. match(i) = indx(1);
  33. else
  34. match(i) = 0;
  35. end
  36. end
  37. %将两幅图像显示在一起
  38. im3 = appendimages(im1,im2);
  39. %将匹配点连在一起
  40. figure('Position', [100 100 size(im3,2) size(im3,1)]);
  41. colormap('gray');
  42. imagesc(im3);
  43. hold on;
  44. cols1 = size(im1,2);
  45. %loc (row, column, scale, orientation)
  46. tran_col = 0;
  47. tran_row = 0;
  48. for i = 1: size(des1,1)
  49. if (match(i) > 0)
  50. col1=loc1(i,2);
  51. row1=loc1(i,1);
  52. col2=loc2(match(i),2);
  53. row2=loc2(match(i),1);
  54. tran_col=tran_col+col2-col1;
  55. tran_row=tran_row+row2-row1;
  56. line([loc1(i,2), loc2(match(i),2)+cols1],[loc1(i,1), loc2(match(i),1)], 'Color', 'c');%将两个匹配点连接
  57. end
  58. end
  59. hold off;
  60. %打印匹配点个数
  61. num = sum(match > 0);
  62. tran_col = int32(tran_col/num);
  63. tran_row = int32(tran_row/num);
  64. fprintf('Found %d matches.\n', num);
  65. fprintf('列偏移量%d.\n', tran_col);
  66. fprintf('行偏移量%d.\n', tran_row);
  67. vv2=imread('v2.jpg');
  68. %平移回去
  69. figure,imshow(i1);
  70. se=translate(strel(1),[double(-tran_row),double(-tran_col)] );
  71. img2=imdilate(vv2,se);
  72. figure,imshow(img2);

OpenCV写得图像配准(SIFT算法)

[cpp] view plain copy
  1. #include<iostream>
  2. #include <opencv2/highgui/highgui.hpp>
  3. #include "opencv2/core/core.hpp"
  4. #include "highgui.h"
  5. #include "opencv2/imgproc/imgproc.hpp"
  6. #include "opencv2/features2d/features2d.hpp"
  7. #include "opencv2/nonfree/nonfree.hpp"
  8. #include "opencv2/legacy/legacy.hpp"
  9. using namespace cv;
  10. using namespace std;
  11. int main(int argc, char** argv)
  12. {
  13. //待匹配的两幅图像,其中img1包括img2,也就是要从img1中识别出img2
  14. Mat img1 = imread("a1.jpg");
  15. Mat img2 = imread("a2.jpg");
  16. SIFT sift1, sift2;
  17. vector<KeyPoint> key_points1, key_points2;
  18. Mat descriptors1, descriptors2, mascara;
  19. sift1(img1, mascara, key_points1, descriptors1);
  20. sift2(img2, mascara, key_points2, descriptors2);
  21. //实例化暴力匹配器——BruteForceMatcher
  22. BruteForceMatcher<L2<float>> matcher;
  23. //定义匹配器算子
  24. vector<DMatch>matches;
  25. //实现描述符之间的匹配,得到算子matches
  26. matcher.match(descriptors1, descriptors2, matches);
  27. //提取出前30个最佳匹配结果
  28. std::nth_element(matches.begin(),     //匹配器算子的初始位置
  29. matches.begin() + 29,     // 排序的数量
  30. matches.end());       // 结束位置
  31. //剔除掉其余的匹配结果
  32. matches.erase(matches.begin() + 30, matches.end());
  33. namedWindow("SIFT_matches");
  34. Mat img_matches;
  35. //在输出图像中绘制匹配结果
  36. drawMatches(img1, key_points1,         //第一幅图像和它的特征点
  37. img2, key_points2,      //第二幅图像和它的特征点
  38. matches,       //匹配器算子
  39. img_matches,      //匹配输出图像
  40. Scalar(255, 0, 255));     //用红色色直线连接两幅图像中的特征点
  41. imshow("SIFT_matches", img_matches);
  42. waitKey(0);
  43. return 0;
  44. }

配准效果(图像存在刚性平移):

OpenCV中的SURF算法解决平移问题:

[cpp] view plain copy
  1. #include <opencv2/legacy/legacy.hpp>
  2. #include <opencv2/nonfree/nonfree.hpp>//opencv_nonfree模块:包含一些拥有专利的算法,如SIFT、SURF函数源码。
  3. #include <stdio.h>
  4. #include <iostream>
  5. #include "opencv2/core/core.hpp"
  6. #include "opencv2/features2d/features2d.hpp"
  7. #include "opencv2/highgui/highgui.hpp"
  8. #include <opencv2/nonfree/features2d.hpp>
  9. #include "vector"
  10. using namespace cv;
  11. using namespace std;
  12. void translateTransform(cv::Mat const& src, cv::Mat& dst, int dx, int dy)
  13. {
  14. //CV_Assert(src.depth() == CV_8U);
  15. const int rows = src.rows;
  16. const int cols = src.cols;
  17. dst.create(rows, cols, src.type());
  18. for (int i = 0; i < rows; i++)
  19. {
  20. for (int j = 0; j < cols; j++)
  21. {
  22. //平移后坐标映射到原图像
  23. int x = j - dx;
  24. int y = i - dy;
  25. //保证映射后的坐标在原图像范围内
  26. if (x >= 0 && y >= 0 && x < cols && y < rows)
  27. dst.at<uchar>(i, j) = src.at<uchar>(y, x);
  28. else
  29. dst.at<uchar>(i, j) = src.at<uchar>(i, j);
  30. }
  31. }
  32. }
  33. int main(int argc, char** argv)
  34. {
  35. Mat img_11 = imread("a1.jpg");
  36. Mat img_22 = imread("a2.jpg");
  37. if (!img_11.data || !img_22.data)
  38. {
  39. std::cout << " --(!) Error reading images " << std::endl;
  40. return -1;
  41. }
  42. Mat img_1, img_2;
  43. cvtColor(img_11, img_1, CV_BGR2GRAY);
  44. cvtColor(img_22, img_2, CV_BGR2GRAY);
  45. //-- Step 1: Detect the keypoints using SURF Detector
  46. int minHessian = 40;
  47. //SiftFeatureDetector detector(minHessian);
  48. SurfFeatureDetector detector( minHessian );
  49. std::vector<KeyPoint> keypoints_1, keypoints_2;
  50. detector.detect(img_1, keypoints_1);
  51. detector.detect(img_2, keypoints_2);
  52. //-- Step 2: Calculate descriptors (feature vectors)
  53. //SiftDescriptorExtractor extractor;
  54. SurfDescriptorExtractor extractor;
  55. Mat descriptors_1, descriptors_2;
  56. extractor.compute(img_1, keypoints_1, descriptors_1);
  57. extractor.compute(img_2, keypoints_2, descriptors_2);
  58. //-- Step 3: Matching descriptor vectors using FLANN matcher
  59. FlannBasedMatcher matcher;
  60. std::vector< DMatch > matches;
  61. matcher.match(descriptors_1, descriptors_2, matches);
  62. double max_dist = 0; double min_dist = 100;
  63. //-- Quick calculation of max and min distances between keypoints
  64. for (int i = 0; i < descriptors_1.rows; i++)
  65. {
  66. double dist = matches[i].distance;
  67. if (dist < min_dist) min_dist = dist;
  68. if (dist > max_dist) max_dist = dist;
  69. }
  70. printf("-- Max dist : %f \n", max_dist);
  71. printf("-- Min dist : %f \n", min_dist);
  72. //-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist )
  73. //-- PS.- radiusMatch can also be used here.
  74. std::vector< DMatch > good_matches;
  75. for (int i = 0; i < descriptors_1.rows; i++)
  76. {
  77. if (matches[i].distance < 2 * min_dist)
  78. {
  79. good_matches.push_back(matches[i]);
  80. }
  81. }
  82. //-- Draw only "good" matches
  83. Mat img_matches;
  84. drawMatches(img_1, keypoints_1, img_2, keypoints_2,
  85. good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
  86. vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
  87. //-- Show detected matches
  88. imshow("Good Matches", img_matches);
  89. //imwrite("a_match_surf.jpg",img_matches);
  90. //imwrite("a_match_sift.jpg",img_matches);
  91. int cnt_nums = 0;
  92. float tran_row = 0;
  93. float tran_col = 0;
  94. for ( unsigned int i = 0; i < good_matches.size(); i++)
  95. {
  96. //good_matches[i].queryIdx保存着第一张图片匹配点的序号,keypoints_1[good_matches[i].queryIdx].pt.x 为该序号对应的点的x坐标。y坐标同理
  97. //good_matches[i].trainIdx保存着第二张图片匹配点的序号,keypoints_2[good_matches[i].trainIdx].pt.x 为为该序号对应的点的x坐标。y坐标同理
  98. float x1_zuo = keypoints_1[good_matches[i].queryIdx].pt.x;
  99. float y1_zuo = keypoints_1[good_matches[i].queryIdx].pt.y;
  100. float x2_zuo = keypoints_2[good_matches[i].trainIdx].pt.x;
  101. float y2_zuo = keypoints_2[good_matches[i].trainIdx].pt.y;
  102. printf("-- Good Match良性匹配点第[%d]个, 来自图1的关键点(坐标为 %f,%f):点的编号为 %d  \n --来自图2的关键点(坐标为 %f,%f): 点的编号为 %d  \n", i,
  103. keypoints_1[good_matches[i].queryIdx].pt.x, keypoints_1[good_matches[i].queryIdx].pt.y, good_matches[i].queryIdx,
  104. keypoints_2[good_matches[i].trainIdx].pt.x, keypoints_2[good_matches[i].trainIdx].pt.y, good_matches[i].trainIdx);
  105. tran_row += keypoints_2[good_matches[i].trainIdx].pt.x - keypoints_1[good_matches[i].queryIdx].pt.x;
  106. tran_col += keypoints_2[good_matches[i].trainIdx].pt.y - keypoints_1[good_matches[i].queryIdx].pt.y;
  107. cnt_nums++;
  108. }
  109. int tr_row = ceil(tran_row / cnt_nums);
  110. int tr_col = ceil(tran_col / cnt_nums);
  111. cout << "偏移量为:" << tr_row << "  " << tr_col;
  112. Mat dst;
  113. //灰度图的平移
  114. translateTransform(img_2,dst,-tr_row,-tr_col);
  115. imshow("校准结果", dst);
  116. waitKey(0);
  117. return 0;
  118. }

注意:最后的匹配结果保存在vector<DMatch>中。DMatch用来保存匹配后的结果

[cpp] view plain copy
  1. struct DMatch
  2. {         //三个构造函数
  3. DMatch() :
  4. queryIdx(-1), trainIdx(-1), imgIdx(-1), distance(std::numeric_limits<float>::max()) {}
  5. DMatch(int  _queryIdx, int  _trainIdx, float  _distance) :
  6. queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(-1), distance(_distance) {}
  7. DMatch(int  _queryIdx, int  _trainIdx, int  _imgIdx, float  _distance) : queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(_imgIdx), distance(_distance) {}
  8. int queryIdx;  //此匹配对应的查询图像的特征描述子索引
  9. int trainIdx;   //此匹配对应的训练(模板)图像的特征描述子索引
  10. int imgIdx;    //训练图像的索引(若有多个)
  11. float distance;  //两个特征向量之间的欧氏距离,越小表明匹配度越高。
  12. bool operator < (const DMatch &m) const;
  13. };

该校准结果是对上面这幅图中右边这幅偏移图像的校准结果,但是明显的问题是,边界问题没有处理好。

博文收录于转载:

一,图像配准算法小总结
首先,图像配准要素结合:特征空间,搜索空间,搜索策略,近似性度量;图像配准方法: 
1.基于灰度信息的方法:交叉相关(互相关)方法,相关系数度量,序贯相似检测算法,信息理论的交换信息相似性准则。 
2.基于变换域的方法:相位相关法,Walsh Transform变换。 
3.基于特征的方法:常用的图像特征有:特征点(包括角点、高曲率点等)、直线段、边缘(Robert、高斯-拉普拉斯LoG、Canny、Gabor滤波等边缘检测算子)或轮廓、闭合区域、特征结构以及统计特征如矩不变量等。
注:像素灰度信息的互相关算法相比,特征提取包含了高层信号信息,所以该类算法对光照、噪声等的抗干扰能力强。

常用的空间变换模型:刚体变换(平移、旋转与缩放的组合)、仿射变换、透射变换、投影变换、非线性变换。

常用的相似性测度: 
1.距离测度:均方根误差,差绝对值和误差,兰氏距离,Mahalanobis距离,绝对差,Hausdorff距离等。 
2.角度度量法(概率测度)。 
3.相关度量法

配准算法的评价标准: 
配准时间、配准率、算法复杂度、算法的可移植性、算法的适用性、图像数据对算法的影响等(这里虽然不是目标追踪的评价标准,但是我们可以借鉴这些评价算法的标准)

二,图像配准算法分类

图像拼接技术主要包括两个关键环节即图像配准和图像融合对于图像融合部分,由于其耗时不太大,且现有的几种主要方法效果差别也不多,所以总体来说算法上比较成熟。而图像配准部分是整个图像拼接技术的核心部分,它直接关系到图像拼接算法的成功率和运行速度,因此配准算法的研究是多年来研究的重点。
目前的图像配准算法基本上可以分为两类:基于频域的方法(相位相关方法)和基于时域的方法。

相位相关法最早是由Kuglin和Hines在1975年提出的,并且证明在纯二维平移的情形下,拼接精度可以达到1个像素,多用于航空照片和卫星遥感图像的配准等领域。该方法对拼接的图像进行快速傅立叶变换,将两幅待配准图像变换到频域,然后通过它们的互功率谱直接计算出两幅图像间的平移矢量,从而实现图像的配准。由于其具有简单而精确的特点,后来成为最有前途的图像配准算法之一。但是相位相关方法一般需要比较大的重叠比例(通常要求配准图像之间有50%的重叠比例),如果重叠比例较小,则容易造成平移矢量的错误估计,从而较难实现图像的配准。

基于时域的方法又可具体分为基于特征的方法和基于区域的方法。基于特征的方法首先找出两幅图像中的特征点(如边界点、拐点),并确定图像间特征点的对应关系,然后利用这种对应关系找到两幅图像间的变换关系。这一类方法不直接利用图像的灰度信息,因而对光线变化不敏感,但对特征点对应关系的精确程度依赖很大。这一类方法采用的思想较为直观,目前大部分的图像配准算法都可以归为这一类。基于区域的方法是以一幅图像重叠区域中的一块作为模板,在另一幅图像中搜索与此模板最相似的匹配块,这种算法精度较高,但计算量过大。

按照匹配算法的具体实现又可以分为直接法和搜索法两大类,直接法主要包括变换优化法,它首先建立两幅待拼接图像间的变换模型,然后采用非线性迭代最小化算法直接计算出模型的变换参数,从而确定图像的配准位置。该算法效果较好,收敛速度较快,但是它要达到过程的收敛要求有较好的初始估计,如果初始估计不好,则会造成图像拼接的失败。搜索法主要是以一幅图像中的某些特征为依据,在另一幅图像中搜索最佳配准位置,常用的有比值匹配法,块匹配法和网格匹配法。比值匹配法是从一幅图像的重叠区域中部分相邻的两列上取出部分像素,然后以它们的比值作模板,在另一幅图像中搜索最佳匹配。这种算法计算量较小,但精度较低;块匹配法则是以一幅图像重叠区域中的一块作为模板,在另一幅图像中搜索与此模板最相似的匹配块,这种算法精度较高,但计算量过大;网格匹配法减小了块匹配法的计算量,它首先要进行粗匹配,每次水平或垂直移动一个步长,记录最佳匹配位置,然后在此位置附近进行精确匹配,每次步长减半,然后循环此过程直至步长减为0。这种算法较前两种运算量都有所减小,但在实际应用中仍然偏大,而且粗匹配时如果步长取的太大,很可能会造成较大的粗匹配误差,从而很难实现精确匹配。

参考资源:

【1】http://blog.csdn.net/zddblog/article/details/7521424

【2】http://www.cs.ubc.ca/~lowe/keypoints/

【3】http://blog.csdn.net/zhaocj/article/details/42124473

【4】http://www.cnblogs.com/cj695/p/4041478.html

【5】http://blog.csdn.net/llw01/article/details/9258699

【6】http://blog.csdn.net/xuluohongshang/article/details/52886352

注:本博文为EbowTang原创,后续可能继续更新本文。如果转载,请务必复制本条信息!

原文地址:http://blog.csdn.net/ebowtang/article/details/51236061

原作者博客:http://blog.csdn.net/ebowtang

版权声明:本文为EbowTang原创文章,后续可能继续更新本文。如果转载,请务必复制本文末尾的信息!

PS:
1,本文博文的matlab代码分析自:SIFT算法的“始作俑者”-----lowe,
2,网址为:http://www.cs.ubc.ca/~lowe/keypoints/
3,下面的代码均来自于他的SIFT算法(改写了一部分代码),此算法有其专利,专利拥有者为英属哥伦比亚大学。

4,本文只是感性的认知和使用SIFT算法,对深入的数学原理未做详尽探讨。

1,SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。

a,不变性:
——对图像的旋转和尺度变化具有不变性;
——对三维视角变化和光照变化具有很强的适应性;
——局部特征,在遮挡和场景杂乱时仍保持不变性;

b,辨别力强:
——特征之间相互区分的能力强,有利于匹配;

c,数量较多:
——Lowe原话:一般500*500的图像能提取约2000个特征点(这个数字依赖于图像内容和几个参数的选择)。

在高斯差分(Difference of Gaussian,DOG)尺度空间中提取极值点并进行优化,从而获取特征点。

2,SIFT算法点检测的具体步骤:
——构建尺度空间;
——构造高斯差分尺度空间;
——DoG尺度空间极值点检测;
——特征点精确定位;
——去除不稳定点;

3,OpenCV下SIFT特征点提取与匹配的大致流程如下:

读取图片-》特征点检测(位置,角度,层)-》特征点描述的提取(16*8维的特征向量)-》匹配-》显示
其中,特征点提取主要有两个步骤,下面做具体分析。

1、使用opencv内置的库读取两幅图片
2、生成一个SiftFeatureDetector的对象,这个对象顾名思义就是SIFT特征的探测器,用它来探测一副图片中SIFT点的特征,存到一个KeyPoint类型的vector中。这里有必要说keypoint的数据结构,涉及内容较多,具体分析查看opencv中keypoint数据结构分析,里面讲的自认为讲的还算详细(表打我……)。简而言之最重要的一点在于:
keypoint只是保存了opencv的sift库检测到的特征点的一些基本信息,但sift所提取出来的特征向量其实不是在这个里面,特征向量通过SiftDescriptorExtractor 提取,结果放在一个Mat的数据结构中。这个数据结构才真正保存了该特征点所对应的特征向量。具体见后文对SiftDescriptorExtractor 所生成的对象的详解。
就因为这点没有理解明白耽误了一上午的时间。哭死!
3、对图像所有KEYPOINT提取其特征向量:
得到keypoint只是达到了关键点的位置,方向等信息,并无该特征点的特征向量,要想提取得到特征向量就还要进行SiftDescriptorExtractor 的工作,建立了SiftDescriptorExtractor 对象后,通过该对象,对之前SIFT产生的特征点进行遍历,找到该特征点所对应的128维特征向量。具体方法参见opencv中SiftDescriptorExtractor所做的SIFT特征向量提取工作简单分析。通过这一步后,所有keypoint关键点的特征向量被保存到了一个MAT的数据结构中,作为特征。
4、对两幅图的特征向量进行匹配,得到匹配值。
两幅图片的特征向量被提取出来后,我们就可以使用BruteForceMatcher对象对两幅图片的descriptor进行匹配,得到匹配的结果到matches中,这其中具体的匹配方法暂没细看,过段时间补上。
至此,SIFT从特征点的探测到最后的匹配都已经完成,虽然匹配部分不甚了解,只扫对于如何使用OPENCV进行sift特征的提取有了一定的理解。接下来可以开始进行下一步的工作了。

一,源代码中三个主要函数

1,共有三段Matlab代码源文件
1)match.m:测试程序
功能:该函数读入两幅(灰度)图像,找出各自的 SIFT 特征, 并显示两连接两幅图像中被匹配的特征点(关键特征点(the matched keypoints)直线(将对应特征点进行连接)。判断匹配的准则是匹配距离小于distRatio倍于下一个最近匹配的距离( A match is accepted only if its distance is less than distRatio times the distance to the second closest match.
该程序返回显示的匹配对的数量。( It returns the number of matches displayed.)

调用实例: match('desk.jpg','book.jpg');
( 假如,想测试一个含有一本书的桌面的图像 和一本书的图像之间特征匹配)
调用方法和参数描述:略。
注意:

(a)图像为灰度图像,如果是彩色图像,应该在调用前利用rgb2gray转换为灰度图像。
(b)参数distRatio 为控制匹配点数量的系数,这里取 0.6,该参数决定了匹配点的数量,在Match.m文件中调整该参数,获得最合适的匹配点数量。

2)sift.m :尺度不变特征变换(SIFT算法)的核心算法程序
具体原理详见David G. Lowe发表于2004年Int Journal of Computer Vision,2(60):91-110的那篇标题为“Distivtive Image Features from Scale -Invariant Keypoints" 的论文

功能:该函数读入灰度图像,返回SIFT 特征关键点( SIFT keypoints.)
调用方法和参数描述:
调用方式:[image, descriptors, locs] = sift(imageFile)
输入参数( Input parameters): imageFile: 图像文件名.
输出或返回参数( Returned): image: 是具有double format格式的图像矩阵

descriptors: 一个 K-by-128 的矩阵x, 其中每行是针对找到的K个关键特征点(the K keypoints)的不变量描述子. 这个描述子(descriptor)是一个拥有128个数值并归一化为单位长度向量.

locs: 是K-by-4 矩阵, 其中的每一行具有四个数值,表示关键点位置信息 (在图像中的行坐标,列坐标(row, column) ,注意,一般图像的左上角为坐标原点), 尺度scale,高斯尺度空间的参数,其中该参数也决定了frame(结构)确定的图像disk的大小, 最后一个参数是方向orientation). 方向参数的范围是[-PI, PI] 单位为弧度.

3)appendimages.m: 该函数创建一个新的图像分别包含两个匹配的图像和他们之间的匹配对的连接直线.

二,小应用

SIFT算法解决图像平移的小应用:

[cpp] view plain copy
  1. close all;
  2. clear all;
  3. clc;
  4. %读取自用图片,(如果是彩色图像将会被sift函数自动转换成灰度图处理)
  5. i1=imread('image2_1.jpg');
  6. i2=imread('a2.jpg');
  7. imwrite(i1,'v1.jpg','quality',80);
  8. imwrite(i2,'v2.jpg','quality',80);
  9. %找到每一幅图的“SIFT关键点”
  10. [im1, des1, loc1] = sift('v1.jpg');
  11. [im2, des2, loc2] = sift('v2.jpg');
  12. %显示关键点及其方向矢量信息
  13. showkeys(im1, loc1);
  14. showkeys(im2, loc2);
  15. %  For efficiency in Matlab, it is cheaper to compute dot products between
  16. %  unit vectors rather than Euclidean distances.  Note that the ratio of
  17. %  angles (acos of dot products of unit vectors) is a close approximation
  18. %  to the ratio of Euclidean distances for small angles.
  19. %
  20. %  distRatio: Only keep matches in which the ratio of vector angles from the
  21. %  nearest to second nearest neighbor is less than distRatio.
  22. distRatio = 0.6;%控制匹配点数量的系数,这里取 0.6,该参数决定了匹配点的数量。
  23. % For each descriptor in the first image, select its match to second image.
  24. des2t = des2';                          % Precompute matrix transpose
  25. len=size(des1,1);
  26. for i = 1 : len
  27. dotprods = des1(i,:) * des2t;        % Computes vector of dot products
  28. [vals,indx] = sort(acos(dotprods));  % Take inverse cosine and sort results
  29. %   Check if nearest neighbor has angle less than distRatio times 2nd.
  30. %   检查是否最近邻域有角度小于二倍distratio。
  31. if (vals(1) < distRatio * vals(2))
  32. match(i) = indx(1);
  33. else
  34. match(i) = 0;
  35. end
  36. end
  37. %将两幅图像显示在一起
  38. im3 = appendimages(im1,im2);
  39. %将匹配点连在一起
  40. figure('Position', [100 100 size(im3,2) size(im3,1)]);
  41. colormap('gray');
  42. imagesc(im3);
  43. hold on;
  44. cols1 = size(im1,2);
  45. %loc (row, column, scale, orientation)
  46. tran_col = 0;
  47. tran_row = 0;
  48. for i = 1: size(des1,1)
  49. if (match(i) > 0)
  50. col1=loc1(i,2);
  51. row1=loc1(i,1);
  52. col2=loc2(match(i),2);
  53. row2=loc2(match(i),1);
  54. tran_col=tran_col+col2-col1;
  55. tran_row=tran_row+row2-row1;
  56. line([loc1(i,2), loc2(match(i),2)+cols1],[loc1(i,1), loc2(match(i),1)], 'Color', 'c');%将两个匹配点连接
  57. end
  58. end
  59. hold off;
  60. %打印匹配点个数
  61. num = sum(match > 0);
  62. tran_col = int32(tran_col/num);
  63. tran_row = int32(tran_row/num);
  64. fprintf('Found %d matches.\n', num);
  65. fprintf('列偏移量%d.\n', tran_col);
  66. fprintf('行偏移量%d.\n', tran_row);
  67. vv2=imread('v2.jpg');
  68. %平移回去
  69. figure,imshow(i1);
  70. se=translate(strel(1),[double(-tran_row),double(-tran_col)] );
  71. img2=imdilate(vv2,se);
  72. figure,imshow(img2);

OpenCV写得图像配准(SIFT算法)

[cpp] view plain copy
  1. #include<iostream>
  2. #include <opencv2/highgui/highgui.hpp>
  3. #include "opencv2/core/core.hpp"
  4. #include "highgui.h"
  5. #include "opencv2/imgproc/imgproc.hpp"
  6. #include "opencv2/features2d/features2d.hpp"
  7. #include "opencv2/nonfree/nonfree.hpp"
  8. #include "opencv2/legacy/legacy.hpp"
  9. using namespace cv;
  10. using namespace std;
  11. int main(int argc, char** argv)
  12. {
  13. //待匹配的两幅图像,其中img1包括img2,也就是要从img1中识别出img2
  14. Mat img1 = imread("a1.jpg");
  15. Mat img2 = imread("a2.jpg");
  16. SIFT sift1, sift2;
  17. vector<KeyPoint> key_points1, key_points2;
  18. Mat descriptors1, descriptors2, mascara;
  19. sift1(img1, mascara, key_points1, descriptors1);
  20. sift2(img2, mascara, key_points2, descriptors2);
  21. //实例化暴力匹配器——BruteForceMatcher
  22. BruteForceMatcher<L2<float>> matcher;
  23. //定义匹配器算子
  24. vector<DMatch>matches;
  25. //实现描述符之间的匹配,得到算子matches
  26. matcher.match(descriptors1, descriptors2, matches);
  27. //提取出前30个最佳匹配结果
  28. std::nth_element(matches.begin(),     //匹配器算子的初始位置
  29. matches.begin() + 29,     // 排序的数量
  30. matches.end());       // 结束位置
  31. //剔除掉其余的匹配结果
  32. matches.erase(matches.begin() + 30, matches.end());
  33. namedWindow("SIFT_matches");
  34. Mat img_matches;
  35. //在输出图像中绘制匹配结果
  36. drawMatches(img1, key_points1,         //第一幅图像和它的特征点
  37. img2, key_points2,      //第二幅图像和它的特征点
  38. matches,       //匹配器算子
  39. img_matches,      //匹配输出图像
  40. Scalar(255, 0, 255));     //用红色色直线连接两幅图像中的特征点
  41. imshow("SIFT_matches", img_matches);
  42. waitKey(0);
  43. return 0;
  44. }

配准效果(图像存在刚性平移):

OpenCV中的SURF算法解决平移问题:

[cpp] view plain copy
  1. #include <opencv2/legacy/legacy.hpp>
  2. #include <opencv2/nonfree/nonfree.hpp>//opencv_nonfree模块:包含一些拥有专利的算法,如SIFT、SURF函数源码。
  3. #include <stdio.h>
  4. #include <iostream>
  5. #include "opencv2/core/core.hpp"
  6. #include "opencv2/features2d/features2d.hpp"
  7. #include "opencv2/highgui/highgui.hpp"
  8. #include <opencv2/nonfree/features2d.hpp>
  9. #include "vector"
  10. using namespace cv;
  11. using namespace std;
  12. void translateTransform(cv::Mat const& src, cv::Mat& dst, int dx, int dy)
  13. {
  14. //CV_Assert(src.depth() == CV_8U);
  15. const int rows = src.rows;
  16. const int cols = src.cols;
  17. dst.create(rows, cols, src.type());
  18. for (int i = 0; i < rows; i++)
  19. {
  20. for (int j = 0; j < cols; j++)
  21. {
  22. //平移后坐标映射到原图像
  23. int x = j - dx;
  24. int y = i - dy;
  25. //保证映射后的坐标在原图像范围内
  26. if (x >= 0 && y >= 0 && x < cols && y < rows)
  27. dst.at<uchar>(i, j) = src.at<uchar>(y, x);
  28. else
  29. dst.at<uchar>(i, j) = src.at<uchar>(i, j);
  30. }
  31. }
  32. }
  33. int main(int argc, char** argv)
  34. {
  35. Mat img_11 = imread("a1.jpg");
  36. Mat img_22 = imread("a2.jpg");
  37. if (!img_11.data || !img_22.data)
  38. {
  39. std::cout << " --(!) Error reading images " << std::endl;
  40. return -1;
  41. }
  42. Mat img_1, img_2;
  43. cvtColor(img_11, img_1, CV_BGR2GRAY);
  44. cvtColor(img_22, img_2, CV_BGR2GRAY);
  45. //-- Step 1: Detect the keypoints using SURF Detector
  46. int minHessian = 40;
  47. //SiftFeatureDetector detector(minHessian);
  48. SurfFeatureDetector detector( minHessian );
  49. std::vector<KeyPoint> keypoints_1, keypoints_2;
  50. detector.detect(img_1, keypoints_1);
  51. detector.detect(img_2, keypoints_2);
  52. //-- Step 2: Calculate descriptors (feature vectors)
  53. //SiftDescriptorExtractor extractor;
  54. SurfDescriptorExtractor extractor;
  55. Mat descriptors_1, descriptors_2;
  56. extractor.compute(img_1, keypoints_1, descriptors_1);
  57. extractor.compute(img_2, keypoints_2, descriptors_2);
  58. //-- Step 3: Matching descriptor vectors using FLANN matcher
  59. FlannBasedMatcher matcher;
  60. std::vector< DMatch > matches;
  61. matcher.match(descriptors_1, descriptors_2, matches);
  62. double max_dist = 0; double min_dist = 100;
  63. //-- Quick calculation of max and min distances between keypoints
  64. for (int i = 0; i < descriptors_1.rows; i++)
  65. {
  66. double dist = matches[i].distance;
  67. if (dist < min_dist) min_dist = dist;
  68. if (dist > max_dist) max_dist = dist;
  69. }
  70. printf("-- Max dist : %f \n", max_dist);
  71. printf("-- Min dist : %f \n", min_dist);
  72. //-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist )
  73. //-- PS.- radiusMatch can also be used here.
  74. std::vector< DMatch > good_matches;
  75. for (int i = 0; i < descriptors_1.rows; i++)
  76. {
  77. if (matches[i].distance < 2 * min_dist)
  78. {
  79. good_matches.push_back(matches[i]);
  80. }
  81. }
  82. //-- Draw only "good" matches
  83. Mat img_matches;
  84. drawMatches(img_1, keypoints_1, img_2, keypoints_2,
  85. good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
  86. vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
  87. //-- Show detected matches
  88. imshow("Good Matches", img_matches);
  89. //imwrite("a_match_surf.jpg",img_matches);
  90. //imwrite("a_match_sift.jpg",img_matches);
  91. int cnt_nums = 0;
  92. float tran_row = 0;
  93. float tran_col = 0;
  94. for ( unsigned int i = 0; i < good_matches.size(); i++)
  95. {
  96. //good_matches[i].queryIdx保存着第一张图片匹配点的序号,keypoints_1[good_matches[i].queryIdx].pt.x 为该序号对应的点的x坐标。y坐标同理
  97. //good_matches[i].trainIdx保存着第二张图片匹配点的序号,keypoints_2[good_matches[i].trainIdx].pt.x 为为该序号对应的点的x坐标。y坐标同理
  98. float x1_zuo = keypoints_1[good_matches[i].queryIdx].pt.x;
  99. float y1_zuo = keypoints_1[good_matches[i].queryIdx].pt.y;
  100. float x2_zuo = keypoints_2[good_matches[i].trainIdx].pt.x;
  101. float y2_zuo = keypoints_2[good_matches[i].trainIdx].pt.y;
  102. printf("-- Good Match良性匹配点第[%d]个, 来自图1的关键点(坐标为 %f,%f):点的编号为 %d  \n --来自图2的关键点(坐标为 %f,%f): 点的编号为 %d  \n", i,
  103. keypoints_1[good_matches[i].queryIdx].pt.x, keypoints_1[good_matches[i].queryIdx].pt.y, good_matches[i].queryIdx,
  104. keypoints_2[good_matches[i].trainIdx].pt.x, keypoints_2[good_matches[i].trainIdx].pt.y, good_matches[i].trainIdx);
  105. tran_row += keypoints_2[good_matches[i].trainIdx].pt.x - keypoints_1[good_matches[i].queryIdx].pt.x;
  106. tran_col += keypoints_2[good_matches[i].trainIdx].pt.y - keypoints_1[good_matches[i].queryIdx].pt.y;
  107. cnt_nums++;
  108. }
  109. int tr_row = ceil(tran_row / cnt_nums);
  110. int tr_col = ceil(tran_col / cnt_nums);
  111. cout << "偏移量为:" << tr_row << "  " << tr_col;
  112. Mat dst;
  113. //灰度图的平移
  114. translateTransform(img_2,dst,-tr_row,-tr_col);
  115. imshow("校准结果", dst);
  116. waitKey(0);
  117. return 0;
  118. }

注意:最后的匹配结果保存在vector<DMatch>中。DMatch用来保存匹配后的结果

[cpp] view plain copy
  1. struct DMatch
  2. {         //三个构造函数
  3. DMatch() :
  4. queryIdx(-1), trainIdx(-1), imgIdx(-1), distance(std::numeric_limits<float>::max()) {}
  5. DMatch(int  _queryIdx, int  _trainIdx, float  _distance) :
  6. queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(-1), distance(_distance) {}
  7. DMatch(int  _queryIdx, int  _trainIdx, int  _imgIdx, float  _distance) : queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(_imgIdx), distance(_distance) {}
  8. int queryIdx;  //此匹配对应的查询图像的特征描述子索引
  9. int trainIdx;   //此匹配对应的训练(模板)图像的特征描述子索引
  10. int imgIdx;    //训练图像的索引(若有多个)
  11. float distance;  //两个特征向量之间的欧氏距离,越小表明匹配度越高。
  12. bool operator < (const DMatch &m) const;
  13. };

该校准结果是对上面这幅图中右边这幅偏移图像的校准结果,但是明显的问题是,边界问题没有处理好。

博文收录于转载:

一,图像配准算法小总结
首先,图像配准要素结合:特征空间,搜索空间,搜索策略,近似性度量;图像配准方法: 
1.基于灰度信息的方法:交叉相关(互相关)方法,相关系数度量,序贯相似检测算法,信息理论的交换信息相似性准则。 
2.基于变换域的方法:相位相关法,Walsh Transform变换。 
3.基于特征的方法:常用的图像特征有:特征点(包括角点、高曲率点等)、直线段、边缘(Robert、高斯-拉普拉斯LoG、Canny、Gabor滤波等边缘检测算子)或轮廓、闭合区域、特征结构以及统计特征如矩不变量等。
注:像素灰度信息的互相关算法相比,特征提取包含了高层信号信息,所以该类算法对光照、噪声等的抗干扰能力强。

常用的空间变换模型:刚体变换(平移、旋转与缩放的组合)、仿射变换、透射变换、投影变换、非线性变换。

常用的相似性测度: 
1.距离测度:均方根误差,差绝对值和误差,兰氏距离,Mahalanobis距离,绝对差,Hausdorff距离等。 
2.角度度量法(概率测度)。 
3.相关度量法

配准算法的评价标准: 
配准时间、配准率、算法复杂度、算法的可移植性、算法的适用性、图像数据对算法的影响等(这里虽然不是目标追踪的评价标准,但是我们可以借鉴这些评价算法的标准)

二,图像配准算法分类

图像拼接技术主要包括两个关键环节即图像配准和图像融合对于图像融合部分,由于其耗时不太大,且现有的几种主要方法效果差别也不多,所以总体来说算法上比较成熟。而图像配准部分是整个图像拼接技术的核心部分,它直接关系到图像拼接算法的成功率和运行速度,因此配准算法的研究是多年来研究的重点。
目前的图像配准算法基本上可以分为两类:基于频域的方法(相位相关方法)和基于时域的方法。

相位相关法最早是由Kuglin和Hines在1975年提出的,并且证明在纯二维平移的情形下,拼接精度可以达到1个像素,多用于航空照片和卫星遥感图像的配准等领域。该方法对拼接的图像进行快速傅立叶变换,将两幅待配准图像变换到频域,然后通过它们的互功率谱直接计算出两幅图像间的平移矢量,从而实现图像的配准。由于其具有简单而精确的特点,后来成为最有前途的图像配准算法之一。但是相位相关方法一般需要比较大的重叠比例(通常要求配准图像之间有50%的重叠比例),如果重叠比例较小,则容易造成平移矢量的错误估计,从而较难实现图像的配准。

基于时域的方法又可具体分为基于特征的方法和基于区域的方法。基于特征的方法首先找出两幅图像中的特征点(如边界点、拐点),并确定图像间特征点的对应关系,然后利用这种对应关系找到两幅图像间的变换关系。这一类方法不直接利用图像的灰度信息,因而对光线变化不敏感,但对特征点对应关系的精确程度依赖很大。这一类方法采用的思想较为直观,目前大部分的图像配准算法都可以归为这一类。基于区域的方法是以一幅图像重叠区域中的一块作为模板,在另一幅图像中搜索与此模板最相似的匹配块,这种算法精度较高,但计算量过大。

按照匹配算法的具体实现又可以分为直接法和搜索法两大类,直接法主要包括变换优化法,它首先建立两幅待拼接图像间的变换模型,然后采用非线性迭代最小化算法直接计算出模型的变换参数,从而确定图像的配准位置。该算法效果较好,收敛速度较快,但是它要达到过程的收敛要求有较好的初始估计,如果初始估计不好,则会造成图像拼接的失败。搜索法主要是以一幅图像中的某些特征为依据,在另一幅图像中搜索最佳配准位置,常用的有比值匹配法,块匹配法和网格匹配法。比值匹配法是从一幅图像的重叠区域中部分相邻的两列上取出部分像素,然后以它们的比值作模板,在另一幅图像中搜索最佳匹配。这种算法计算量较小,但精度较低;块匹配法则是以一幅图像重叠区域中的一块作为模板,在另一幅图像中搜索与此模板最相似的匹配块,这种算法精度较高,但计算量过大;网格匹配法减小了块匹配法的计算量,它首先要进行粗匹配,每次水平或垂直移动一个步长,记录最佳匹配位置,然后在此位置附近进行精确匹配,每次步长减半,然后循环此过程直至步长减为0。这种算法较前两种运算量都有所减小,但在实际应用中仍然偏大,而且粗匹配时如果步长取的太大,很可能会造成较大的粗匹配误差,从而很难实现精确匹配。

参考资源:

【1】http://blog.csdn.net/zddblog/article/details/7521424

【2】http://www.cs.ubc.ca/~lowe/keypoints/

【3】http://blog.csdn.net/zhaocj/article/details/42124473

【4】http://www.cnblogs.com/cj695/p/4041478.html

【5】http://blog.csdn.net/llw01/article/details/9258699

【6】http://blog.csdn.net/xuluohongshang/article/details/52886352

注:本博文为EbowTang原创,后续可能继续更新本文。如果转载,请务必复制本条信息!

原文地址:http://blog.csdn.net/ebowtang/article/details/51236061

原作者博客:http://blog.csdn.net/ebowtang

版权声明:本文为EbowTang原创文章,后续可能继续更新本文。如果转载,请务必复制本文末尾的信息!

数字图像处理,图像配准SIFT算法 (Lowe的代码)相关推荐

  1. 数字图像处理 图像对比度增强算法概览

    一.图像对比度增强 图像对比度增强又叫作图像对比度拉伸或者直接称为点运算.图像亮度和对比度调整的目的之一是在合适的亮度上提供最大的细节信息,细节纹理的沟纹越深,图像越清晰.在图像处理中,图像对比度增强 ...

  2. 图像配准----SIFT

    SIFT算子(Scale Invariant Feature Transform)是David Lowe提出的一种基于尺度空间的.对图像缩放.旋转甚至仿射变换保持不变性的图像局部特征描述算子.SIFT ...

  3. 数字图像处理图像反转的实现_使用8086微处理器反转16位数字

    数字图像处理图像反转的实现 Problem statement: 问题陈述: Write an assembly language program in 8086 microprocessor to ...

  4. 数字图像处理图像反转的实现_反转8位数字| 8085微处理器

    数字图像处理图像反转的实现 Problem statement: 问题陈述: To reverse 8 bits number using 8085 microprocessors. 使用8085微处 ...

  5. 数字图像处理——隐形眼镜缺陷检测算法

    数字图像处理--隐形眼镜缺陷检测算法 摘 要:本文致力于寻找出一种具有较强鲁棒性的检测隐形眼镜边缘缺陷的方法.本文针对图像中物体几何形状的特殊性,提出了一种基于霍夫变换的缺陷检测算法,并在低噪声图像的 ...

  6. 计算机图像进行滤波的函数,数字图像处理图像滤波.ppt

    数字图像处理图像滤波 图像滤波 图像处理中所用到的图像往往含有噪声,需要用图像滤波的方法去除噪声. 内容框架 像素基础知识介绍 算术和逻辑运算 直方图 直方图均衡算法,用于图像锐化. 图像增强基本方法 ...

  7. 数字图像处理课设图像的锐化_数字图像处理图像锐化处理.ppt

    数字图像处理图像锐化处理 4.7.2 灰度级到彩色转换 灰度级到彩色转换(例) 在HSI彩色空间的直方图均衡强度均衡处理没有改变图像的色调和饱和度值,但它的确影响了整体图像的彩色感观. 向量分量可以用 ...

  8. matlab 求其骨架,数字图像处理图像的骨架生成和提取(Matlab)三种方法

    [实例简介] 数字图像处理图像的骨架生成和提取(Matlab),有三种方法,推荐给大家! [实例截图] [核心代码] Programe ├── Programe1 │   ├── 00.JPG │   ...

  9. Matlab数字图像处理——图像的空间变换

    Matlab空间变换函数 imtransform Matlab空间变换函数 imtransform 可以实现图像仿射变换(如 平移.旋转.剪切.缩放).投影变换, 该函数可与 maketform 配合 ...

  10. 《opencv 数字图像处理 图像基础》

    <opencv 数字图像处理 图像基础> 矩阵 通道分离和合并 彩色图像转灰度图像 灰度图转二值化图像 图像运算 矩阵 定义一个显示图像的函数,对于灰度图,里面添加了vmin=0,vmax ...

最新文章

  1. 若不能连接到sql server的localhost
  2. springmvc二十:数据绑定
  3. (建议收藏)产品经理要懂的SaaS知识,一文打包给你
  4. logrotate管理nginx日志文件
  5. Python——文本进度条
  6. 安徽工业大学计算机学院推免名单,2021年安徽工业大学拟录取推免研究生名单公示...
  7. linux下安装Oracle10g时,安装rpm文件的技巧 (rpm -Uvh package名)
  8. Linux脚本5秒后启动程序,嵌入式Linux启动时间优化的秘密之四-启动脚本
  9. asp.net 将ppt,word转化为pdf实现在线浏览详解
  10. Robot Framework 的安装配置和简单的实例介绍
  11. 《FLUENT 14流场分析自学手册》——1.3 附面层理论
  12. windows 清理助手 3.1
  13. cad相对坐标快捷键_47个快捷键+50个CAD技巧助你玩转CAD
  14. 分享一个商品历史价格查询的网站
  15. APtos 简介及机制
  16. leetcode1108-1111、1114-1117
  17. 十种最令人讨厌的编程语言,你使用的语言上榜了吗?
  18. form 表单 onsubmit 属性
  19. L1正则化与L2正则化详解
  20. Chrome升级后不能访问任何网站和自身设置

热门文章

  1. 计算机无法正常启动安全模式开启,Win7电脑开机无法正常启动只能进入安全模式怎么解决...
  2. SMI/SAMI 字幕
  3. 深入浅出讲解梯度消失和梯度爆炸问题(原因、解决方法)
  4. 转载-公历转换农历VB示例
  5. vmin、vmax用处
  6. SoftICE使用(2)-网络远程调试zz xfocus
  7. sourceTree 添加 ssh key 方法
  8. linux系统怎么拨号上网,linux配置上网 linux adsl拨号上网设置
  9. Windows2000下IE5升级到IE6
  10. 微信小程序 条码 二维码生成