C++ OpenCV学习笔记

1、图像的加载、修改与保存

涉及API:
cv::imread(); //读取
cv::imshow(); //显示
cv::cvtColor(); //修改
cv::imwrite(); //保存

扩展图像窗口创建API:cv::namedWindow();
cv::namedWindow需要两个参数,第一个参数是窗口名称,第二个参数是关于窗口操作的关键字(包含:WINDOW_AUTOSIZE会根据图像大小自动设置窗口大小并且生成的窗口大小不能修改;WINDOW_NORMAL此关键字一般使用在跟QT集成以后的程序中,表示允许修改窗口大小)

cv::imread:
参数两个,第一个参数是图像存储的绝对路径,第二个参数读取图像类型(包含:IMREAD_UNCANGED表示加载原图;IMREAD_GRAYSCALE表示将图像作为灰度图像加载进来;IMREAD_COLOR表示原图作为RGB图像加载进来)

cv::imshow:
两个参数,第一个参数是图像窗口名称(可以自动创建),第二个参数是Mat对象名

cv::cvtColor:
三个参数,第一个是需更改的Mat对象名,第二个是用于保存更改后的Mat对象名,第三个参数是修改使用的源和目标色彩空间(如:COLOR_BGR2GRAY表示修改成灰度图像)

cv::imwrite:
使用时包含两个参数,第一个参数是保存图像的绝对路径,第二个参数是需要保存的Mat对象名


2、矩阵的掩膜操作

获取图像像素指针:
CV_Assert(image.depth()==CV_8U)
Mat.ptr(int i = 0)获取像素矩阵的指针,其中索引 i 表示第几行,从0开始计行数
获取当前行指针语句:const uchar* current = image.ptr<uchar>(row);
获取当前像素点P(row,col)的像素值语句:p(row,col) = current[col];

像素范围处理saturate_cast<uchar>(重要函数)

saturate_cast<uchar)(-100),返回0
saturate_cast<uchar)(299),返回255
saturate_cast<uchar>(100),返回100

说明:此函数的功能是确保RGB值的范围在0~255之间

什么是图像掩膜操作,掩膜操作实现的是图像对比度调整

opencv提供的掩膜操作(对比度提高)API:filter2D
定义掩膜矩阵:

Mat kernel = (Mat_<char>(3,3)<< 0,-1,0,-1,5,-1,0,-1,0);

API调用举例:filter2D(img, dst, img.depth(), kernel);
说明:第一个参数是操作对象名,第二个参数保存操作后对象名,第三个参数图像深度(使用depth()函数获取了原图像深度),第三个参数是掩膜方法(对应掩膜矩阵)

如何初始化一个零时Mat对象用于存储原图像?
代码:Mat dst = Mat::zeros(img.size(), img.type()); //zeros方法代表创建RGB为0的纯黑图像,大小和类型与原图像相同

拓展:执行时间的显示
代码:

double t = getTickCount();

/* 代码部分 */
double time = (getTickCount() - t)/getTickFrequency();
// cout << "执行时间: " << time << endl;

3、Mat对象(一种Iplimage更加安全的存储对象,Mat对象的内存空间被自动分配)

Mat对象构造函数:
Mat()
Mat(int rows, int cols, int type)
Mat(Size size, int type)

Mat(int rows, int cols, int type, const Scaler &s) // 说明:前两个参数分别表示行和列,第三个参数是类型参数(比如CV_8UC3中8表示每个通道占8位,U表示无符号,C表示Char类型,3表示三个通道数),第四个参数是向量表示初始化每个像素值为多少,向量长度对应通道数目一致。

Mat(Size size, int type, const Scaler &s) //Scaler()用来给像素赋值
Mat(int ndims, const int *sizes, int type)
Mat(int ndims, const int *sizes, int type, const Scaler &s)

说明:拷贝构造函数只会赋值对象头部,使用API–>demo = mat.clone() or mat.copyTo(demo) 才能进行完全复制(包括数据部分)

常用方法:
void copyTo(Mat mat);
void convertTo(Mat dst, int type);
Mat clone();
int channels();
int depth();
bool empty();
uchar* ptr(i = 0); //备注:查资料详学(读取像素值)

cv::Mat::create(size, type) //create方法创建对象(可指定对象尺寸大小)
两种用法:

M.create(img.size(), img.type()); 
M.create(4,3,CV_8UC2);	M = Scaler(123,123);

定义小数组:(掩膜运用)
Mat kernel = (Mat_<char>(3,3)<< 0,-1,0,-1,5,-1,0,-1,0);

初始化全0图像有多种方法,其中比较特殊的是Mat::zero(size, type);
用法:

Mat m = Mat::zero(img.size(), img.type());
Mat m = Mat::zero(2, 2, CV_8UC1);

拓展:Mat::eye(……)方法,初始化对角线为一的图像矩阵。


4、图像操作

读取像素:
· 读取一个gray像素点的像素值(CV_8UC1)
Scalar intensity = img.at<uchar>(row, col); or Scalar intensity = img.at<uchar>(Point(row, col));

· 读取一个RGB像素点的像素值

Vec3f intensity = img.at<Vec3f>(row, col);
float blue = intensity.val[0];
float green = intensity.val[1];
float red = intensity.val[2];

for(int row = o; row < img.rows; row++)
{
	for(int col = 0; col < img.cols; col++)
	{
		int b = img.at<Vec3b>(row, col)[0];
		int g = img.at<Vec3b>(row, col)[1];
		int r = img.at<Vec3b>(row, col)[2];
	}
}

说明:Vec3b是一种数据结构,放置BGR像素点,3b表示3bit读取,也可以用Vec3f,3f表示以float类型读取,如第一种读取方法。

修改像素:
· 灰度图像
img.at<uchar>(row, col) = 123;

· RGB图像
img.at<Vec3b>(row, col)[0] = 123; //修改参数B
img.at<Vec3b>(row, col)[1] = 123; //修改参数G
img.at<Vec3b>(row, col)[2] = 123; //修改参数R

· 空白图
img = Scalar(100); //将每个像素点赋值为100

· ROI选择
Rect r(10, 10, 100, 100);
Mat smallimg = img(r);

Vec3b与Vec3f
· Vec3b对应三通道顺序blue、green、red的uchar类型数据
· Vec3f对应三通道float类型数据
· 把CV_8UC1转换到CV32F1实现如下:
img.convertTo(dst, CV_32F1); //使用API-->convertTo(dst, type);


5、图像混合

· 理论-线性混合操作
g(x) = (1-a)f0(x)+af1(x)
说明:f0(x)表示一个图像,f1(x)表示另一个图像,其中a的取值范围为0~1之间,g(x)表示混合后得到的图像(注意:对图像每个像素的操作)

相关API

cv::addWeighted(inputArray 	 src1, 		//参数1:输入图像Mat - src1
	            double 		alpha, 		//参数2:输入图像src1的alpha值(alpha表示表达式中的a)
			   inputArray 	src2, 		//参数3:输入图像Mat - src2
			   double 		beta, 		//参数4:输入图像src2的alpha值
			   double 		gamma, 		//参数5:gamma值(校验值,使其得到正常图像)
			   OutputArray 	dst, 		//参数6:输出混合图像
			   int 			dtpye = -1	//dtpye默认不用带入
	           )

注意:两张图像大小和类型必须一致才可以使用此API混合

dst(I) = saturate(src1(I) * alpha +src2(I) * beta + gamma);

拓展API:
add(img, dst, dst1); //直接叠加两个图像像素
multiply(img, dst, dst1, 1.0); //两个图像像素相乘


6、调整图像亮度和对比度

图像变换可以看作像素变换(点操作)和领域操作(区域操作),调整图像亮度和对比度属于像素变换
g(i,j) = af(i,j) + β (其中a>0,β是增益变量)

