我的个人博客:谋仁·Blog
微信公众号:谋仁的麻袋
文章目录
- 一些概念
- 颜色空间
- 图像的深度
- 图像通道
- 颜色空间的转换-cvtColor
- 函数cvtColor
- 示例(BGR转换成灰度图)
- 高斯滤波-GaussianBlur
- 函数GaussianBlur
- 示例
- 图像边缘检测-Canny
- 函数Canny
- 示例
- 图像的膨胀和侵蚀-dilate和erode
- 函数dilate/erode
- 补充:函数getStructuringElement
- 示例
为了表示一种特定的颜色,我们通常建立一维、二维、三维甚至四维空间坐标来表示,这种坐标系统所能定义的色彩范围即颜色空间。下面列举常见的颜色空间:
-
RGB模型
RGB模型将颜色编码成(R,G,B)即(Red红,Green绿,Blue蓝)。每个分量范围是[0,255]共256级。因此,RGB模型可以表示256×256×256≈1670万种颜色。
注意:在OpenCV中存储顺序不是RGB,而是BGR。 -
单通道模型
单通道图即灰度图,图片像素颜色由一维的值来表示,分量范围是[0,255]。0是黑色,255是白色,中间是不同程度的灰色。 -
二值模型
二值图像即黑白图像,每个像素的颜色由一维的值来表示,分量范围是[0,1],0代表黑色,1代表白色。 -
HSV模型
HSV模型由三个参数来表示颜色:色调(H)、饱和度(S)、明度(V)。
色调(H)用角度表示,范围[0°,360°],红色为0°,从红色开始按逆时针方向计算。(如下图)
饱和度(S)表示颜色接近光谱色的程度,饱和度越高,颜色越深而艳。取值范围[0%,100%]。
明度(V)表示颜色鲜亮的程度,取值范围[0%,100%],0%为黑色,100%为白色。
-
Lab模型
Lab颜色空间中的L分量用于表示像素的亮度,取值范围是[0,100],表示从纯黑到纯白;a表示从红色到绿色的范围,取值范围是[127,-128];b表示从黄色到蓝色的范围,取值范围是[127,-128]。图示如下:
图像用于存储像素的值占得比特(bit)位数(就是转换为二进制的位数),就是图像的深度。例如:在二值模型中每个像素点的值是一维的,且取值范围是[0,1],所以仅用一位比特位就可以满足,图像深度为1;RGB模型中每个像素用R,G,B三个分量表示,每个分量取值范围[0,255],用8位可以表示,所以像素深度总共为24位。
图像通道为了储存像素数据,每一个像素点用一个或多个分量来存储数据,分量的数量就是图像通道。例如,RGB模式中每个像素点由Red、Dreen、Blue三个分量来表示,每个取值范围都是[0,255],这个图像通道就是3。灰度图仅用一个取值范围为[0,255]数值来表示,灰度图的图像通道就是1。
颜色空间的转换-cvtColor 函数cvtColorcv::cvtColor()作用是将图像从一个颜色空间转换到另一个颜色空间。并且在转换的过程中能够保证数据的类型不变,即转换后的图像的数据类型和位深与源图像一致。
函数定义:
void cv::cvtColor(
cv::InputArray src, // 输入图像
cv::OutputArray dst, // 输出图像
int code, // 模式转换的映射码
int dstCn = 0 // 输出的通道数 (0='automatic')
);
- src: Mat类,输入待转换的图像
- dst:Mat类,转换后新图像放在这里
- code:转换的代码或标识,即图像转换的格式(模式1→模式2)
OpenCV提供的映射:
- dstCn:(默认是0)目标图像通道数,如果取值为0,则由src和code决定
源代码:
#include#include using namespace cv; #ifdef _DEBUG #pragma comment(lib,"opencv_world453d.lib") #else #pragma comment(lib,"opencv_world453.lib") #endif // _DEBUG int main() { Mat img = imread("D:\My Bags\图片\Test.jpg"); Mat imgGray; cvtColor(img, imgGray, COLOR_BGR2GRAY); imshow("原图", img); imshow("灰度图", imgGray); waitKey(0); return 0; }
运行结果:
函数的定义:
void GaussianBlur( InputArray src, //输入的图像
OutputArray dst, //接收输出的图像
Size ksize,//高斯内核大小
double sigmaX,
double sigmaY = 0,
int borderType = BORDER_DEFAULT);
- src:Mat类,输入待处理的图像
- dst:Mat类,输出与原图大小和类型相同的图像
- ksize:高斯内核的大小,决定了滤波的程度。其中ksize.width和ksize.height可以不同,但他们都必须为正数和奇数。或者,它们可以是零的,它们都是由sigma计算而来
- sigmaX:高斯核函数在X方向上的标准偏差
- sigmaY:高斯核函数在Y方向上的标准偏差,如果sigmaY是0,则函数会自动将sigmaY的值设置为与sigmaX相同的值,如果sigmaX和sigmaY都是0,这两个值将由ksize.width和ksize.height计算而来
- borderType:推断图像外部像素的某种便捷模式,有默认值BORDER_DEFAULT,如果没有特殊需要不用更改
源代码:
#include#include using namespace cv; #ifdef _DEBUG #pragma comment(lib,"opencv_world453d.lib") #else #pragma comment(lib,"opencv_world453.lib") #endif // _DEBUG int main() { Mat img = imread("D:\My Bags\图片\Test.jpg"); Mat imgGaus; GaussianBlur(img, imgGaus, Size(7, 7), 7); imshow("原图", img); imshow("高斯滤波图", imgGaus); waitKey(0); return 0; }
运行结果:
函数定义
重载1:
void Canny( InputArray image,//输入图像
OutputArray edges,//输出图像
double threshold1, //阈值1
double threshold2,//阈值2
int apertureSize = 3, //Sober算子大小
bool L2gradient = false //是否采用更精确的方式计算图像梯度
);
两个阈值参数:
- 低于阈值1的像素点会被认为不是边缘;
- 高于阈值2的像素点会被认为是边缘;
- 在阈值1和阈值2之间的像素点,若与第2步得到的边缘像素点相邻,则被认为是边缘,否则被认为不是边缘
- 建议上限是下限的2或3倍
apertureSize参数:
- 为Sobel()运算提供内核大小,默认值为3
重载2:
void Canny( InputArray dx,
InputArray dy,
OutputArray edges,//输出图像
double threshold1, //下阈值
double threshold2,//上阈值
bool L2gradient = false
);
- InputArray dx:输入图像在x方向的导数
- InputArray dy:输入图像在y方向的导数
源代码
#include#include using namespace cv; #ifdef _DEBUG #pragma comment(lib,"opencv_world453d.lib") #else #pragma comment(lib,"opencv_world453.lib") #endif // _DEBUG int main() { Mat img = imread("D:\My Bags\图片\Test.jpg"); Mat imgGaus,imgEdge; GaussianBlur(img, imgGaus, Size(3, 3), 3);//高斯滤波降噪 Canny(imgGaus, imgEdge, 100, 300);//边缘检测 imshow("原图", img); imshow("边缘图", imgEdge); waitKey(0); return 0; }
运行结果:
dilate函数的定义
void dilate( InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor = Point(-1,-1),
int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue()
);
erode函数的定义
void erode( InputArray src,
OutputArray dst,
InputArray kernel,
Point anchor = Point(-1,-1),
int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue()
);
两个函数参数完全一样,参数解释:
- src:Mat类,输入的原图
- dst:Mat类,用于存放处理后的图像
- kernel:用于膨胀/侵蚀操作的结构元素,当为NULL时,那么默认使用一个3 x 3 的方形结构元素,可以使用getStructuringElement()(下文有详细介绍)来创建结构元素
- anchor:结构元素的锚点位置,默认值value(-1,-1)表示锚点位于结构元素中心
- iterations:进行膨胀/侵蚀操作迭代执行的次数,默认是1
- borderType:用于推断图像外部像素的某种推断模式。默认值BORDER_CONSTANT
- Scalar& borderValue:边缘值,默认值morphologyDefaultBorderValue()。一般不用改动
函数的定义:
Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1) );
作用:返回(Mat类型)指定形状和尺寸的结构元素
参数解释:
- shape:结构元素的形状
矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
椭圆形:MORPH_ELLIPSE; - ksize:结构元素的尺寸,同GaussianBlur函数的ksize
- anchor:锚点的位置,默认值Point(-1,-1),表示锚点位于中心点
源代码:
#include#include using namespace cv; #ifdef _DEBUG #pragma comment(lib,"opencv_world453d.lib") #else #pragma comment(lib,"opencv_world453.lib") #endif // _DEBUG int main() { Mat imgDilate, imgErode; Mat img = imread("D:\My Bags\图片\Test.jpg"); Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));//新建一个结构元素 dilate(img, imgDilate, kernel);//膨胀操作 erode(img, imgErode, kernel);//侵蚀操作 imshow("原图", img); imshow("膨胀图", imgDilate); imshow("侵蚀图", imgErode); waitKey(0); return 0; }
运行结果:



