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);
}
时间: 2024-08-05 15:21:02

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

OpenCV —— 图像变换

将一副图像转变成另一种表现形式 ,比如,傅里叶变换将图像转换成频谱分量   卷积 -- 变换的基础 cvFilter2D  源图像 src 和目标图像 dst 大小应该相同 注意:卷积核的系数应该是浮点类型的,必须用 CV_32F 来初始化矩阵 cvFilter2D 函数内部处理边界 -- cvCopyMakeBorder (将特定的图像轻微变大,然后以一种方式填充图像边界)   梯度和Sobel导数 sobel 算子包含任意阶的微分以及融合偏导   大核对导数有更好的逼近,小核对噪声更加敏感

opencv 图像变换原理详解 图像平移 图像旋转 图像缩放

常见的2D图像变换从原理上讲主要包括基于2×3矩阵的仿射变换和基于3×3矩阵透视变换. 仿射变换 原理 基本的图像变换就是二维坐标的变换:从一种二维坐标(x,y)到另一种二维坐标(u,v)的线性变换: 如果写成矩阵的形式,就是: 作如下定义: 矩阵T(2×3)就称为仿射变换的变换矩阵,R为线性变换矩阵,t为平移矩阵,简单来说,仿射变换就是线性变换+平移.变换后直线依然是直线,平行线依然是平行线,直线间的相对位置关系不变,因此非共线的三个对应点便可确定唯一的一个仿射变换,线性变换4个自由度+平移2

OPENCV图像变换-2

一.经典霍夫变换 霍夫变换是图像处理中的一种特征提取技术,该方法通过在一个参数空间中通过计算累计结果的局部最大值来得到一个符合该特定形状的集合,作为结果. 运用两个坐标空间之间的变换,将一个空间中具有相同形状的曲线或者是直线映射到另一个坐标空间中的一个点形成峰值,从而将统计任意性状化为统计峰值问题. opencv中,霍夫线变换市一中寻找直线的方法,在使用霍夫线变换之前,要先对图像进行边缘检测的处理,霍夫变换的直接输入为阈值化之后的二值图像 opencv至此三种不同的霍夫线变换,标准霍夫变换(SH

Opencv 中透视变换函数对IplImage图像变换时出现的问题?

最近一直在做视频稳像的项目,为了简化部分实现,使用了部分Opencv的函数,其中包括Opencv中对IplImage进行同时变换的函数cvWarpPerspective(src, dst,...) 发现的问题是,不管后面设置什么参数出现的结果有时候会出现差异.比如,正常的输出时在变换后没有图像区域像素为黑色(0),但是偶尔会出现异常,没有图像的区域像素是灰色(大约是125),像素值范围是0~256.暂时不知道为什么?还是其他地方没有正确初始化?(未完待续)

【OpenCV学习笔记 008】基于形态学运算的图像变换

一.形态学滤波对图像进行腐蚀.膨胀运算 1.概念及原理 (1)腐蚀和膨胀是形态学中最基本的运算,而结构元素又是数学形态学中最基本的工具.结构元素可以简单理解为像素的结构以及一个原点.使用形态学滤波就是对像素的每个元素应用这个结构,当结构元素的原点和像素对齐时,它与图像的相交部分定义了一组进行形态学运算的像素.结构元素可以是任何形状,我们一般使用简单的方形.圆形.或菱形,原点即位于中心位置. (2)腐蚀替换当前像素位像素集合中找到的最小像素值,膨胀则相反.为了想象出两个运算的效果,可以考虑背景(黑

opencv中的子库

1 FLANN 近似最近邻库,NN就是nearest neighbor的缩写. 2 IlmImf Ilm是Industrial light & magic公司的缩写. Imf是image format的缩写吗? 3 libjasper Jasper是JPEG2000的一个非官方实现,由一个国外的一个大学教师实现,还算是个好用的LIB,你可以从http://www.ece.uvic.ca/~mdadams/jasper/地址下在,里面有VC的工程文件.Jpeg60是JPEG的官方实现:其编译只提供

OpenCV人脸检测

由于光照.遮挡和倾斜等原因,部分人脸和眼睛并不能正确检测.. // 简单的人脸检测 #include <iostream> #include <vector> #include <opencv2\opencv.hpp> #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/im

OpenCV 2.4.9 学习笔记(1)—— 基本功能结构

一些关于OpenCV(2.4.9版本)的学习笔记,作为记录,以免自己忘了. 安装与配置 OpenCV的下载.安装以及在各个平台(Windows/Linux等)配置网上有很多的资料,自己就不用存了.需要或者遇到问题的时候再说. 基本模块结构 OpenCV(Open Source Computer Vision Library),一个遵循BSD协议的计算机视觉技术开源库,包含了几百个计算机视觉算法.目前最新版本应该是OpenCV3.0,alpha版和beta版都有了,我目前是用的2.4.9,3.0版

【OpenCV学堂】图像处理开发者基本知识图谱

原创图像处理与机器学习文章,关注微信公众号[OpenCV学堂] 作为一个入门的图像处理开发者与工程师,要掌握的知识点也不少,不要看每个知识点只有几个字,可以说每个都代表一个算法,都有数学知识,都需要你认真领悟学习!不认真的学习一年两年你不可能做到下面的全部领悟与贯通,成为一个合格的图像处理与机器学习开发者,一个人工智能时代的程序员! 图像像素操作 - 几何运算-加减乘除 - 逻辑运算-与或非取反 - 像素读写 - 通道混合与调整 - 对比度与亮度调整 图像变换 - 插值(zoom in或out)