再次回顾重要API:
//像素范围处理函数
saturate_cast<uchar)(-100),返回0
saturate_cast<uchar)(299),返回255
saturate_cast(100),返回100

//图像数据类型转换
img.convertTo(dst, CV_32F);
说明:如果图像默认bit类型,我们把数据转换成浮点型,提高图像精度可以使处理效果提高。


7、绘制形状和文字

· 使用cv::Pointcv::Scalar
Point表示2D平面上一个点,坐标(x,y)
如下:

Point p;
p.x = 10;
p.y = 8;
Point p1 = Point(x, y );

Scalar表示四个元素的向量
Scalar(a, b, c); //a = Blue, b = green, c = Red表示BGR三个通道

· 绘制线、矩形、圆、椭圆等基本几何形状
API使用:
线–> cv::line(LINE_4\LINE_8\LINE_AA) //参数表示绘制线的类型,LINE_AA表示反锯齿
椭圆–> cv::ellipse
椭圆API说明:使用语句示例–>

ellipse(img, Point(img.rows/2, img.cols/2), Size(img.rows/5, img.cols/6), 90, 0, 360, color, 2, 8);
/* Point表示椭圆中心坐标,size表示椭圆尺寸,其中两个参数表示长短轴,angle = 90表示顺时针方向旋转角,startAngle = 0表示绘制的起始角度,endAngle = 360表示绘制的终止角度。*/

矩形–> cv::rectangle //五个参数,第一个参数是Mat对象,第二个参数矩形类型,第三个参数颜色,第四个参数线宽(默认1),第五个参数线的类型(默认LINE_8)
圆–> cv::circle
填充–> cv::fillPoly
fillPoly各参数说明:用法–>

Point pts[1][5] = { Point(100,100), Point(100,200), Point(200,200), Point(200,100), Point(100,100) };
const Point* ppts[] = { pts[0] };
int npt[] = { 5 };
fillPoly(img, ppts, npt, 1, Scalar(255,0,255), 8);		
//ppts表示多边形各顶点集合(静态点对象指针数组),npt表示多边形顶点个数,								//ncontours = 1表示填充个数

对象:
Rect rect = Rect(x, y, w_len, h_len); //后两个参数分别是宽高

· 随机生成与绘制文本
绘制文本API:cv::putText(Mat&, string, Point, int_fontFace, double_fontScale, Scalar, thickness, lineType, bottomLeftOrigin = false);
代码示例:

putText(img, "Hello OpenCV", Point(100,100), CV_FONT_HERSHEY_COMPLEX, 1.0, Scalar(0,0,255), 1, 8);

说明:int_fontFace表示字体类型,double_fontScale表示字体缩放比例,bottomLeftOrigin默认为FALSE不用管。

随机生成图像(以画线为例)
代码如下:

void RandomLineDemo(Mat& img)
{
	RNG rng(12345);
	Point pt1, pt2;
	Mat dst = Mat::zeros(img.size(), img.type());
	namedWindow("test7", CV_WINDOW_AUTOSIZE);
	for (int i = 0; i < 10000; i++)
	{
		pt1.x = rng.uniform(0, img.cols);
		pt2.x = rng.uniform(0, img.cols);
		pt1.y = rng.uniform(0, img.rows);
		pt2.y = rng.uniform(0, img.rows);
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		if (waitKey(50) > 0)
			break;
		imshow("test7", dst);
		line(dst, pt1, pt2, color);
	}
}

说明:RNG是opencv中的随机数类,构造函数指明随机数范围或种子个数,使用uniform(正态分布随机数)方法指定随机数范围,同样的也可以使用gaussian(double sigma)方法生成高斯随机数


8、模糊图像(一)

· 图像的模糊原理

  • Smooth/Blur是图像处理中最简单和常用的操作之一
  • 使用该操作的原因之一就是为了给图像预处理时候降低噪声
  • 使用Smooth/Blur操作其背后是数学的卷积计算:g(i, j) = Σ f( i+k, j+l)h(k, l)
  • 通常这些卷积算子计算都是线性操作,所以又叫线性滤波
  • 归一化盒子滤波(均值滤波)
  • 高斯滤波

· 相关API

  • 均值模糊:
    blur(Mat src, Mat dst, Size(xradius, yradius), Point(-1, -1)); //Point表示中心像素在哪里,(-1, -1)表示默认中心像素

  • 高斯滤波:
    GaussianBlur(Mat src, Mat dst, Size(11, 11), sigmax, sigmay); //sigmax, sigmay是用于调节正态分布图像的参数
    注意:其Size(x, y)中x和y必须是正数而且是奇数,size表示窗口大小


9、模糊图像(二)

· 中值滤波

  • 统计排序滤波器
  • 中值对椒盐噪声有很好的抑制作用
    比如有一个5×5图像:
    123 125 126 130 140
    122 124 126 127 135
    118 120 150 125 134
    119 115 119 123 133
    111 116 110 120 130
    3×3领域像素(坐标为22到44)排序如下:115,119,120,123,124,125,126,127,150
    中值等于:124
    均值等于:125.33

API:medianBlur (Mat src, Mat dst, ksize)
注意:中值模糊的ksize大小必须是大于1而且为奇数 --> ksize表示卷积核大小

· 双边滤波

  • 均值滤波无法克服边缘像素信息丢失缺陷,原因是均值滤波是基于平均权重
  • 高斯模糊部分克服该缺陷,但无法完全避免,原因是没有考虑像素值的不同
  • 高斯双边模糊是边缘保留的滤波方法,避免了边缘信息的丢失,保留了图像轮廓不变

API:bilateralFilter (src, dst, d=15, 150, 3)
说明:d=15为计算半径,半径之内的像素都会被纳入计算,如果该参数提供-1则会根据sigma space参数取计算半径
150表示sigma color,决定多少差值之内像素会被计算
3表示sigma space如果d值大于0则声明无效


10、膨胀与腐蚀

· 膨胀

  • 图像形态学操作:基于形状的一系列图像操作集合,主要是基于集合论基础上的形态学数学
  • 形态学有四个基本操作:腐蚀、膨胀、开、闭
  • 腐蚀和膨胀是图像处理中最基本的形态学操作

说明:膨胀操作跟卷积操作类似,假设有图像A和机构元素B,结构元素B在A上移动,其中B定义其中心为锚点,计算B覆盖下A的最大像素值用来替换锚点像素其中B作为结构体可以是任意形状。而腐蚀跟膨胀操作类似,唯一不同的是以最小值替换锚点重叠下图像的像素值。

相关API:
· getStructuringElement(int shape, Size ksize, Point anchor) //获取结构形状
说明:三个参数分别代表形状(MORPH_RECT \ MORPH_CROSS \ MORPH_ELLIPSE)、大小(要求奇数)、锚点(默认是Point(-1,-1)意思就是中心像素)
· dilate(src, dst, kernel) //膨胀
· erode(src, dst, kernel) //腐蚀

拓展:
动态调整结构元素大小 (GUI函数)

 TrackBar -> createTrackbar(constString & trackbarname,
						   const String winName,
						   int* value,
						   int count,
						   Trackbarcallback func,
						   void* userdata = 0)

//其中最重要的是callback函数功能,如果设置为NULL就是说只有值update,但是不会调用callback的函数。


11、形态学操作(多用于二值图像处理)

· 开操作 - open
说明:图像先腐蚀后膨胀的操作即称为图像的开操作,图像开操作可以去掉小的对象。

· 闭操作 - close
说明: 先膨胀后腐蚀称之为闭操作,可以讲大面积图像中小的缺口给填充。

· 形态学梯度 - Morphological Gradient
说明:图像膨胀后减去原图的腐蚀图像,此种方法又称基本梯度,得到的图像具有梯度效果。

· 顶帽 - top hat
说明:顶帽是原图像与开操作之间的差值图像

· 黑帽 - black hat
说明:黑帽是闭操作图像与源图像的差值图像

API:morphologyEx(src, dst, CV_MOP_BLACKHAT, kernel);
参数说明:
- int OP --> CV_MOP_OPEN/ CV_MOP_CLOSE/ CV_MOP_GRADIENT/ CV_MOP_TOPHAT/ CV_MOP_BLACKHAT (表示形态学操作类型)
- Mat kernel --> 结构元素(选取大小取决于去掉的对象大小)
- int Iteration=1 --> 迭代次数,默认为1

使用实例(开操作):

Mat kernal = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(src, dst, CV_MOP_OPEN, kernal);
imshow("dst", dst);
waitKey(0);

12、提取水平与垂直线(形态学应用)

· 原理方法
图像形态学操作的时候,可以通过自定义的结构元素实现结构元素对输入图像一些对象敏感、另外一些对象不敏感,这样就会让敏感的对象改变而不敏感的对象保留输出。
通过使用两个最基本的形态学操作:膨胀与腐蚀。使用不同的结构元素实现对输入图像的操作并得到想要的结果。

知识回顾:

  • 膨胀,输出的像素值是结构元素覆盖下输入图像的最大像素值
  • 腐蚀,输出的像素值是结构元素覆盖下输入图像的最小像素值

· 结构元素
膨胀与腐蚀过程是可以使用任意的结构元素,常见的形状:矩形、圆、直线、磁盘形状、砖石形状等各种自定义形状。

· 提取步骤
1 - 输入图像
2 - 灰度变换
3 - 二值化 --> adaptiveThreshold
4 - 定义结构元素
5 - 开操作提取水平与垂直线

相关API - adaptiveThreshold(src, dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C);
参数说明:
double maxValue - 输入图像最大灰度值
int adaptiveMethod - 自适应阈值方法(ADAPTIVE_THRESH_MEAN_C / ADAPTIVE_THRESH_GAUSSIAN_C)
int thresholdType - 阈值类型(常用 THRESH_BINARY)
int blockSize - 子块大小
double C - 常量,可为正数、负数、0

结构元素定义实例代码:

Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1));
Mat wline = getStructruingElement(MORPH_RECT, Size(1, src.row . 16), Point(-1, -1));

拓展API:bitwist_not(src, src); --> 图像二进制数据“非”操作


13、图像上采样和降采样

· 图像金字塔概念说明
我们在图像处理中常常会调整图像大下,最常见的就是放大和缩小,尽管几何变换也可以实现图像的放大和缩小,但是这里所说的
大小调整是指图像金字塔从下到上分辨率的缩小。一个图像金字塔是一系列图像组成,最底下一张是图像尺寸最大,最上方图像尺
寸最小,从空间上由上向下看就像古埃及金字塔。

图像金字塔分为高斯金字塔和拉普拉斯金字塔,高斯金字塔用来对图像进行降采样,拉普拉斯金字塔用来重建一张图片根据它的上
层降采样图片

高斯金字塔:

  • 高斯金字塔是从底向上,逐层采样得到的

  • 降采样之后图像大小是原图像 M × N 的 M/2 × N/2,就是对原图像删除偶数行与列,即得到采样后的上层图像

  • 高斯金字塔的生成过程分为两步:
    1 - 对当前层进行高斯模糊
    2 - 删除当前层的偶数行与列
    即可得到上一层图像,这样上一层和下一层相比,都只有它大小的1/4

          	{1, 4, 6,4,1;	
           	 4,16,24,16,4;
     1/16 ×  6,24,36,24,6;
           	 4,16,24,16,4;
           	 1, 4, 6, 4,1;}
    

高斯不同(DOG):

  • 定义:把同一张图像在不同的参数下做高斯模糊之后的结果相减,得到的输出图像称之为高斯不同。

  • 高斯不同是图像的内在特征,在灰度图像增强、角点检测中经常使用
    代码示例:

    cvtColor(src, gray_src, CV_BGR2GRAY);
    GaussianBlur(gray_src, g1_dst, Size(3, 3), 0, 0);
    GaussianBlur(g1_dst, g2_dst, Size(3, 3), 0, 0);
    subtract(g1_dst, g2_dst, DOGimage, Mat());
    normalize(DOGimage, DOGimage, 255, 0, NORM_MINMAX);	// 还原灰度范围
    imshow("DOG image", DOGimage);
    waitKey(0);
    

相关API:
· 上采用 --> cv::pyrUp(Mat src, Mat dst, Size(src.cols*2, src.rows*2))
效果:生成的图像是原图在宽和高各放大两倍

· 降采样 --> cv::pyrDown(Mat src, Mat dst, Size(src.col/2, src.rows/2))
效果:生成的图像是原图在宽与高各缩小1/2


14、阈值操作

阈值操作:二值化、反二值化、截断、阈值取零、阈值反取零
API–>cv::threshold(img, dst, thresh, max_value, type);
说明:type参数表示阈值操作类型,可填写cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC, cv::THRESH_TOZERO, cv::THRESH_TOZERO_TNV等。


15、边缘填充

·OpenCV中常用的边缘填充函数为copyMakeBorder();
函数原型:void copyMakeBorder(const Mat &src, Mat& dst, int top, int bottom, int left, int right, int borderType, const Scalar &value=Scalar());
功能:扩充src的边缘,将图像变大,然后以各种外插方式自动填充图像边界,这个函数实际上调用了函数cv::borderInterpolate,这个函数最重要的功能就是为了处理边界,比如均值滤波或者中值滤波中,使用copyMakeBorder将原图稍微放大,然后我们就可以处理边界的情况。
参数说明:
src,dst:原图与目标图像
top,bottom,left,right分别表示在原图四周扩充边缘的大小
borderType:扩充边缘的类型,就是外插的类型,OpenCV中给出以下几种方式

  • BORDER_REPLICATE

  • BORDER_REFLECT

  • BORDER_REFLECT_101

  • BORDER_WRAP

  • BORDER_CONSTANT
    BORDER_REPLICATE:边缘像素复制法
    BORDER_REFLECT_101:对称法,以最边缘像素为轴,对称
    BORDER_CONSTANT:常量法


16、sobel算子锐化和Laplace算子锐化

API:cv::Sobel(img, dst, depth, dx, dy); // dx和dy分别表示x方向和y方向上的差分阶数
cv::Laplacian(img, dst, depth);


17、Canny边缘检测算法

· Canny算法五步走:

1、高斯模糊 - GaussianBlur

2、灰度转换 - cvtColor

3、计算梯度 - Sobel / Scharr

4、非最大信号抑制

5、高低阈值连接输出二值图像

什么是非最大信号抑制:

图像梯度幅值矩阵中的元素值越大,说明图像中该点的梯度值越大,但这不不能说明该点就是边缘(这仅仅是属于图像增强的过程)。在Canny算法中,非极大值抑制是进行边缘检测的重要步骤,通俗意义上是指寻找像素点局部最大值,将非极大值点所对应的灰度值置为0,这样可以剔除掉一大部分非边缘的点。

img

根据图可知,要进行非极大值抑制,就首先要确定像素点C的灰度值在其8值邻域内是否为最大。图中蓝色的线条方向为C点的梯度方向,这样就可以确定其局部的最大值肯定分布在这条线上,也即出了C点外,梯度方向的交点dTmp1和dTmp2这两个点的值也可能会是局部最大值。因此,判断C点灰度与这两个点灰度大小即可判断C点是否为其邻域内的局部最大灰度点。如果经过判断,C点灰度值小于这两个点中的任一个,那就说明C点不是局部极大值,那么则可以排除C点为边缘。这就是非极大值抑制的工作原理。

