前言:看的是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
#include
#include
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;
}