图像变换是指将一幅图像变换为图像数据的另一种表现形式,例如将图像进行傅立叶变换,或者对图像进行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 = ;
int g_deltaxValue;
const int g_deltayMax = ;
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 = ;
g_deltayValue = ;
createTrackbar("deltax value", "src image", &g_deltaxValue, g_deltaxMax,onTrackBarScharrDeltax,);
createTrackbar("deltay value", "src image", &g_deltayValue, g_deltayMax,onTrackBarScharrDeltay,);
onTrackBarScharrDeltax(g_deltaxValue,); imshow("src image", srcImage);
moveWindow("src image", , );
moveWindow("scharrx image", srcImage.cols, );
moveWindow("scharry image", , srcImage.rows);
moveWindow("scharrxy image", srcImage.cols, srcImage.rows); waitKey();
return ;
} void onTrackBarScharrDeltax(int pos,void* userData)
{
int deltax = g_deltaxValue+;
int deltay = g_deltayValue+;
Scharr(srcImage, scharrxImage, CV_16S, deltax, );
Scharr(srcImage, scharryImage, CV_16S, , 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+;
int deltay = g_deltayValue+;
Scharr(srcImage, scharrxImage, CV_16S, deltax, );
Scharr(srcImage, scharryImage, CV_16S, , 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 = ;
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(,), );
cvtColor(srcImageGassianBlur, srcImageGray, CV_RGB2GRAY); namedWindow("src image");
namedWindow("dst image"); g_coreSizeValue = ;
createTrackbar("core size", "dst image", &g_coreSizeValue, g_coreSizeMax,onTrackBarCoreSize,);
onTrackBarCoreSize(g_coreSizeValue, ); imshow("src image", srcImage); moveWindow("src image", , );
moveWindow("dst image", srcImage.cols, ); waitKey();
return ;
} void onTrackBarCoreSize(int pos,void* userData)
{
int coreSize = g_coreSizeValue* + ;
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 = ;//平?滑?滤?波¡§孔¡Á径?
int g_blurValue;
const int g_sobelSizeMax = ;//sobel孔¡Á径?
int g_sobelValue;
const int g_lowThresholdMax = ;//边À?缘¦Ì检¨¬测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() != )
{
cvtColor(srcImage, grayImage, CV_BGR2GRAY);
}
else
{
grayImage = srcImage.clone();
}
namedWindow("src image");
namedWindow("dst image");
g_blurValue = ;
g_sobelValue = ;
g_lowThresholdValue = ;
g_upThresholdValue = ;
createTrackbar("blur size", "dst image", &g_blurValue, g_blurSizeMax,onTrackBarBlurSize,);
createTrackbar("sobel size", "dst image", &g_sobelValue, g_sobelSizeMax,onTrackBarSobelSize,);
createTrackbar("low threshold", "dst image", &g_lowThresholdValue, g_lowThresholdMax,onTrackBarLowThresholdSize,);
onTrackBarBlurSize(g_blurValue, ); imshow("src image", srcImage); moveWindow("src image", , );
moveWindow("dst image", srcImage.cols, ); waitKey();
return ;
} void onTrackBarBlurSize(int pos,void* userData)
{
int blurValue = g_blurValue* +;
int sobelValue = g_sobelValue* +;
if (g_lowThresholdValue == ) {
g_lowThresholdValue = ;
}
int lowThresholdValue = g_lowThresholdValue;
int upThresholdValue = lowThresholdValue*; //平?滑?滤?波¡§
blur(srcImage, grayBlurImage, Size(blurValue,blurValue));
//计?算?canny
Canny(grayBlurImage, cannyImage, lowThresholdValue, upThresholdValue,sobelValue);
dstImage = Scalar::all();
srcImage.copyTo(dstImage, cannyImage);
imshow("dst image", dstImage);
}
void onTrackBarSobelSize(int pos,void* userData)
{
int blurValue = g_blurValue* +;
int sobelValue = g_sobelValue* +;
if (g_lowThresholdValue == ) {
g_lowThresholdValue = ;
}
int lowThresholdValue = g_lowThresholdValue;
int upThresholdValue = lowThresholdValue*; //平?滑?滤?波¡§
blur(srcImage, grayBlurImage, Size(blurValue,blurValue));
//计?算?canny
Canny(grayBlurImage, cannyImage, lowThresholdValue, upThresholdValue,sobelValue); //用canny为掩码?,将src拷贝到dstimage中D,应为检测到的线条才会得到拷贝,所以,目标图上检测到的线条就会变成彩色条纹?
dstImage = Scalar::all();
srcImage.copyTo(dstImage, cannyImage);
imshow("dst image", dstImage);
} void onTrackBarLowThresholdSize(int pos,void* userData)
{
int blurValue = g_blurValue* +;
int sobelValue = g_sobelValue* +;
if (g_lowThresholdValue == ) {
g_lowThresholdValue = ;
}
int lowThresholdValue = g_lowThresholdValue;
int upThresholdValue = lowThresholdValue*; //平?滑?滤?波¡§
blur(srcImage, grayBlurImage, Size(blurValue,blurValue));
//计?算?canny
Canny(grayBlurImage, cannyImage, lowThresholdValue, upThresholdValue,sobelValue);
dstImage = Scalar::all();
srcImage.copyTo(dstImage, cannyImage);
imshow("dst image", dstImage);
}

OPENCV图像变换-1的更多相关文章

  1. OpenCV图像变换(仿射变换与透视变换)

    仿射变换(affine transform)与透视变换(perspective transform)在图像还原.图像局部变化处理方面有重要意义.通常,在2D平面中,仿射变换的应用较多,而在3D平面中, ...

  2. OPENCV图像变换-2

    一.经典霍夫变换 霍夫变换是图像处理中的一种特征提取技术,该方法通过在一个参数空间中通过计算累计结果的局部最大值来得到一个符合该特定形状的集合,作为结果. 运用两个坐标空间之间的变换,将一个空间中具有 ...

  3. OpenCV —— 图像变换

    将一副图像转变成另一种表现形式 ,比如,傅里叶变换将图像转换成频谱分量 卷积 —— 变换的基础 cvFilter2D  源图像 src 和目标图像 dst 大小应该相同 注意:卷积核的系数应该是浮点类 ...

  4. python+opencv图像变换的两种方法cv2.warpAffine和cv2.warpPerspective

    本文链接:https://blog.csdn.net/qq_27261889/article/details/80720359 # usr/bin/env python # coding: utf- ...

  5. OpenCV图像变换二 投影变换与极坐标变换实现圆形图像修正

    投影变换 在放射变换中,物体是在二维空间中变换的.如果物体在三维空间中发生了旋转,那么这种变换就成为投影变换,在投影变换中就会出现阴影或者遮挡,我们可以运用二维投影对三维投影变换进行模块化,来处理阴影 ...

  6. <学习opencv>图像变换

    拉伸.收缩.扭曲和旋转 统一调整大小 我们经常会遇到一些我们希望转换为其他尺寸的图像. 我们可能想要扩大或缩小图像; 这两项任务都是由同一个功能完成的. cv::resize() 该cv::resiz ...

  7. [opencv]<学习Opencv>英文原版翻译学习

    [注]下文全部内容为 <<Learning OpenCV 3: Computer Vision in C++ with the OpenCV Library>>经由在线翻译整理 ...

  8. pyhton:图像旋转

    最近一个作业中要用到图像旋转,分享一下学习过程.如有讲错的地方,恳请指正! 图像旋转,想想真简单啊,不就是将图像矩阵乘上一个旋转平移矩阵就完了吗?实际上还真没这么简单.首先这个旋转平移矩阵怎么获得?通 ...

  9. OpenCV-Python Tutorials目录

    版本 3.4.6 1 Introduction to OpenCV OpenCV介绍Learn how to setup OpenCV-Python on your computer! 2 Gui F ...

随机推荐

  1. 关于jQuery的条件判断问题

    遇到的第一个问题,点击第一行用toggle实现背景的变换,需要在toggle函数里面判断,当下面显示的时候是一个状态,下面不显示的时候是另一个状态,我用了 if($(".check-box& ...

  2. 使用jquery的js的页面实现例子

    var validate;var nodeId="";var modifyappId=""; addExportTaskURL = ctx + "/x ...

  3. [转]解决LinearLayout中控件不能居右对齐

    在LinearLayout布局时使用右对齐(android:layout_gravity="right")控件对齐方式不生效,需要设置 android:layout_weight= ...

  4. SuperSocket+unity 网络笔记

    学习SuperSocket 必须要注意的 代码是 static void Main(string[] args) { WebSocketServer appServer = new WebSocket ...

  5. ajax2016/4/15 post与get

    post方式,数据放在send()里面作为参数传递 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); ...

  6. CodeForces 682C Alyona and the Tree(广搜 + 技巧)

    方法:从根节点开始广搜,如果遇到了应该删除的点,就再广搜删掉它的子树并标记,然后统计一下被标记的个数就是答案,所谓技巧就是从根节点开始搜索的时候,如果遇到了某个节点的距离<0,就让它是0,0可以 ...

  7. Android Studio ADB响应失败解决方法(2CTo.com)

    当启动Android Studio时,如果弹出 adb not responding. you can wait more,or kill "adb.exe" process ma ...

  8. cookies和session的优缺点

    具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案. Cookie的优缺点: 优点:极高的扩展性和可用性通过良好的编程,控制保存在cookie ...

  9. Ubuntu Linux 环境变量

    2011年09月17日 Ubuntu 下设置adb环境变量 分类: 同Windows一样,Ubuntu Linux系统包含两类环境变量:系统环境变量和用户环境变量.系统环境变量对所有系统用户都有效,用 ...

  10. Socket在手机上的应用

    usb读取:pid vid --可以唯一的确定设备获取手机驱动socket固定端口通信 wifipc机在局域网内,udp的数据包(整个网段) 蓝牙配对 bluetoothsocket 如果放大:可以分 ...