- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
1.功能描述
ShapeContextDistanceExtractor是OpenCV库中的一个类,主要用于计算形状之间的相似度或距离。它是基于形状上下文(Shape Context)特征描述符的,这是一种在计算机视觉和图像处理领域广泛使用的形状匹配技术。该方法由Belongie等人在2000年代初提出,通过分析形状边界点的邻域分布来描述形状特征,进而计算形状间的相似度。
2.使用场景
形状匹配:在图像数据库中查找相似的形状或对象。
物体识别:作为特征提取的一部分,辅助分类或识别任务。
内容基于的图像检索:根据形状内容搜索图像。
3.函数computeDistance
计算由其轮廓定义的两个形状之间的形状距离,首先提取每个轮廓的关键点及其邻域信息,然后通过比较不同轮廓间对应关键点的邻域分布差异来量化形状间的距离。
3.1函数原型
virtual float cv::ShapeDistanceExtractor::computeDistance (
InputArray contour1,
InputArray contour2
)
3.2 参数
- 参数contour1 定义第一个形状的轮廓.
- 参数contour2 定义第二个形状的轮廓…
4 示例代码
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/shape.hpp"
#include <iostream>
#include <opencv2/core/utility.hpp>
#include <string>
using namespace std;
using namespace cv;
static vector< Point > simpleContour( const Mat& currentQuery, int n = 300 )
{
vector< vector< Point > > _contoursQuery;
vector< Point > contoursQuery;
findContours( currentQuery, _contoursQuery, RETR_LIST, CHAIN_APPROX_NONE );
for ( size_t border = 0; border < _contoursQuery.size(); border++ )
{
for ( size_t p = 0; p < _contoursQuery[ border ].size(); p++ )
{
contoursQuery.push_back( _contoursQuery[ border ][ p ] );
}
}
// In case actual number of points is less than n
int dummy = 0;
for ( int add = ( int )contoursQuery.size() - 1; add < n; add++ )
{
contoursQuery.push_back( contoursQuery[ dummy++ ] ); // adding dummy values
}
// 均匀采样
cv::randShuffle( contoursQuery );
vector< Point > cont;
for ( int i = 0; i < n; i++ )
{
cont.push_back( contoursQuery[ i ] );
}
return cont;
}
int main( int argc, char** argv )
{
string path = "/media/dingxin/data/study/OpenCV/sources/images/shape/";
cv::Ptr< cv::ShapeContextDistanceExtractor > mysc = cv::createShapeContextDistanceExtractor();
Size sz2Sh( 300, 300 );
stringstream queryName;
int indexQuery = 1;
queryName << path << indexQuery << ".jpg";
Mat query = imread( queryName.str(), IMREAD_GRAYSCALE );
Mat queryToShow;
resize( query, queryToShow, sz2Sh, 0, 0, INTER_LINEAR_EXACT );
imshow( "QUERY", queryToShow );
moveWindow( "TEST", 0, 0 );
vector< Point > contQuery = simpleContour( query );
int bestMatch = 0;
float bestDis = FLT_MAX;
for ( int ii = 1; ii <= 4; ii++ )
{
if ( ii == indexQuery )
continue;
waitKey( 30 );
stringstream iiname;
iiname << path << ii << ".jpg";
cout << "name: " << iiname.str() << endl;
Mat iiIm = imread( iiname.str(), 0 );
Mat iiToShow;
resize( iiIm, iiToShow, sz2Sh, 0, 0, INTER_LINEAR_EXACT );
imshow( "TEST", iiToShow );
moveWindow( "TEST", sz2Sh.width + 50, 0 );
vector< Point > contii = simpleContour( iiIm );
float dis = mysc->computeDistance( contQuery, contii );
//获取匹配度最佳的id和匹配距离值
if ( dis < bestDis )
{
bestMatch = ii;
bestDis = dis;
}
std::cout << " distance between " << queryName.str() << " and " << iiname.str() << " is: " << dis << std::endl;
}
destroyWindow( "TEST" );
stringstream bestname;
bestname << path << bestMatch << ".jpg";
Mat iiIm = imread( bestname.str(), 0 );
Mat bestToShow;
resize( iiIm, bestToShow, sz2Sh, 0, 0, INTER_LINEAR_EXACT );
imshow( "BEST MATCH", bestToShow );
moveWindow( "BEST MATCH", sz2Sh.width + 50, 0 );
waitKey();
return 0;
}
运行结果
我一共选了4张图,拿第一张图跟其他三张图比较,看哪个图跟第一张图里的足球形状匹配的最好。四张图如下:
运行结果:
命令行输出结果: