OPENCV图像变换-1

图像变换是指将一幅图像变换为图像数据的另一种表现形式,例如将图像进行傅立叶变换,或者对图像进行X,Y方向的求导等,经过这些变换,可以将图像数据处理中的某些问题换一个别的角度想办法,所以图像变换是图像处理的时候比较常用的一种方法.

         一.sobel算子

         sobel算子是一个用于边缘检测的离散微分算子,其结合了高斯平滑和微分求导,用于计算图像灰度函数的近似梯度,在图像的任何一点使用该函数,都将产生对应的梯度矢量或者是发矢量,简单地说,sobel算子适用于计算出图像像素点之间变化幅度的算子,而边缘的变化幅度是最剧烈的,所以sobel算子能用来做边缘检测.

         sobel算子分方向,在x,y方向指定阶数.

         API:void sobel(输入源,输出,int 输出图像深度,int X方向差分阶数,int y方向差分阶数,int sobel邻域核大小,double 可选的缩放因子,double 可选的delata值,double 边界模式)

         注:源图像和目标图像尺寸类型一致,,输出图像的深度根据源图像的深度决定,默认为-1,输出图像必须比源图像的数据更宽,sobel核大小默认为3,只能为1,3,5,7其中之一,缩放因子默认为-1,不缩放,delate值默认为.0

         实际功能代码如下

Mat srcImage,sobelxImage,sobelxAbsImage,sobelyImage,sobelyAbsImage,dstImage;const int g_sobelCoreMax = 2;
int g_sobelCoreValue;const int g_deltaxMax = 9;
int g_deltaxValue;const int g_deltayMax = 9;
int g_deltayValue;void onTrackBarSobelCore(int pos,void* userData);
void onTrackBarSobelDeltax(int pos,void* userData);
void onTrackBarSobelDeltay(int pos,void* userData);int main(int argc,char* argv[])
{srcImage = imread("F:\\opencv\\OpenCVImage\\sobel.jpg");namedWindow("src image");namedWindow("sobelx image");namedWindow("sobely image");namedWindow("sobelxy image");g_sobelCoreValue = 0;g_deltaxValue = 0;g_deltayValue = 0;createTrackbar("core size", "src image", &g_sobelCoreValue, g_sobelCoreMax,onTrackBarSobelCore,0);createTrackbar("deltax value", "src image", &g_deltaxValue, g_deltaxMax,onTrackBarSobelDeltax,0);createTrackbar("deltay value", "src image", &g_deltayValue, g_deltayMax,onTrackBarSobelDeltay,0);onTrackBarSobelCore(g_sobelCoreValue, 0);imshow("src image", srcImage);moveWindow("src image", 0, 0);moveWindow("sobelx image", srcImage.cols, 0);moveWindow("sobely image", 0, srcImage.rows);moveWindow("sobelxy image", srcImage.cols, srcImage.rows);waitKey(0);return 0;
}void onTrackBarSobelCore(int pos,void* userData)
{int coreSize = g_sobelCoreValue*2+3;int deltax = g_deltaxValue+1;int deltay = g_deltayValue+1;Sobel(srcImage, sobelxImage, CV_16S, deltax, 0,coreSize);Sobel(srcImage, sobelyImage, CV_16S, 0, deltay,coreSize);convertScaleAbs(sobelxImage, sobelxAbsImage);convertScaleAbs(sobelyImage, sobelyAbsImage);addWeighted(sobelxAbsImage, 0.5, sobelyAbsImage, 0.5, 0.0, dstImage);imshow("sobelx image", sobelxAbsImage);imshow("sobely image", sobelyAbsImage);imshow("sobelxy image", dstImage);
}void onTrackBarSobelDeltax(int pos,void* userData)
{int coreSize = g_sobelCoreValue*2+3;int deltax = g_deltaxValue+1;int deltay = g_deltayValue+1;Sobel(srcImage, sobelxImage, CV_16S, deltax, 0,coreSize);Sobel(srcImage, sobelyImage, CV_16S, 0, deltay,coreSize);convertScaleAbs(sobelxImage, sobelxAbsImage);convertScaleAbs(sobelyImage, sobelyAbsImage);addWeighted(sobelxAbsImage, 0.5, sobelyAbsImage, 0.5, 0.0, dstImage);imshow("sobelx image", sobelxAbsImage);imshow("sobely image", sobelyAbsImage);imshow("sobelxy image", dstImage);
}void onTrackBarSobelDeltay(int pos,void* userData)
{int coreSize = g_sobelCoreValue*2+3;int deltax = g_deltaxValue+1;int deltay = g_deltayValue+1;Sobel(srcImage, sobelxImage, CV_16S, deltax, 0,coreSize);Sobel(srcImage, sobelyImage, CV_16S, 0, deltay,coreSize);convertScaleAbs(sobelxImage, sobelxAbsImage);convertScaleAbs(sobelyImage, sobelyAbsImage);addWeighted(sobelxAbsImage, 0.5, sobelyAbsImage, 0.5, 0.0, dstImage);imshow("sobelx image", sobelxAbsImage);imshow("sobely image", sobelyAbsImage);imshow("sobelxy image", dstImage);
}

  

当Ksize为1的时候,仅使用1*3内核或者3*1内核,而且没有平滑操作.

二.scharr算子

         当sobel算子核大小为3的时候,因为计算使用的是导数的近似值,为了解决ksize为3的时候的误差问题,opencv引入了函数scharr,scharr和sobel一样快,但是结果更加精确

         另外,对于sobel,因为目标图像的深度一般比源图像的深度更深,所以为了正常的显示目标图像,我们可以使用convertScalarAbs()函数,将深度缩放为八位数字图像,便于显示和保存.

         API:void scharr(源图像,目标图像, int 输出图像深度,int X方向差分阶数,int y方向差分阶数 ,double 可选的缩放因子,double 可选的delata值,double 边界模式)

         注:和sobel相比少了一个邻域核大小,因为默认为3

使用例程代码如下

Mat srcImage,scharrxImage,scharrxAbsImage,scharryImage,scharryAbsImage,dstImage;
const int g_deltaxMax = 0;
int g_deltaxValue;
const int g_deltayMax = 0;
int g_deltayValue;
void onTrackBarScharrDeltax(int pos,void* userData);
void onTrackBarScharrDeltay(int pos,void* userData);int main(int argc,char* argv[])
{srcImage = imread("F:\\opencv\\OpenCVImage\\scharr.jpg");namedWindow("src image");namedWindow("scharrx image");namedWindow("scharry image");namedWindow("scharrxy image");g_deltaxValue = 0;g_deltayValue = 0;createTrackbar("deltax value", "src image", &g_deltaxValue, g_deltaxMax,onTrackBarScharrDeltax,0);createTrackbar("deltay value", "src image", &g_deltayValue, g_deltayMax,onTrackBarScharrDeltay,0);onTrackBarScharrDeltax(g_deltaxValue,0);imshow("src image", srcImage);moveWindow("src image", 0, 0);moveWindow("scharrx image", srcImage.cols, 0);moveWindow("scharry image", 0, srcImage.rows);moveWindow("scharrxy image", srcImage.cols, srcImage.rows);waitKey(0);return 0;
}void onTrackBarScharrDeltax(int pos,void* userData)
{int deltax = g_deltaxValue+1;int deltay = g_deltayValue+1;Scharr(srcImage, scharrxImage, CV_16S, deltax, 0);Scharr(srcImage, scharryImage, CV_16S, 0, deltay);convertScaleAbs(scharrxImage, scharrxAbsImage);convertScaleAbs(scharryImage, scharryAbsImage);addWeighted(scharrxAbsImage, 0.5, scharryAbsImage, 0.5, 0.0, dstImage);imshow("scharrx image", scharrxAbsImage);imshow("scharry image", scharryAbsImage);imshow("scharrxy image", dstImage);
}
void onTrackBarScharrDeltay(int pos,void* userData)
{int deltax = g_deltaxValue+1;int deltay = g_deltayValue+1;Scharr(srcImage, scharrxImage, CV_16S, deltax, 0);Scharr(srcImage, scharryImage, CV_16S, 0, deltay);convertScaleAbs(scharrxImage, scharrxAbsImage);convertScaleAbs(scharryImage, scharryAbsImage);addWeighted(scharrxAbsImage, 0.5, scharryAbsImage, 0.5, 0.0, dstImage);imshow("scharrx image", scharrxAbsImage);imshow("scharry image", scharryAbsImage);imshow("scharrxy image", dstImage);
}

三.laplacian算子 (拉普拉斯算子)

         有时候我们需要在X和y方向上同时差分,然后看整体的结果,这就需要用到laplacian算子,该算子是N维欧几里德空间中的二阶微分算子.

         让一幅图的源图像减去其拉普拉斯算子的结果,图像的对比度将变得更强

         API:void laplacian(源图像,目标图像,目标深度,int 邻域孔径尺寸,int 可选的缩放比例因子,int deleta可选值,int 边界模式);

         注:图像深度和sobel一致,cv_8u对应cv_16s,ksize默认为1,且必须是正奇数.

         实际上,laplacian是图像在x方向上的sobel算子和y方向上的sobel算子的和,使用这种算子之前,最好先进行图像的滤波操作,防止引入微笑误差.

使用代码

// lapacian拉普拉斯算子
Mat srcImage,srcImageGassianBlur,srcImageGray,laplacianImage,laplacianAbs;
const int g_coreSizeMax = 5;
int g_coreSizeValue;
void onTrackBarCoreSize(int pos,void* userData);int main(int argc,char* argv[])
{srcImage = imread("F:\\opencv\\OpenCVImage\\laplacian.jpg");GaussianBlur(srcImage, srcImageGassianBlur, Size(3,3), 0);cvtColor(srcImageGassianBlur, srcImageGray, CV_RGB2GRAY);namedWindow("src image");namedWindow("dst image");g_coreSizeValue = 0;createTrackbar("core size", "dst image", &g_coreSizeValue, g_coreSizeMax,onTrackBarCoreSize,0);onTrackBarCoreSize(g_coreSizeValue, 0);imshow("src image", srcImage);moveWindow("src image", 0, 0);moveWindow("dst image", srcImage.cols, 0);waitKey(0);return 0;
}void onTrackBarCoreSize(int pos,void* userData)
{int coreSize = g_coreSizeValue*2 + 1;Laplacian(srcImageGray, laplacianImage, CV_16S,coreSize);convertScaleAbs(laplacianImage, laplacianAbs);imshow("dst image", laplacianAbs);
}

四.canny边缘检测

         边缘检测在工程上,有极大的应用,依靠边缘,确定物体的形状,检测产品的良好程度,canny算法,是opencv中提供的很不错的边缘检测算法,其检测边缘的步骤如下.

         首先是滤波,使用高斯平滑滤波卷积降噪.然后是计算梯度幅值与方向,类似于sobel ,laplacian,第三是非极大值一致,排除掉不是边缘的像素,最后是之后阈值化,使用两个阈值,并且绑定的时候考虑颜色之间的关联关系(高低阈值的比例在1:2或者1:3之间).

         API:void canny(输入图像,输出图像,double 低与阈值,double 高阈值,int sobel算子孔径,bool 计算梯度幅值标志);

         注:sobel算子孔径默认为3,计算梯度幅值的标记默认为false,低阈值用于控制图像边缘的连接,而高阈值用于控制边缘的初始点位置.

         另外,使用canny检测算法之前,最好先对图像经过一次降噪处理.

使用例程如下

