title:OpenCV
time:2019年9月7日09:46:56
参考
添加系统变量path:D:\Microsoft\opencv\build\x64\vc15\bin
把opencv\build\x64\vc15\bin中几个应用程序扩展全都放进window/sysWOW64和system32中
项目属性管理器中x64中右键
vc++目录中包含目录
库目录
链接器中
加载图像(cv::imread)
加载图像文件成为一个Mat对象,
第一个参数是图像文件名称
表示加载的图像是什么类型,支持常见的三个参数值
注意:支持JPG、PNG、TIFF等常见格式图像文件加载
显示图像(cv::namedWindos与cv::inshow)
修改图像(cv::cvtColor)
保存图像(cv::imwrite)
waitKey(0)
像素范围处理saturate_cast
对比度增加
这个公式的意思就是如果你选中 的这个中心点比周围的暗,那就让它更暗,如果比周围的亮,那就让它更亮,当你把这个操作扩展到整个图像之后,图像之间的亮暗差距会变得更大,也就是对比度会更大row=1 而不是0,因为一个图像的边缘点没有四周进行对比,不能使用公式,所以循环从1开始,去掉了最外圈像素没有办法进行比较的点
int cols = (src.cols-1) * src.channels();
int offsetx = src.channels();
int rows = src.rows;
dst = Mat::zeros(src.size(), src.type());
for (int row = 1; row < (rows - 1); row++) {
const uchar* previous = src.ptr(row - 1);
const uchar* current = src.ptr(row);
const uchar* next = src.ptr(row + 1);
uchar* output = dst.ptr(row);
for (int col = offsetx; col < cols; col++) {
output[col] = saturate_cast(5 * current[col] - (current[col- offsetx] + current[col+ offsetx] + previous[col] + next[col]));
}
}
而OpenCV把这部分代码封装了起来
函数调用filter2D功能
定义掩膜:
Mat kernal = (Mat_(3,3)<<0,-1,0,-1,5, -1, 0, -1, 0);
filter2D( src, dst, src.depth(), kernel );其中src与dst是Mat类型变量、src.depth表示位图深度,默认是-1,有32、24、8等。
double t = getTickCount();
Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dst, src.depth(), kernel);
double timeconsume = (getTickCount() - t) / getTickFrequency();//获取执行时间
printf("tim consume %.2f\n", timeconsume);
Mat对象使用
MatB(A)
A.clone() 或 A.copyTo(B)
cv::Mat::Mat构造函数
#include
#include
using namespace std;
using namespace cv;
int main() {
Mat src = imread("C:/Users/sualab/Downloads/image/timg.jfif");
if (src.empty()) {
cout << "not found" << endl;
return -1;
}
//自定义图片大小、类型
Mat dsrc = Mat(src.size(), src.type());
dsrc = Scalar(4, 22, 244);
/*namedWindow("test", WINDOW_AUTOSIZE);
imshow("test", dsrc);*/
Mat dsrc00(dsrc);
Mat dsrc01 = src.clone();
//src.copyTo(dsrc01);
namedWindow("test", WINDOW_AUTOSIZE);
imshow("test", dsrc01);
//查看通道数
Mat dsrc02;
cvtColor(src, dsrc02,COLOR_BGR2GRAY);
namedWindow("test01", WINDOW_AUTOSIZE);
imshow("test01", dsrc02);
cout <<"原图像的通道数:"<< dsrc01.channels() << endl;
cout << "转化图像的通道数:" << dsrc02.channels() << endl;
//可以自定义大小的构造方式
Mat dsrc04 = Mat(3, 3, CV_8UC3, Scalar(2, 45, 2));
//创建Mat,同上
Mat dsrc05;
dsrc05.create(3, 3, CV_8UC3);
dsrc05 = Scalar(1, 3, 2);
cout << "dsrc05" << dsrc05 << endl;
//获得图像的指针
uchar* firstRow = dsrc05.ptr(0);
printf("指针指向图像的第一个像素的灰度值:%d", *firstRow);//这里用cout不能获取指针的值(?)
/*uchar* firstRow = src.ptr(0);
cout << "" << *firstRow << endl;*/
//获得行数、列数
int rows = src.rows;
int cols = src.cols;
cout << "rows:" << rows << endl;
cout << "cols" << cols;
//定义小数组,(可以用来提高图片的对比度)
Mat kernal = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
//把一个图像初始化为0(全黑)
//Mat::zeros(src.size(),src.type());
Mat m = Mat::zeros(2, 2, CV_8UC1);
cout << "m" << m << endl;
namedWindow("test02", WINDOW_AUTOSIZE);
imshow("test02", m);
//创建对角线为1的矩阵
Mat m1 = Mat::eye(2, 2, CV_8UC1);
waitKey(0);
return 0;
}
理论
图像变换
调整图像亮度和对比度属于像素变换-点操作
重要的API
使用Point 和Scalar
绘制线、矩形、园、椭圆等基本几何形状
画线 cv::line (LINE_4\LINE_8\LINE_AA(反锯齿))
画椭圆cv::ellipse
画矩形cv::rectangle
画圆cv::circle
画填充cv::fillPoly
fillPoly(img,ppt,npt,1,Scalar(255,255,255),lineType);
函数参数:
多边形的顶点集为ppt
绘制的多边形顶点数目为npt
要绘制的多边形数量为1
多边形的颜色定义为Scarlar(255,255,255),即RGB的值为白色
void myfillpoly() {
//申明一个顶点集合数组
Point a[1][5];
//五个顶点
a[0][0] = Point(100, 100);
a[0][1] = Point(100, 300);
a[0][2] = Point(200, 300);
a[0][3] = Point(200, 300);
a[0][4] = Point(200, 300);
const Point* ppt[] = { a[0] };//定一个指针集,指向各个顶点
int npt[] = { 5 };//顶点数目,因为可能有多个多边形,所以定义为数组形式
//第四个参数为多边形的数目
fillPoly(src, ppt, npt, 1, Scalar(33, 55,6, 122));
}
putText()绘制文本
void putText(
cv::Mat& img, // 待绘制的图像
const string& text, // 待绘制的文字
cv::Point origin, // 文本框的左下角
int fontFace, // 字体 (如cv::FONT_HERSHEY_PLAIN)
double fontScale, // 尺寸因子,值越大文字越大
cv::Scalar color, // 线条的颜色(RGB)
int thickness = 1, // 线条宽度
int lineType = 8, // 线型(4邻域或8邻域,默认8邻域)
bool bottomLeftOrigin = false // true='origin at lower left'
)
RNG
噪声在图像当中常表现为一引起较强视觉效果的孤立像素点或像素块。简单来说,噪声的出现会给图像带来干扰,让图像变得不清楚。
均值滤波
void blur(Mat src,Mat dst, Size(xradius,yradius), Point(-1, -1))
高斯滤波
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。
#高斯函数
void GaussianBlur(InputArray src, //输入图像
OutputArray dst, //输出图像
Size ksize, //内核的大小,size(x,y)其中xy为正数,奇数。
double sigmaX, //高斯核函数在X方向的标准偏差
double sigmaY=0, //高斯核函数在Y方向的标准偏差
intborderType=BORDER_DEFAULT )
中值滤波
中值,中间值,将数据从小到大排序后的中间值,赋给中间的值
中值模糊的ksize大小必须是大于1而且必须是奇数。
void medianBlur(InputArray src, OutputArray dst, int ksize)
双边滤波
均值模糊无法克服边缘像素信息丢失缺陷。原因是均值模糊是基于平均权重。
高斯模糊部分克服了该缺陷,但是无法完全避免,因为没考虑到像素值的不同。
双边滤波是保留边缘的滤波方法,避免了边缘信息的丢失,保留了图像轮廓不变。
void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT
中值与双边一般适合磨边美颜。
参考
膨胀
腐蚀
#include
using namespace cv;
Mat src_1,nsrc_1;
//拖动条的值
int value;
void on_trackBar(int, void*);
int main1_1() {
value = 1;
src_1 = imread("C:/Users/sualab/Downloads/image/tg.jfif");
namedWindow("test", WINDOW_AUTOSIZE);
imshow("test", src_1);
namedWindow("ntest", WINDOW_AUTOSIZE);
createTrackbar("bar", "ntest", &value, 100, on_trackBar);
on_trackBar(value, 0);//回调函数,调用定义的trackBar函数
waitKey(0);
return 0;
}
void on_trackBar(int, void*) {
if (value == 0) {
value = 1;
}
int s = value * 2 + 1;
Mat element = getStructuringElement(MORPH_RECT, Size(s, s));//Size为腐蚀的程度
//腐蚀
//erode(src_1, nsrc_1, element);//第三个为结构元素,第四个为锚点,默认值
//膨胀
dilate(src_1, nsrc_1, element);
imshow("ntest", nsrc_1);
}
void morphologyEx(src, dst, int op, InputArray kernel, Point ancho, int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue())
第三个参数:选择使用什么形态学操作
MORPH_OPEN - 开操作
MORPH_CLOSE - 闭操作
MORPH_GRADIENT - 形态学梯度
MORPH_TOPHAT - 顶帽
MORPH_BLACKHAT - 黑帽
MORPH_HITMISS - 击中与击不中
开运算
闭运算
形态学梯度
顶帽
原图像与开操作之间的差值,
因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。
顶帽运算往往用来分离比邻近点亮一些的斑块。当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取。
黑帽
黑帽是闭操作图像与源图像的差值图像
黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关。所以,黑帽运算用来分离比邻近点暗一些的斑块。
参考
输入图像彩色图像 imread
转换为灰度图像 – cvtColor
转换为二值图像 – adaptiveThreshold
定义结构元素
开操作 (腐蚀 + 膨胀)提取 水平与垂直线
#include
using namespace cv;
//输入图像彩色图像 imread
//转换为灰度图像 – cvtColor
//转换为二值图像 – adaptiveThreshold
//定义结构元素
//开操作 (腐蚀 + 膨胀)提取 水平与垂直线
int main1_3() {
Mat src = imread("C:/Users/sualab/Pictures/test.png");
Mat gray_src,nsrc;
//转为灰度
cvtColor(src, gray_src, COLOR_BGR2GRAY);
//转为二值图像
//adaptiveThreshold(
// Mat src, // 输入的灰度图像 取反操作,默认是黑底白字
// Mat dest, // 二值图像
// double maxValue, // 二值图像最大值
// int adaptiveMethod // 自适应方法,只能其中之一 –
// // ADAPTIVE_THRESH_MEAN_C , ADAPTIVE_THRESH_GAUSSIAN_C
// int thresholdType,// 阈值类型
// int blockSize, // 块大小
// double C // 常量C 可以是正数,0,负数
//)
imshow("test3", gray_src);
adaptiveThreshold(~gray_src, nsrc, 255,ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
//定义结构元素
//定义矩形元素
Mat kernal = getStructuringElement(MORPH_RECT, Size(3, 3));
//定义水平元素
Mat xline = getStructuringElement(MORPH_RECT, Size(1, src.rows / 16));
//定义垂直元素
Mat yline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1));
Mat nnsrc;
Mat nnnsrc;
/*erode(nsrc, nnsrc, xline);
dilate(nnsrc, nnnsrc, xline);*/
//morphologyEx(src, nnsrc, MORPH_OPEN, kernal);效果如上所示
/*erode(nsrc, nnsrc, yline);
dilate(nnsrc, nnnsrc, yline);*/
erode(nsrc, nnsrc, kernal);
dilate(nnsrc, nnnsrc, kernal);
imshow("ntest", nnnsrc);
waitKey();
return 0;
}
图像的二值化
阈值类型
threshold(img, threshold, maxval,type)
THRESH_BINARY
THRESH_BINARY_INV
THRESH_TRUNC
THRESH_TOZERO
小于阈值部分被置为0,大于部分保持不变
**THRESH_TOZERO_INV **
参考
卷积概念
卷积是图像处理中一个操作,是kernal在图像的每个像素上的操作。
kernal本质上是一个固定的矩阵数组,其中心点称为锚点(anchor point)
算子
-1 1 -1
-1 5 -1
-1 1 -1