注意以下两点:

​ 1)中非最大抑制是回答这样一个问题:“当前的梯度值在梯度方向上是一个局部最大值吗?” 所以,要把当前位置的梯度值与梯度方向上两侧的梯度值进行比较;

​ 2)梯度方向垂直于边缘方向。

​ 但实际上,我们只能得到C点邻域的8个点的值,而dTmp1和dTmp2并不在其中,要得到这两个值就需要对该两个点两端的已知灰度进行线性插值,也即根据图中的g1和g2对dTmp1进行插值,根据g3和g4对dTmp2进行插值,这要用到其梯度方向,这是Canny算法中要求解梯度方向矩阵Thita的原因。

​ 完成非极大值抑制后,会得到一个二值图像,非边缘的点灰度值均为0,可能为边缘的局部灰度极大值点可设置其灰度为128。根据下文的具体测试图像可以看出,这样一个检测结果还是包含了很多由噪声及其他原因造成的假边缘。因此还需要进一步的处理。

在这里插入图片描述

高低阈值连接:

img

· API介绍

cv::Canny(InputArray src,	// 8bit输入图像
         OutputArray edges,	// 输出边缘图像,一般都是二值图像,背景为黑色
         double threshold1,	// 低阈值,常取高阈值的1/2或者1/3
         double threshold2, // 高阈值
         int aptertureSize, // Sobel算子size,通常为3×3,取值3
         bool L2gradient 	// 选择true表示是L2归一化方法,否则使用L1方法
         )

· 相关代码

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using std::cout;
using std::endl;

const int t1_value = 50, max_value = 255;
Mat src, dst, gray_src;
void Canny_Demo(int, void*)
{
    Mat edge_output;
    blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
    Canny(gray_src, edge_output, t1_value, t1_value*2, 3, false);
    dst.create(src.size(), src.type());
    src.copyTo(dst, edge_output);
    // imshow("output", dst);
    imshow("out", edge_output);
}
int main(int argc, char** argv)
{
    src = imread("Path");
    if(!src.data)
    {
        cout << "could not load image" << endl;
        return -1;
    }
    imshow("input", src);
    cvtColor(src, gray_src, CV_BGR2GRAY);
    createTrackbar("Threshold Value", "Result", &t1_value, max_value, Canny_Demo);
    Canny_Demo(0, 0);
    
    waitKey(0);
    return 0;
}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV(Open Source Computer Vision Library)是一个开源计算机视觉库,主要用于实时图像处理、计算机视觉任务和机器学习应用。在C++中使用OpenCV需要注意以下几个关键点: 1. **安装**:首先需要从官网下载适合你的平台的版本,并按照文档安装。确保路径添加到系统环境变量中,以便程序能够找到库文件。 2. **基本结构**:OpenCV的主要数据结构包括Mat(矩阵),它是最基本的数据容器,用于存储图像和像素数据。还有其他如Point、Size、Rect等用于表示几何形状的对象。 3. **函数使用**:OpenCV提供大量图像处理和计算机视觉函数,例如读取和显示图片(imread、imshow)、图像操作(resize、crop)、颜色空间转换、边缘检测(Canny)、特征提取(SIFT、SURF)以及机器学习模块(比如Haar cascades用于人脸检测)。 4. **模板编程**:利用OpenCV提供的API,通常通过模板类和函数来编写代码,因为很多操作都是针对不同类型的图像矩阵。 5. **异常处理**:由于OpenCV函数可能会抛出错误,记得在关键部分使用try-catch块来捕获并处理异常。 6. **内存管理**:Mat对象在内部管理其内存,但建议手动释放不再使用的大型矩阵,避免内存泄漏。 7. **多线程支持**:OpenCV提供了线程安全的函数,如果你需要在多线程环境中工作,确保正确同步访问共享资源。 8. **实践项目**:熟悉OpenCV最好的方式就是实际参与一些项目,比如图像分类、物体追踪等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值