//低̨ª阈D值¦Ì和¨ª高?阈D值¦Ì默?认¨?1:3
//sobel算?子Á¨®孔¡Á径?只?能¨¹取¨?值¦Ì 3 5 7
//平?滑?滤?波¡§算?子Á¨®孔¡Á径? 3,5,7,9
Mat srcImage,grayImage,grayBlurImage,cannyImage,dstImage;const int g_blurSizeMax = 3;//平?滑?滤?波¡§孔¡Á径?
int g_blurValue;
const int g_sobelSizeMax = 2;//sobel孔¡Á径?
int g_sobelValue;
const int g_lowThresholdMax = 80;//边À?缘¦Ì检¨¬测a低̨ª阈D值¦Ì
int g_lowThresholdValue;
int g_upThresholdValue;void onTrackBarBlurSize(int pos,void* userData);
void onTrackBarSobelSize(int pos,void* userData);
void onTrackBarLowThresholdSize(int pos,void* userData);int main(int argc,char* argv[])
{srcImage = imread("F:\\opencv\\OpenCVImage\\canny2.jpg");if(srcImage.channels() != 1){cvtColor(srcImage, grayImage, CV_BGR2GRAY);}else{grayImage = srcImage.clone();}namedWindow("src image");namedWindow("dst image");g_blurValue = 1;g_sobelValue = 1;g_lowThresholdValue = 3;g_upThresholdValue = 9;createTrackbar("blur size", "dst image", &g_blurValue, g_blurSizeMax,onTrackBarBlurSize,0);createTrackbar("sobel size", "dst image", &g_sobelValue, g_sobelSizeMax,onTrackBarSobelSize,0);createTrackbar("low threshold", "dst image", &g_lowThresholdValue, g_lowThresholdMax,onTrackBarLowThresholdSize,0);onTrackBarBlurSize(g_blurValue, 0);imshow("src image", srcImage);moveWindow("src image", 0, 0);moveWindow("dst image", srcImage.cols, 0);waitKey(0);return 0;
}void onTrackBarBlurSize(int pos,void* userData)
{int blurValue = g_blurValue*2 +3;int sobelValue = g_sobelValue*2 +3;if (g_lowThresholdValue == 0) {g_lowThresholdValue = 1;}int lowThresholdValue = g_lowThresholdValue;int upThresholdValue = lowThresholdValue*3;//平?滑?滤?波¡§
   blur(srcImage, grayBlurImage, Size(blurValue,blurValue));//计?算?canny
   Canny(grayBlurImage, cannyImage, lowThresholdValue, upThresholdValue,sobelValue);dstImage = Scalar::all(0);srcImage.copyTo(dstImage, cannyImage);imshow("dst image", dstImage);
}
void onTrackBarSobelSize(int pos,void* userData)
{int blurValue = g_blurValue*2 +3;int sobelValue = g_sobelValue*2 +3;if (g_lowThresholdValue == 0) {g_lowThresholdValue = 1;}int lowThresholdValue = g_lowThresholdValue;int upThresholdValue = lowThresholdValue*3;//平?滑?滤?波¡§
   blur(srcImage, grayBlurImage, Size(blurValue,blurValue));//计?算?canny
   Canny(grayBlurImage, cannyImage, lowThresholdValue, upThresholdValue,sobelValue);//用canny为掩码?,将src拷贝到dstimage中D,应为检测到的线条才会得到拷贝,所以,目标图上检测到的线条就会变成彩色条纹?dstImage = Scalar::all(0);srcImage.copyTo(dstImage, cannyImage);imshow("dst image", dstImage);
}void onTrackBarLowThresholdSize(int pos,void* userData)
{int blurValue = g_blurValue*2 +3;int sobelValue = g_sobelValue*2 +3;if (g_lowThresholdValue == 0) {g_lowThresholdValue = 1;}int lowThresholdValue = g_lowThresholdValue;int upThresholdValue = lowThresholdValue*3;//平?滑?滤?波¡§
   blur(srcImage, grayBlurImage, Size(blurValue,blurValue));//计?算?canny
   Canny(grayBlurImage, cannyImage, lowThresholdValue, upThresholdValue,sobelValue);dstImage = Scalar::all(0);srcImage.copyTo(dstImage, cannyImage);imshow("dst image", dstImage);
}

 

