OpenCV笔记

前言:看的是B站上的视频,基于3.1.0版本和VS2015版本的

1.矩阵掩膜函数,用来增强图片的对比度,使图像阴暗更分明,看起来效果更好:
Mat src,dst;
Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);// 创建掩膜矩阵.
filter2D(src, dst, src.depth(), kernel)//表示把图src用kernel掩膜然后传给dst,src.depth()表示图的位深度
2.一个很重要的处理像素范围的函数:
saturate_cast(int value);//此函数返回一个0到255的值,当value小于0的时候返回0,大于255的时候返回255,在0-255之间的时候返回value。
3.Mat对象的一些常用方法:
Mat src,dst;
⑴.dst = Mat(src.size(), src.type());//创建一个和src尺寸相同,类型一样的图
dst = Scalar(0, 255, 0);//给这个图的三个通道统一赋值
namedWindow(“output”, CV_WINDOW_AUTOSIZE);//创建窗口
imshow(“output”, dst);在这个窗口上把dst显示出来。
⑵.克隆图像:
src.copyTo(dst)或者dst=src.clone();
⑶.图像转换:
cvtColor(src,dst,CV_BGR2GRAY);//把src从rgb转换成gary,并传给dst.
const char*firstRow=dst.ptr(0);//获取dst图第0行第一个灰度值,前提是dst是灰度图。
4.读取像素值
⑴.针对Gray灰度图:用image.at(y,x)
⑵.针对RGB三通道图:某一坐标的B值=image.at(y,x)[0]
G值=image.at(y,x)[1]
R值=image.at(y,x)[2]
5.对图像进行取反函数:Mat src,dst
bitwise_not(src,dst);//把src图取反传给dst
6.C++中取两个数中最大值的函数:max(a,b)
7.配完环境后如果还提示缺少opencv的dll,可以把所有dll放在C:\Windows\System32里就可以了
8.Mat::zeros(image.size(),image.type())//创建一张跟原图像大小类型一致的空白图像,像素初始值为0;
9.提高或者降低图像亮度与对比度:

	Mat src, dst;
	dst = Mat::zeros(src.size(), src.type());

	float alpha = 1.2;//增加对比度,若想降低可以赋值为0点几
	float beta = 100;//增加亮度,若想降低可赋值为小于0
	for (int row = 0; row < src.rows; row++)
	{
		for (int col = 0; col < src.cols; col++)
		{
			if (src.channels() == 3)
			{
				float b = src.at<Vec3b>(row, col)[0];
				float g = src.at<Vec3b>(row, col)[1];
				float r = src.at<Vec3b>(row, col)[2];
				dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b*alpha + beta);
				dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g*alpha + beta);
				dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r*alpha + beta);

			}
			else if(src.channels() == 1)
			{
				float v = src.at<uchar>(row, col);
				dst.at<uchar>(row, col) = saturate_cast<uchar>(v*alpha + beta);
			}
		}
	}

10.绘制图像和文字:
创建点:

    Point p;
	p.x = 10;
	p.y = 8;

或者:

    Point p = Point(10, 8);

在图像上画线,矩形,椭圆,圆,写文本:

using namespace cv;
using namespace std;
Mat bgImage;
const char input_window[] = "draw image demo";
void MyLines();
void MyRectangle();
void MyEllipse();
void MyCircle();
int main(int argc, char** argv) {
	bgImage = imread("C:/Users/lenovo/Desktop/timg.jpg");
	if (bgImage.empty())
	{


		cout << "could not open the picture!";
		return -1;
	}
	MyLines();//划线
	MyRectangle();//画矩形
	MyEllipse();//画椭圆
	MyCircle();//画圆
	putText(bgImage, "Hello World!", Point(bgImage.cols / 2, bgImage.rows / 2), CV_FONT_HERSHEY_COMPLEX, 1.0, Scalar(0, 0, 255), 2, LINE_8);//在图像上写文字
	//bgImage是要写上字的图像,Point是文字中心点,3是字体类型,1.0是字体缩放倍数,5是字体颜色,2是字体粗细,LINE_8是字线条类型。
	namedWindow(input_window, CV_WINDOW_AUTOSIZE);
	imshow(input_window, bgImage);
	waitKey(0);
	return 0;
}

void MyLines()
{
	Point p1 = Point(20, 30);
	Point p2 = Point(300, 300);
	Scalar color = Scalar(0, 0, 255);
	line(bgImage, p1, p2, color, 1, LINE_8);//p1,p2是起始点,color是线颜色,1是线宽,LINE_8是线类型
}

void MyRectangle()
{
	Rect rect = Rect(200, 100, 300, 300);//头两个参数是起点x,y坐标,后两个是宽和高
	Scalar color = Scalar(255, 0, 0);
	rectangle(bgImage, rect, color, 2, LINE_8);//2是线宽,LINE_8是线类型
}

void MyEllipse()
{
	Scalar color = Scalar(0, 255, 0);
	ellipse(bgImage, Point(bgImage.cols / 2, bgImage.rows / 2), Size(bgImage.cols / 4, bgImage.rows / 8), 90, 0, 360, color, 2, LINE_8);
	//Point是椭圆中心,Size里面是长轴和短轴,90是旋转角度,0和360代表画完一整个封闭椭圆
}

void MyCircle()
{
	Scalar color = Scalar(0, 255, 0);
	circle(bgImage, Point(bgImage.cols / 2, bgImage.rows / 2), 50, color, 2, LINE_8);//Point是圆心,50是半径
}

11.图像模糊:
⑴.高斯滤波和均值滤波的区别理解:两者都可以用来消除噪声(个人理解中值滤波是去除噪声最好的),但均值滤波不能很好地保留图像细节(高斯好一点,但也不能完全保留细节,高斯双边滤波可以,常用于人脸美容);均值滤波处理后,原本很大的像素值可以变得很小,高斯滤波则会让原本很大的像素值依然很大,经常用来消除服从高斯分布的高斯噪声;高斯滤波比均值滤波的好处是可以突出重点。
⑵.算子说明:
①.均值滤波:

void blur(InputArray src, OutputArraydst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT )  

参数说明:前两个参数分别是输入和输出图像;Size是平滑的矩阵大小((15,1)是对图像X方向进行模糊,(1,15)是对Y方向模糊),矩阵越大模糊越厉害,常用(3,3);Point表示矩阵的锚点,默认值是(-1,-1),表示在中心;第五个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT,我们一般不去管它,可以直接不用输入这个参数。
②.高斯滤波:

void GaussianBlur(InputArray src,OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, intborderType=BORDER_DEFAULT )  

参数说明:前两个参数分别是输入和输出图像;第三个参数,Size类型的ksize高斯内核的大小,表示平滑矩阵大小;第四个参数,double类型的sigmaX,表示高斯核函数在X方向的的标准偏差;第五个参数,double类型的sigmaY,表示高斯核函数在Y方向的的标准偏差。若sigmaY为零,就将它设为sigmaX,如果sigmaX和sigmaY都是0,那么就由ksize.width和ksize.height计算出来;为了结果的正确性着想,最好是把第三个参数Size,第四个参数sigmaX和第五个参数sigmaY全部指定到;第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT,我们一般不去管它,可以不用输入。
③.中值滤波:(去除椒盐噪声最常用)

void medianBlur(InputArray src,OutputArray dst, Size ksize)

参数说明:前两个分别为输入和输出图像,ksize是平滑的矩阵大小,这个值只能大于0,且一定是奇数,填一个数就行,因为这个矩阵一定是正方形的。
④.高斯双边滤波:(相对于高斯滤波能更好的保留原图细节,常用于人脸美容修图祛痘)

void bilateralFilter( InputArray src, OutputArray dst, int d,
                                   double sigmaColor, double sigmaSpace,
                                   int borderType = BORDER_DEFAULT );

参数说明:
参数3:每个像素领域的直径d。(常用15)

参数4:颜色空间滤波器sigma的值,决定多少差值之内的像素会被计算。可以比喻为一个网,越大,漏出来的越大。(常用150)

参数5:坐标空间中滤波器sigma的值。d>0,声明无效,否则根据它来计算d值。(常用3)

参数6:边界模式,有默认值(可以不填)

12.膨胀和腐蚀
形态学四个基本操作:腐蚀、膨胀、开运算、闭运算。
⑴.膨胀:用一个模板在图像上滑动,以模板内像素最大值替换模板中心点像素值,作用是把图暗的区域变得更小
⑵.腐蚀:和膨胀相反
代码演示:(注意创建滑动条和函数绑定的方法很实用)

#include<opencv2/opencv.hpp>
#include<iostream>
#include<cstdio>

using namespace cv;
using namespace std;
Mat src,dst;
const char output_window[] = "output image";
int element_size = 3;
int max_size = 21;
void CallBack_demo(int, void*);
int main(int argc, char** argv) {
	src = imread("C:/Users/lenovo/Desktop/timg.jpg");
	if (!src.data)
	{
		cout << "could not open the picture!\n";
		return -1;
	}
	namedWindow("input image", CV_WINDOW_AUTOSIZE);
	imshow("input image", src);

	namedWindow(output_window, CV_WINDOW_AUTOSIZE);
	createTrackbar("Element Size: ",output_window,&element_size,max_size,CallBack_demo);//在UI上创建一个滑动条,回调函数用CallBack_demo
	//这样滑动这个模块的时候图像就会跟着变化,注意CallBack_demo函数中structElement的赋值,是跟element_size关联在一起的
	CallBack_demo(0, 0);

	waitKey(0);
	return 0;
}

void CallBack_demo(int, void *)
{
	Mat structElement = getStructuringElement(MORPH_RECT, Size(element_size * 2 + 1, element_size * 2 + 1), Point(-1, -1));//获取结构元素函数,第一个参数
	//是形态学运算的模板形状(这里是矩形),第二个参数是内核的尺寸,第三个参数是内核的锚点,默认为(-1,-1),表示在中心点。
	dilate(src, dst, structElement, Point(-1, -1), 1);//膨胀(亮的更多),Point默认在(-1,-1)锚点在中心点(可不写),1表示膨胀的循环次数为1次(不写默认为1)
	erode(src,dst,structElement);//腐蚀(暗的更多)参数解释同膨胀
	imshow(output_window, dst);
}

13.开运算闭运算
高级形态学变换:
开运算:
先腐蚀,再膨胀,可清除小亮点
闭运算:
先膨胀,再腐蚀,可清除小黑点
形态学梯度:
膨胀图与腐蚀图之差,提取物体边缘
顶帽:
原图像-开运算图,突出原图像中比周围亮的区域 ,可以用来提取小亮点
黑帽:
闭运算图-原图像,突出原图像中比周围暗的区域,提取小黑点

morphologyEx函数利用基本的膨胀和腐蚀技术,来执行更加高级形态学变换,函数如下:

morphologyEx( InputArray src, OutputArray dst,
                                int op, InputArray kernel,
                                Point anchor = Point(-1,-1), int iterations = 1,
                                int borderType = BORDER_CONSTANT,
                                const Scalar& borderValue = morphologyDefaultBorderValue() );

