opencv学习 特征提取

内容来源于《opencv4应用开发入门、进阶与工程化实践》  

图像金字塔

拉普拉斯金字塔

对输入图像进行reduce操作会生成不同分辨率的图像,对这些图像进行expand操作,然后使用reduce减去expand之后的结果,就会得到拉普拉斯金字塔图像。

详情可查看https://zhuanlan.zhihu.com/p/80362140

图像金字塔融合

 拉普拉斯金字塔通过源图像减去先缩小再放大的图像构成,保留的是残差,为图像还原做准备。

根据拉普拉斯金字塔的定义可以知道,拉普拉斯金字塔的每一层都是一个高斯差分图像。:

原图 = 拉普拉斯金字塔图L0层 + expand(高斯金字塔G1层),也就是说,可以基于低分辨率的图像与它的高斯差分图像,重建生成一个高分辨率的图像。

详情参考https://zhuanlan.zhihu.com/p/454085730的图像融合部分,讲的很好。

步骤:

  1. 生成苹果、橘子的高斯金字塔G_{L}G_{R}
  2.  求苹果、橘子的的拉普拉斯金字塔L_{apple}L_{orange}
  3. 求mask的高斯金字塔G_{mask}
  4. 在每个尺度(分辨率)下,用G_{mask}拼接L_{apple}L_{orange},最终得到拼接的拉普拉斯金字塔L_{fused}
  5. 生成最低分辨率的起始图(都选取最低分辨率下的G_{L}G_{R} 根据同分辨率下G_{mask} 进行拼接,得到最低分辨率下的拼接结果 O_{min}
  6. O_{min}开始,利用L_{fused}得到最高分辨率的拼接结果

示例代码:

int level = 3;
Mat smallestLevel;
Mat blend(Mat &a, Mat &b, Mat &m) {int width = a.cols;int height = a.rows;Mat dst = Mat::zeros(a.size(), a.type());Vec3b rgb1;Vec3b rgb2;int r1 = 0, g1 = 0, b1 = 0;int r2 = 0, g2 = 0, b2 = 0;int red = 0, green = 0, blue = 0;int w = 0;float w1 = 0, w2 = 0;for (int row = 0; row<height; row++) {for (int col = 0; col<width; col++) {rgb1 = a.at<Vec3b>(row, col);rgb2 = b.at<Vec3b>(row, col);w = m.at<uchar>(row, col);w2 = w / 255.0f;w1 = 1.0f - w2;b1 = rgb1[0] & 0xff;g1 = rgb1[1] & 0xff;r1 = rgb1[2] & 0xff;b2 = rgb2[0] & 0xff;g2 = rgb2[1] & 0xff;r2 = rgb2[2] & 0xff;red = (int)(r1*w1 + r2*w2);green = (int)(g1*w1 + g2*w2);blue = (int)(b1*w1 + b2*w2);// outputdst.at<Vec3b>(row, col)[0] = blue;dst.at<Vec3b>(row, col)[1] = green;dst.at<Vec3b>(row, col)[2] = red;}}return dst;
}vector<Mat> buildGaussianPyramid(Mat &image) {vector<Mat> pyramid;Mat copy = image.clone();pyramid.push_back(image.clone());Mat dst;for (int i = 0; i<level; i++) {pyrDown(copy, dst, Size(copy.cols / 2, copy.rows / 2));dst.copyTo(copy);pyramid.push_back(dst.clone());}smallestLevel = dst;return pyramid;
}vector<Mat> buildLapacianPyramid(Mat &image) {vector<Mat> lp;Mat temp;Mat copy = image.clone();Mat dst;for (int i = 0; i<level; i++) {pyrDown(copy, dst, Size(copy.cols / 2, copy.rows / 2));pyrUp(dst, temp, copy.size());Mat lapaian;subtract(copy, temp, lapaian);lp.push_back(lapaian);copy = dst.clone();}smallestLevel = dst;return lp;
}
void FeatureVectorOps::pyramid_blend_demo(Mat &apple, Mat &orange) {Mat mc = imread("D:/images/mask.png");if (apple.empty() || orange.empty()) {return;}imshow("苹果图像", apple);imshow("橘子图像", orange);vector<Mat> la = buildLapacianPyramid(apple);Mat leftsmallestLevel;smallestLevel.copyTo(leftsmallestLevel);vector<Mat> lb = buildLapacianPyramid(orange);Mat rightsmallestLevel;smallestLevel.copyTo(rightsmallestLevel);Mat mask;cvtColor(mc, mask, COLOR_BGR2GRAY);vector<Mat> maskPyramid = buildGaussianPyramid(mask);Mat samllmask;smallestLevel.copyTo(samllmask);Mat currentImage = blend(leftsmallestLevel, rightsmallestLevel, samllmask);imwrite("D:/samll.png", currentImage);// 重建拉普拉斯金字塔vector<Mat> ls;for (int i = 0; i<level; i++) {Mat a = la[i];Mat b = lb[i];Mat m = maskPyramid[i];ls.push_back(blend(a, b, m));}// 重建原图Mat temp;for (int i = level - 1; i >= 0; i--) {pyrUp(currentImage, temp, ls[i].size());add(temp, ls[i], currentImage);}imshow("高斯金子图像融合重建-图像", currentImage);
}

Harris角点检测

角点是图像中亮度变化最强的地方,反映了图像的本质特征。

图像的角点在各个方向上都有很强的梯度变化。

亚像素级别的角点检测

详细请参考https://www.cnblogs.com/qq21497936/p/13096048.html

大概理解是角点一般在边缘上,边缘的梯度与沿边缘方向的的向量正交,也就是内积为0,根据内积为零,角点周围能列出一个方程组,方程组的解就是角点坐标。

opencv亚像素级别定位函数API:

void cv::cornerSubPix(InputArray imageInputOutputArray corners //输入整数角点坐标,输出浮点数角点坐标Size winSize //搜索窗口Size zeroZone TermCriteria criteria //停止条件
)

 示例代码

void FeatureVectorOps::corners_sub_pixels_demo(Mat &image) {Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);int maxCorners = 400;double qualityLevel = 0.01;std::vector<Point2f> corners;goodFeaturesToTrack(gray, corners, maxCorners, qualityLevel, 5, Mat(), 3, false, 0.04);Size winSize = Size(5, 5);Size zeroZone = Size(-1, -1);//opencv迭代终止条件类TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.001);cornerSubPix(gray, corners, winSize, zeroZone, criteria);for (size_t t = 0; t < corners.size(); t++) {printf("refined Corner: %d, x:%.2f, y:%.2f\n", t, corners[t].x, corners[t].y);}
}

HOG特征描述子

详细请参考:https://baijiahao.baidu.com/s?id=1646997581304332534&wfr=spider&for=pc&searchword=HOG%E7%89%B9%E5%BE%81%E6%8F%8F%E8%BF%B0%E5%AD%90

讲的很好。

大概就是以一种特殊的直方图来表示图像特征,直方图存储的是梯度的方向和幅值(x轴是方向,y轴是幅值且加权)。

示例代码:

virtual void cv::HOGDescriptor::compute(InputArray imgstd::vector<float> & descriptorsSize winStride=Size()Size padding=Size()const std::vector<Point> &locations = std::vector<Point>()
)void FeatureVectorOps::hog_feature_demo(Mat &image) {Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);HOGDescriptor hogDetector;std::vector<float> hog_descriptors;hogDetector.compute(gray, hog_descriptors, Size(8, 8), Size(0, 0));std::cout << hog_descriptors.size() << std::endl;for (size_t t = 0; t < hog_descriptors.size(); t++) {std::cout << hog_descriptors[t] << std::endl;}
}

HOG特征行人检测

opencv基于HOG行人特征描述子的检测函数:

void HOGDescriptor::detectMultiScale(InputArray img,vector<Rect>& foundLocations, double hitThreshold=0, Size winStride=Size(), Size padding=Size(),double scale=1.05,double finalThreshold=2.0,bool useMeanshiftGrouping=false
)
//示例代码
void FeatureVectorOps::hog_detect_demo(Mat &image) {HOGDescriptor *hog = new HOGDescriptor();hog->setSVMDetector(hog->getDefaultPeopleDetector());vector<Rect> objects;hog->detectMultiScale(image, objects, 0.0, Size(4, 4), Size(8, 8), 1.25);for (int i = 0; i < objects.size(); i++) {rectangle(image, objects[i], Scalar(0, 0, 255), 2, 8, 0);}imshow("HOG行人检测", image);
}

ORB特征描述子

没看懂。

描述子匹配

暴力匹配:

再使用暴力匹配之前先创建暴力匹配器:

static Ptr<BFMatcher> cv::BFMatcher::create(int normType=NORM_L2 //计算描述子暴力匹配时采用的计算方法bool crossCheck=false //是否使用交叉验证
)

调用暴力匹配的匹配方法,有两种,最佳匹配和KNN匹配

void cv::DescriptorMatch::match(InputArray queryDescriptorsInputArray trainDescriptorsstd::vector<DMatch> & matchesInputArray mask=noArray
)void cv::DescriptorMatch::knnMatch(InputArray queryDescriptorsInputArray trainDescriptorsstd::vector<DMatch> & matchesint kInputArray mask=noArraybool compactResult =false
)
FLANN匹配:
cv::FlannBasedMatcher::FlannBasedMatcher(const Ptr<flann::IndexParams> & indexParams=makePtr<flann::KDTreeIndexParams>()const Ptr<flann::SearchParams> & searchParams=makePtr<flann::SearchParams>()
)

示例代码:

void FeatureVectorOps::orb_match_demo(Mat &box, Mat &box_in_scene) {// ORB特征提取auto orb_detector = ORB::create();std::vector<KeyPoint> box_kpts;std::vector<KeyPoint> scene_kpts;Mat box_descriptors, scene_descriptors;orb_detector->detectAndCompute(box, Mat(), box_kpts, box_descriptors);orb_detector->detectAndCompute(box_in_scene, Mat(), scene_kpts, scene_descriptors);// 暴力匹配auto bfMatcher = BFMatcher::create(NORM_HAMMING, false);std::vector<DMatch> matches;bfMatcher->match(box_descriptors, scene_descriptors, matches);Mat img_orb_matches;drawMatches(box, box_kpts, box_in_scene, scene_kpts, matches, img_orb_matches);imshow("ORB暴力匹配演示", img_orb_matches);// FLANN匹配auto flannMatcher = FlannBasedMatcher(new flann::LshIndexParams(6, 12, 2));flannMatcher.match(box_descriptors, scene_descriptors, matches);Mat img_flann_matches;drawMatches(box, box_kpts, box_in_scene, scene_kpts, matches, img_flann_matches);namedWindow("FLANN匹配演示", WINDOW_FREERATIO);cv::namedWindow("FLANN匹配演示", cv::WINDOW_NORMAL);imshow("FLANN匹配演示", img_flann_matches);
}

基于特征的对象检测

特征描述子匹配之后,可以根据返回的各个DMatch中的索引得到关键点对,然后拟合生成从对象到场景的变换矩阵H。根据矩阵H可以求得对象在场景中的位置,从而完成基于特征的对象检测。

opencv中求得单应性矩阵的API:

Mat cv::findHomograph(InputArray srcPointsOutputArray dstPointsint method=0double ransacReprojThreshold=3OutputArray mask=noArray()const int maxIters=2000;const double confidence=0.995
)

有了变换矩阵H ,可以运用透视变换函数求得场景中对象的四个点坐标并绘制出来。

透视变换函数:

void cv::perspectiveTransform(InputArray srcOutputArray dstInputArray m
)

示例代码:

void FeatureVectorOps::find_known_object(Mat &book, Mat &book_on_desk) {// ORB特征提取auto orb_detector = ORB::create();std::vector<KeyPoint> box_kpts;std::vector<KeyPoint> scene_kpts;Mat box_descriptors, scene_descriptors;orb_detector->detectAndCompute(book, Mat(), box_kpts, box_descriptors);orb_detector->detectAndCompute(book_on_desk, Mat(), scene_kpts, scene_descriptors);// 暴力匹配auto bfMatcher = BFMatcher::create(NORM_HAMMING, false);std::vector<DMatch> matches;bfMatcher->match(box_descriptors, scene_descriptors, matches);// 好的匹配std::sort(matches.begin(), matches.end());const int numGoodMatches = matches.size() * 0.15;matches.erase(matches.begin() + numGoodMatches, matches.end());Mat img_bf_matches;drawMatches(book, box_kpts, book_on_desk, scene_kpts, matches, img_bf_matches);imshow("ORB暴力匹配演示", img_bf_matches);// 单应性求Hstd::vector<Point2f> obj_pts;std::vector<Point2f> scene_pts;for (size_t i = 0; i < matches.size(); i++){//-- Get the keypoints from the good matchesobj_pts.push_back(box_kpts[matches[i].queryIdx].pt);scene_pts.push_back(scene_kpts[matches[i].trainIdx].pt);}Mat H = findHomography(obj_pts, scene_pts, RANSAC);std::cout << "RANSAC estimation parameters: \n" << H << std::endl;std::cout << std::endl;H = findHomography(obj_pts, scene_pts, RHO);std::cout << "RHO estimation parameters: \n" << H << std::endl;std::cout << std::endl;H = findHomography(obj_pts, scene_pts, LMEDS);std::cout << "LMEDS estimation parameters: \n" << H << std::endl;// 变换矩阵得到目标点std::vector<Point2f> obj_corners(4);obj_corners[0] = Point(0, 0); obj_corners[1] = Point(book.cols, 0);obj_corners[2] = Point(book.cols, book.rows); obj_corners[3] = Point(0, book.rows);std::vector<Point2f> scene_corners(4);perspectiveTransform(obj_corners, scene_corners, H);// 绘制结果Mat dst;line(img_bf_matches, scene_corners[0] + Point2f(book.cols, 0), scene_corners[1] + Point2f(book.cols, 0), Scalar(0, 255, 0), 4);line(img_bf_matches, scene_corners[1] + Point2f(book.cols, 0), scene_corners[2] + Point2f(book.cols, 0), Scalar(0, 255, 0), 4);line(img_bf_matches, scene_corners[2] + Point2f(book.cols, 0), scene_corners[3] + Point2f(book.cols, 0), Scalar(0, 255, 0), 4);line(img_bf_matches, scene_corners[3] + Point2f(book.cols, 0), scene_corners[0] + Point2f(book.cols, 0), Scalar(0, 255, 0), 4);//-- Show detected matchesnamedWindow("基于特征的对象检测", cv::WINDOW_NORMAL);imshow("基于特征的对象检测", img_bf_matches);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/657353.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【开源操作系统】上海道宁为您带来稳定、安全、开源和易用的操作系统——Ubuntu,为您的数字化生活保驾护航

Ubuntu是 源于非洲的一种传统价值观 意为“人性、关爱和共享” 这种价值观在 开源、稳定、安全、易用的 Ubuntu操作系统中 得到了完美的体现 除此之外&#xff0c;Ubuntu还具有 强大的安全性 它自带了诸多安全功能 如防火墙、加密文件系统等 可以有效地保护用户的隐私…

你ping一下,服务器累成狗--第二篇

你ping一下&#xff0c;服务器累成狗-目录篇文章浏览阅读1.7k次&#xff0c;点赞65次&#xff0c;收藏20次。我们的电脑怎么干活的https://blog.csdn.net/u010187815/article/details/135796967 你ping一下&#xff0c;服务器累成狗--第一篇文章浏览阅读62次&#xff0c;点赞6…

Vue自定义事件

简介&#xff1a;Vue自定义事件是对JS原生事件的拓展&#xff0c;允许程序员自定义并注册一些事件名。 JS原生事件的特点&#xff1a; 1. 触发由浏览器进行捕捉得到&#xff1b; 2.DOM节点属性中存在大量的事件属性&#xff0c;例如onclick、onchange等&#xff1b; 3. 存在事件…

Python中hasattr()、getattr()、setattr()

简介 在Python中&#xff0c;hasattr()、getattr()和setattr()是一组内置函数&#xff0c;用于对对象的属性进行操作和查询。这些函数提供了一种方便的方式来检查对象是否具有特定属性&#xff0c;获取属性的值&#xff0c;以及设置属性的值。本文将从入门到精通&#xff0c;全…

C#用正则表达式验证格式:电话号码、密码、邮编、手机号码、身份证、指定的小数点后位数、有效月

正则表达式在程序设计中有着重要的位置&#xff0c;经常被用于处理字符串信息。 用Regex类的IsMatch方法&#xff0c;使用正则表达式可以验证电话号码是否合法。 一、涉及到的知识点 Regex类的IsMatch方法用于指示正则表达式使用pattern参数中指定的正则表达式是否在输入字符串…

「数据结构」实现顺序表

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;Java数据结构 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 实现顺序表 &#x1f349;前言&#x1f349;整体框架&#x1f349;添加元素&#x1f34c;尾插&#x1f34c;任意位置插入 &#…

IntersectionObserver、MutationObserver应用,监听项目中指定属性数据,点击或模块显示时

当项目中&#xff0c;需要获取某个页面上、某个标签上、有指定自定义属性时&#xff0c;需要在点击该元素时进行公共逻辑处理&#xff0c;或该元素在显示的时候进行逻辑处理&#xff0c;这时可以定义一个公共的方法&#xff0c;在每个页面引用&#xff0c;并写入数据即可 &…

自然语言处理的就业前景

国家发展大势所趋&#xff0c;促进各行各业智能化、数字化转型&#xff0c;而计算机自然语言处理是一个快速发展的领域&#xff0c;随着人工智能技术的不断发展和应用&#xff0c;对自然语言处理的需求也越来越大。因此&#xff0c;计算机自然语言处理的就业前景非常好。 在就业…

OSPF的优化

一&#xff1a;OSPF的优化&#xff1a;---lsa的优化 1、汇总 --- 减少骨干区域LSA更新量 2、特殊区域 --- 减少非骨干区域LSA更新量 二&#xff1a;汇总 1、区域汇总&#xff1a;OSPF的汇总被称为区域汇总 域间路由汇总---针对OSPF区域之间的路由进行汇总&#xff0c;针对…

【机器学习300问】21、什么是激活函数?常见激活函数都有哪些?

在我写的上一篇文章中介绍了感知机&#xff08;单个神经元&#xff09;的构成&#xff0c;其中就谈到了神经元会计算传送过来的信号的总和&#xff0c;只有当这个总和超过了某个界限值时&#xff0c;才会输出值。这也称为“神经元被激活”。如果想对神经网络是什么有更多了解的…

npm install 一直卡在 sill idealTree 解决方案

npm install 一直卡在 sill idealTree 解决方案 npm install安装vue项目的依赖时&#xff0c;执行 npm install 一直卡在 idealTree:xxx: sill idealTree buildDeps 。 解决方案&#xff1a; 设置淘宝源 npm config set registry https://registry.npm.taobao.org查看是否设置…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之DataPanel组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之DataPanel组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、DataPanel组件 数据面板组件&#xff0c;用于将多个数据占比情况使用占比图进…

集成学习之Boosting方法系列_XGboost

文章目录 【文章系列】【前言】【算法简介】【正文】&#xff08;一&#xff09;XGBoost前身&#xff1a;梯度提升树&#xff08;二&#xff09;XGBoost的特点&#xff08;三&#xff09;XGBoost实际操作1. 前期准备&#xff08;1&#xff09;数据格式&#xff08;2&#xff09…

小程序定制开发:解析定制化移动应用的未来

引言 在当今数字化时代&#xff0c;移动应用已经成为人们生活不可或缺的一部分。随着智能手机的普及&#xff0c;移动应用的需求呈现出爆发式增长&#xff0c;企业们也纷纷投身于这场数字化浪潮。然而&#xff0c;众多企业在竞争激烈的市场中&#xff0c;如何突显个性、提高用…

使用Eclipse搞Android项目报错

相信现在都没什么人还会用Eclipse来开发的了。 不过安装完后&#xff0c;打开Eclipse会提示我的Jdk版本不符合 --------------------------- Incompatible JVM --------------------------- Version 1.8.0_391 of the JVM is not suitable for this product. Version: 17 or g…

在 C# 中 checked 和 unchecked 关键字

在 C# 中&#xff0c;checked 和 unchecked 是用于控制整数运算溢出检查的关键字。它们允许我们明确指定在进行整数运算时是否要检查溢出&#xff0c;以及如何处理溢出情况。 默认情况下&#xff0c;C# 中的整数运算是未检查的&#xff0c;也就是说&#xff0c;当运算结果溢出…

实现sleep函数

作用&#xff1a;让线程休眠&#xff0c;等到指定时间在重新唤起。 基于Date实现&#xff1a; 以上的代码不会让线程休眠&#xff0c;而是通过高负荷计算使cpu无暇处理其他任务。缺点是在sleep的过程中其他所有的任务都会被暂停&#xff0c;包括dom的渲染。sleep的过程中程序会…

python之poetry模块,项目管理

一、简介 Poetry 是一个用于管理 Python 项目依赖关系和构建工具的工具。它提供了一个简单的命令行界面&#xff0c;可以帮助您创建、管理和发布 Python 项目&#xff0c;使用方法&#xff1a;command [options] [arguments] 官网&#xff1a;https://python-poetry.org/docs/…

书生浦语训练营笔记与作业汇总

课程笔记&#xff1a; 第一节&#xff1a;https://blog.csdn.net/qq_37397652/article/details/135532014第二节&#xff1a;https://blog.csdn.net/qq_37397652/article/details/135533226第三节&#xff1a;https://blog.csdn.net/qq_37397652/article/details/135586700第四…

Android --- Content Provider是使用示例,通俗易懂

当两个应用程序之间需要共享数据时&#xff0c;可以通过 Content Provider 来实现。在这个示例中&#xff0c;我们将创建一个简单的 Content Provider&#xff0c;让 App_B 暴露人口总数的数据&#xff0c;并由 App_A 来获取这个数据。 首先&#xff0c;我们来创建一个简单的示…