转载于:https://www.cnblogs.com/dengxiaojun/p/5252234.html

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

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

相关文章

postgresql select for update 多行加锁顺序_PostgreSQL和Mysql的MVCC实现机制的差异对比

任何数据库的主要要求之一就是实现可伸缩性。只有将争用(锁定)最小化(如果不能一起删除),才可以实现。由于读/写/更新/删除是数据库中发生的一些主要的频繁操作,因此对于这些操作并发进行而不被阻塞非常重要…

【C语言简单说】十六:do...while循环

** ㄟ(▔^▔ㄟ) (╯▔^▔)╯** 今天差点忘记更了。。。 今天我们来说我们的do…while循环,其实这个循环和我们的while循环很像,区别就在于我们现在要学的这个循环是先执行一次循环,再去判断条件是否正确。 为什么这么…

java数位倒置递归_有人能解释一下这个递归代码如何在java中反转int吗?

r根本不用10*rn%10实际上,这是一件很棘手的事情,而且很酷。这是一个很好的例子,说明变量命名不当会使代码难以理解。我们有3行代码可以实际执行某些操作,但它的工作原理并不明显。private static int NOTHING_REVERSED_SO_FAR 0;private static int reverse(int numberToBeRev…

WireShark抓DNS请求和回复数据报的分析

1 DNS简单理解 我们简单理解DNS功能是把域名转成IP地址,我们先发送一个NDS请求数据包到本地域名服务器去找,找不到我们就去根域名服务器去找,根域名找不到我们再把顶级域名服务器地址回复给本地域名服务器,然后本地域名服务器到顶级域名服务器去查询,如果依然找不到,同理…

C#趣味程序---车牌号判断

甲说前两位相同&#xff0c;乙说后两位相同&#xff0c;丙说四位的车牌号刚好是一个数的平方&#xff0c;这个车牌号是多少&#xff1f; using System;namespace ConsoleApplication1 {class Program{static void Main(string[] args){int k, c;for (int i 1; i < 10; i)fo…

12款白帽子用于黑客渗透测试的操作系统

想知道什么样的操作系统的是白帽子黑客的最爱吗?本文我们将推荐12个操作系统&#xff0c;包括一些Linux发行版&#xff0c;如Kali Linux&#xff0c;Parrot安全操作系统&#xff0c;BlackArch等。这些以安全为重点的操作系统&#xff0c;可以帮助白帽子黑客进行渗透测试&#…

jqurey操作radio总结

2019独角兽企业重金招聘Python工程师标准>>> 在我们前端的项目中&#xff0c;会经常用到radio单选按钮&#xff0c;下面给出个例子总结jquery对radio的各种操作&#xff1a; 示例如下&#xff1a; <html> <head><meta charset"UTF-8">&…

android中文离线api_比林肯法球Linken sphere浏览器更多更新指纹的国产防关联软件-VMLogin中文版浏览器...

林肯法球&#xff08;Linken Sphere&#xff09;是俄罗斯人开发的一个功能强大的浏览器&#xff0c;该工具最早出现在2017年7月&#xff0c;此外还具有“离线记录模式”功能&#xff0c;能够简化会话之间导入和导出cookie的过程。使用Linken Sphere工具开启浏览器会话时&#x…

【C语言简单说】十七:数组

** ( ิ∀ิ ) 还有两个小节就基本上简单的过了一遍C语言了&#xff0c;现在我们来讲诉什么是数组。** 字面意思&#xff1a;数组&#xff0c;数组的一个组&#xff1f;应该说一堆数值的一个集合&#xff1f;我不知道大家的年龄段在于什么阶段&#xff0c;如果学过集合的话&am…

剑指offer之用链表实现栈(带头节点)

1 问题 用链表实现栈,栈先进后出. 2 代码实现 #include <stdio.h> #include <stdlib.h>#define true 1 #define false 0typedef struct Node {int value;struct Node *next; } Stack;/**打印栈*/ void print(Stack *stack) {if (stack NULL){printf("stack…

java arraylist枚举器遍历_Java基础(七)泛型数组列表ArrayList与枚举类Enum

一、泛型数组列表ArrayList1.在Java中&#xff0c;ArrayList类可以解决运行时动态更改数组的问题。ArrayList使用起来有点像数组&#xff0c;但是在添加或删除元素时&#xff0c;具有自动调节数组容量的功能&#xff0c;而不需要为此编写任何代码。对数组列表实施插入和删除操作…

Blazor University (12)组件 — 组件生命周期

原文链接&#xff1a;https://blazor-university.com/components/component-lifecycles/组件生命周期源代码[1]Blazor 组件具有许多我们可以重写以影响应用程序行为的虚拟方法。这些方法在组件生命周期的不同时间执行。下图概述了这些生命周期方法的流程。组件生命周期图SetPar…

datatable.select()的一个问题

今天用tbCategory.select("ID"id)时发现报错&#xff1a;在 Range 对象中&#xff0c;Min (3)必须小于或等于 max (-1) 后来百度发现参数要用单引号括起来&#xff1a;tbCategory.select("ID"id"")&#xff0c;但是ID的类型是int型的&#xff0c…

C#趣味程序---个位数为6,且能被3整出的五位数

using System;namespace ConsoleApplication1 {class Program{static void Main(string[] args){int count 0;int k;for (int i 1000; i < 9999; i){k i * 10 6;if (k % 3 0){Console.WriteLine(k);count;}}Console.WriteLine(count); }} }

如何通过css控制内容显示顺序 第二行的内容优先显示

我们有时进行网页设计时为了想让用户感兴趣的内容优先显示在前&#xff0c;又不想改动代码的先后顺序&#xff0c;要怎么操作呢&#xff1f;&#xff08;或者换种说法&#xff1a;源代码中要先看到A再看到B&#xff0c;而视觉上是先B再A&#xff09;举个简单的例子&#xff0c;…

【C语言简单说】十七:数组(补)

上一节 我们所说的数组是整数类型的对吧&#xff1f;那么我们还有其他类型 的数组&#xff0c;在这里用字符数组举例。 如下代码&#xff1a; #include<stdio.h> #include<stdlib.h> int main() {char a[5]{a,b,c,d,e};int i;for(i0;i<5;i){printf("a[%d…

精简 opencv python_基于Python的OpenCV人脸检测!简直不要太简单!

一、文章概述注意&#xff1a;本文只是人脸检测&#xff0c;人脸识别的实现请参见本人另一篇博客&#xff1a;基于OpenCVTensorFlowKeras实现人脸识别本文将要讲述的是Python环境下如何用OpenCV检测人脸&#xff0c;本文的主要内容分为&#xff1a;1、检测图片中的人脸2、实时检…

WireShark之抓包过滤链接部分

1 问题 我们打开WireShark&#xff0c;开始抓包&#xff0c;然后浏览器输入http链接地址&#xff0c;那我们怎么快速在WireShark里面找到 2 解决办法 1&#xff09;在WireShark里面输入http 2 ) Ctrl F,然后选择字符串&#xff0c;然后在字符串的右边输入 我们要过滤的部分…

最通俗易懂的依赖注入之生命周期

这篇文章是 ASP.NET 6 依赖注入系列文章的第二篇&#xff0c;点击上方蓝字可以阅读整个系列。在上一篇文章中&#xff0c;我们讨论了什么是依赖注入和控制反转&#xff0c;以及它的作用是什么。在这篇文章中&#xff0c;我们先演示一下依赖注入的基本用法&#xff0c; 然后再讨…

Cnblogs自定义皮肤css样式-星空观测者

不知不觉来Cnblogs也这么久了&#xff0c;然而Blogs提供的主题还是依旧那么复古&#xff0c;总觉得阅读起来难免枯燥&#xff0c;虽然我认为做技术不可以太过浮躁&#xff0c;但是一个美观的主题终究是吸引人眼的第一要素。 毕竟这么久了&#xff0c;在博客园还没有发现一个比较…