参数说明:
src
输入图像,图像位深应该为以下五种之一:CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。
dst
输出图像,需和源图片保持一样的尺寸和类型。
op
表示形态学运算的类型:
MORPH_OPEN – 开运算(Opening operation)
MORPH_CLOSE – 闭运算(Closing operation)
MORPH_GRADIENT - 形态学梯度(Morphological gradient)
MORPH_TOPHAT - 顶帽(Top hat)
MORPH_BLACKHAT - 黑帽(Black hat)
kernel
形态学运算的内核。为NULL,使用参考点位于中心3x3的核。一般使用函数getStructuringElement配合这个参数的使用,
kernel参数填保存getStructuringElement返回值的Mat类型变量。
anchor
锚的位置,其有默认值(-1,-1),表示锚位于中心。 可不输入
iterations
迭代使用函数的次数,默认值为1。 可不输入
borderType
用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_CONSTANT。 可不输入
borderValue
当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),可不输入

一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。
14.两种二值化方法详解:
此部分参考【OpenCV3】阈值化操作,又修改了部分内容。
⑴.直接二值化:


double cv::threshold(
	cv::InputArray src, // 输入图像
	cv::OutputArray dst, // 输出图像
	double thresh, // 阈值
	double maxValue, // 向上最大值
	int thresholdType // 阈值化操作的类型 
);

参数详解:thresholdType 有五个选项:
CV_THRESH_BINARY;CV_THRESH_BINARY_INV;CV_THRESH_TRUNC;CV_THRESH_TOZERO;CV_THRESH_TOZERO_INV。下图给出了五个不同选项的效果:
在这里插入图片描述
代码演示:

void test_threshold()
{
	Mat src = imread("C:/Users/lenovo/Desktop/timg.jpg", IMREAD_GRAYSCALE);
	Mat dst;

	threshold(src, dst, 100, 255, THRESH_BINARY);

	namedWindow("threshold", CV_WINDOW_AUTOSIZE);
	imshow("threshold", dst);
	waitKey(0);

	return;
}

注:有时我们自己不知道如何去确定阈值设为多少才合适,这时候就会用到两个自动找阈值的方法,具体的操作方式是:

threshold(gray_src,dst,0,255,THRESH_OTSU | THRESH_BINARY);//注意最后一个参数的用法,“|”之前是一个表示要自动寻阈值

但是,直接阈值化操作是一种一刀切的方式,对于亮度分布差异较大的图像,常常无法找到一个合适的阈值。如下所示,对棋盘格进行二值化操作,由于图像右上角区域和图像下部的亮度差异较为大,无法找到一个合适的阈值,将棋盘上的所有棋盘格给区分开来
原图
直接二值化图片
针对于上述情况,我们需要一种改进的阈值化算法,即自适应阈值化。
⑵.自适应阈值化能够根据图像不同区域亮度分布的,改变阈值,具体调用方法如下:


void cv::adaptiveThreshold(
	cv::InputArray src, // 输入图像
	cv::OutputArray dst, // 输出图像
	double maxValue, // 向上最大值
	int adaptiveMethod, // 自适应方法,平均或高斯
	int thresholdType // 阈值化类型
	int blockSize, // 块大小
	double C // 常量
	);

cv::adaptiveThreshold()支持两种自适应方法,即cv::ADAPTIVE_THRESH_MEAN_C(平均)和cv::ADAPTIVE_THRESH_GAUSSIAN_C(高斯)。在两种情况下,自适应阈值T(x, y)。通过计算每个像素周围b*b大小像素块的加权均值并减去常量C得到。其中,b由blockSize给出,大小必须为奇数;如果使用平均的方法,则所有像素周围的权值相同;如果使用高斯的方法,则(x,y)周围的像素的权值则根据其到中心点的距离通过高斯方程得到。
代码演示如下:


void test_adaptive_threshold()
{
	Mat src = imread("chessboard.png", IMREAD_GRAYSCALE);
	Mat dst;
 
	int maxVal = 255;
	int blockSize = 41;
	double C = 0;
	adaptiveThreshold(src, dst, maxVal, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, blockSize, C);
 
	imshow("threshold", dst);
	waitKey(0);
	return;
}

分别使用平均和高斯两种自适应方法,结果如下:
在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值