(1)加载图像是什么:
Mat src = cv::imread(“D:2222.jpg”);
imread的功能是加载图像文件成为一个Mat对象,第一个参数表示图像的存储路径,第二个参数表示加载的图像是什么类型;
IMREAD_UNCHANGED(<0)表示加载原图,不做任何修改;
IMREAD_GRAYSCALE(=0)表示把原图作为灰度图像加载进来;
IMREAD_COLOR(>0)表示把原图作为RGB图像加载进来;
OpenCV支持加载jpg、png、tiff等格式图像;
(2)图像显示是什么:
cv::namedWindos和cv::imshow;
namedWindos(“Window Title”, WINDOW_AUTOSIZE);
WINDOW_AUTOSIZE表示根据图像大小显示,不能认为修改图像的尺寸大小;
namedWindos表示创建一个OpenCV窗口,它是由OpenCV自动创建和销毁的,无需手动销毁;
imshow(“Window Title”, src);
imshow是根据窗口名称显示图像到指定窗口中去,第一个参数是窗口名称,第二个参数是Mat对象;
(3)修改图像是什么:
cv::cvtColor
cvtColor(src, des, COLOR_BGR2GRAY);
cvtColor的功能是把图像从一个彩色空间转移到另外一个彩色空间,第一个参数表示源图像,第二个参数表示转移到的目标图像,第三个参数表示转移色彩属性,COLOR_BGR2HLS、COLOR_BGR2GAY等;
(4)保存图像是什么:
cv::imwrite
用于保存图像到指定目录中;
只有8位、16位的JPG、PNG、TIFF格式的图像并且单通道或者三通道的BGR的图像才能通过这种方式保存;
保存PNG格式的时候可以保存透明通道的图片;
可以指定压缩参数;
(5)代码演示:
Mat src, des;
src = imread("D:2222.jpg", IMREAD_UNCHANGED);
if(src.empty())
{
cout << "could not read image\n" << endl;
return -1;
}
nameWindos("Input image", WINDOW_AUTOSIZE);
imshow("Input image", src);
cvtColor(src, des, COLOR_BGR2HLS);
imwrite("D:1234.png", src);
waitKey(0);
5、如何获取图像的像素指针:
获取当前行指针:const uchar* current = myImage.prt(row);
row表示第几行;
获取当前像素点p(row, col)的像素值p(row, col) = current[col];
6、图像像素范围处理saturate_cast
saturate_cast(-100),返回0
saturate_cast(288),返回255
saturate_cast(100),返回100
该函数的功能是确保RGB值范围是在0-255;
7、掩膜操作是什么:
根据掩膜来重新计算每个像素的像素值,掩膜mask也被称为Kernel;
通过掩膜操作来提高图像的对比度;
演示代码:
Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dst, src.depth(), kernel);
nameWindos(“Input image”, WINDOW_AUTOSIZE);
imshow(“Input image”, src);
waitKey(0);
8、Mat对象是什么:
Mat对象是OpenCV2.0之后引入的图像数据结构、自动分配内存、不存在内存泄漏的问题、是面向对象的数据结构,分为头部和数据两部分;
9、Mat对象的构造函数和常用方法是什么:
Mat(); Mat(int rows, int cols, int type); Mat(Size size, int type);
void copyTo(Mat mat) 将当前Mat对象复制到另外一个对象
void convertTo(Mat dst, int type)
Mat clone() 将当前Mat对象克隆给另外一个对象
int channels() 当前对象通道数
int depth() 当前对象的深度
bool empty(); 当前对象图像数据是否为空
uchar* ptr(i=0) 当前对象像素指针
Mat creat(src.size(), src.type()); 创建一个和src对象大小和类型一样的对象
(1)相关API:
参数1:输入图像Mat-src1
参数2:输入图像src1的alpha值
参数3:输入图像Mat-src2
参数4:输入图像src2的alpha值
参数5:gamma值
参数6:输出混合图像
注:两张图像的大小和类型必须一致才可以
(2)示例代码:
Mat src1, src2, dest;
src1 = imread("D:/vcprojects/images/LinuxLogo.jpg");
src2 = imread("D:/vcprojects/images/win7logo.jpg");
if (!src1.data)
{
printf("could not load LinuxLogo image...\n");
return -1;
}
if (!src2.data)
{
printf("could not load win7logo image...\n");
return -1;
}
if (src1.rows == src2.rows && src1.cols == src2.cols)
{
double alpha = 0.5;
namedWindow("line-blend", CV_WINDOW_AUTOSIZE);
addWeighted(src1, (1 - alpha), src2, alpha, 0.0, dest);
imshow("line-blend", dest);
waitKey(0);
return 0;
}
else
{
printf("image size is not same...\n");
return -1;
}
(1)相关API cv::Point cv::Scalar
Point表示2D平面上一个点x,y
Point p;
p.x = 10;
p.y = 8;
p = Point(10, 8);
Scalar表示四个元素的向量
Scalar(a, b, c); //a = blue, b = green, c = red表示RGB三个通道
(2)如何绘制线、矩形、圆、椭圆等基本几何形状
画线 cv::line (LINE_4\LINE_8\LINE_AA)
画椭圆 cv::elipse
画矩形 cv::rectangle
画圆 cv::circle
画填充 cv::fillPoly
(3)如何生成随机数
cv::RNG
生成高斯随机数gaussian(double sigma)
生成正态分布随机数uniform(int a, int b)
(4)如何添加文字
putText函数中设置fontFace(cv::HersheyFonts)
-fontFace, CV_FONT_HERSHEY_PLAIN
-fontScale, 1.0, 2.0~8.0
7、代码演示
#include
#include
using namespace std;
using namespace cv;
Mat bgImage;
const char* drawdemo_win = "draw shapes and text demo";
void MyLines(); //画线
void MyRectangle(); //画矩形
void MyEllipse(); //画椭圆
void MyCircle(); //画圆
void MyPolygon(); //画多边形
void RandomLineDemo(); //画自由线
int main(int argc, char** argv) {
bgImage = imread("D:/vcprojects/images/test1.png");
if (!bgImage.data) {
printf("could not load image...\n");
return -1;
}
MyLines();
MyRectangle();
MyEllipse();
MyCircle();
MyPolygon();
putText(bgImage, "Hello OpenCV", Point(300, 300), CV_FONT_HERSHEY_COMPLEX, 1.0, Scalar(12, 23, 200), 3, 8);
namedWindow(drawdemo_win, CV_WINDOW_AUTOSIZE);
imshow(drawdemo_win, bgImage);
RandomLineDemo();
waitKey(0);
return 0;
}
void MyLines() {
Point p1 = Point(20, 30);
Point p2;
p2.x = 400;
p2.y = 400;
Scalar color = Scalar(0, 0, 255);
line(bgImage, p1, p2, color, 1, LINE_AA);
}
void MyRectangle() {
Rect rect = Rect(200, 100, 300, 300);
Scalar color = Scalar(255, 0, 0);
rectangle(bgImage, rect, color, 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);
}
void MyCircle() {
Scalar color = Scalar(0, 255, 255);
Point center = Point(bgImage.cols / 2, bgImage.rows / 2);
circle(bgImage, center, 150, color, 2, 8);
}
void MyPolygon() {
Point pts[1][5];
pts[0][0] = Point(100, 100);
pts[0][1] = Point(100, 200);
pts[0][2] = Point(200, 200);
pts[0][3] = Point(200, 100);
pts[0][4] = Point(100, 100);
const Point* ppts[] = { pts[0] };
int npt[] = { 5 };
Scalar color = Scalar(255, 12, 255);
fillPoly(bgImage, ppts, npt, 1, color, 8);
}
void RandomLineDemo() {
RNG rng(12345);
Point pt1;
Point pt2;
Mat bg = Mat::zeros(bgImage.size(), bgImage.type());
namedWindow("random line demo", CV_WINDOW_AUTOSIZE);
for (int i = 0; i < 100000; i++) {
pt1.x = rng.uniform(0, bgImage.cols);
pt2.x = rng.uniform(0, bgImage.cols);
pt1.y = rng.uniform(0, bgImage.rows);
pt2.y = rng.uniform(0, bgImage.rows);
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
if (waitKey(50) > 0) {
break;
}
line(bg, pt1, pt2, color, 1, 8);
imshow("random line demo", bg);
}
}
第八课、模糊图像一
(1)模糊原理是什么:
Smooth/blur是图像处理中最简单和常用的操作之一;
为了给图像预处理时降低噪声;
Smooth和blur操作使用了卷积计算,使用均值滤波和高斯滤波;
均值滤波:blur(Mat src, Mat dst, Size(xradius, yradius), Point(-1,-1));
高斯滤波:GaussianBlur(Mat src, Mat dst, Size(11, 11), sigmax, sigmay);
其中Size(x, y), x, y 必须是正数而且是奇数;
(2)实例代码:
#include
#include
using namespace cv;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("D:/vcprojects/images/test.png");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
char input_title[] = "input image";
char output_title[] = "blur image";
namedWindow(input_title, CV_WINDOW_AUTOSIZE);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow(input_title, src);
blur(src, dst, Size(11, 11), Point(-1, -1)); //均值滤波
imshow(output_title, dst);
Mat gblur;
GaussianBlur(src, gblur, Size(11, 11), 11, 11); //高斯滤波
imshow("gaussian blur", gblur);
waitKey(0);
return 0;
}
第九课、图像模糊二
(1)中值滤波是什么:
统计排序滤波器;
中值对椒盐噪声有很好的抑制作用;
(2)双边滤波是什么:
边缘保留的滤波算法,避免了边缘信息丢失,保留了图像轮廓不变;
中值模糊medianBlur(Mat src, Mat dest, ksize);
双边模糊bilateralFilter(src, dest, d=15, 150, 3);
(3)代码演示
#include
#include
using namespace cv;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("D:/vcprojects/images/cvtest.png");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
//medianBlur(src, dst, 3);
bilateralFilter(src, dst, 15, 100, 5); //双边滤波
namedWindow("BiBlur Filter Result", CV_WINDOW_AUTOSIZE);
imshow("BiBlur Filter Result", dst);
Mat resultImg;
Mat kernel = (Mat_<int>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(dst, resultImg, -1, kernel, Point(-1, -1), 0); //掩膜操作,用于提高图像对比度
imshow("Final Result", resultImg);
waitKey(0);
return 0;
}
第十课、膨胀与腐蚀
(1)形态学操作—膨胀是什么:
基于形状的一系列图像处理操作的合集,主要上基于集合论基础上的形态学数学;
形态学有四个基本操作:腐蚀、膨胀、开、闭;
膨胀和腐蚀是形态学操作中最常用的形态学操作手段;
膨胀是用最大像素值替换锚点值;
腐蚀是用最小像素值替换锚点值;
getStructuringElement(int shape, Size ksize, Point anchor)
- 形状 (MORPH_RECT \MORPH_CROSS \MORPH_ELLIPSE)
- 大小 - 锚点 默认是Point(-1, -1)意思就是中心像素
dilate(src, dst, kernel) ;
erode(src, dst, kernel);
(2)实例演示:
#include
#include
using namespace cv;
int main(int argc, char** argv) {
Mat src, dest;
src = imread("D:/vcprojects/images/cvtest.png");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
char INPUT_WIN[] = "input image";
char OUTPUT_WIN[] = "outout image";
namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
//dilate
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
//dilate(src, dest, kernel); //腐蚀
//erosion
erode(src, dest, kernel); //膨胀
imshow(INPUT_WIN, src);
imshow(OUTPUT_WIN, src);
waitKey(0);
return 0;
}
第十一课、形态学操作—开与闭
(1)开操作—open:
先腐蚀后膨胀
可以去掉小的对象,假设对象是前景色,背景是黑色;
(2)闭操作—close:
先膨胀后腐蚀(bin2)
可以填充小的洞(fill hole),假设对象是前景色,背景是黑色;
(3)形态学梯度–Morphological Gradient
又称为基本梯度(其它还包括-内部梯度、方向梯度)
(4)顶帽—top hat是什么:
顶帽是原图像和开操作之间的差值图像;
(5)黑帽是什么:
闭操作图像与源图像的差值图像;
(6)morphologyEx(src, dest, CV_MOP_BLACKHAT, kernel);
- Mat src – 输入图像 - Mat dest – 输出结果
- int OPT – CV_MOP_OPEN/ CV_MOP_CLOSE/ CV_MOP_GRADIENT / CV_MOP_TOPHAT/ CV_MOP_BLACKHAT
形态学操作类型 Mat kernel 结构元素 int Iteration 迭代次数,默认是1
(7)实例代码:
#include
#include
#include
using namespace cv;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("D:/vcprojects/images/bin2.png");
if (!src.data) {
printf("could not load image...\n");
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
char output_title[] = "morphology demo";
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
Mat kernel = getStructuringElement(MORPH_RECT, Size(11, 11), Point(-1, -1));
morphologyEx(src, dst, CV_MOP_BLACKHAT, kernel);
imshow(output_title, dst);
waitKey(0);
return 0;
}
第十二课、形态学操作应用—提取水平和垂直线
(1)原理方法是什么:
通过自定义的结构元素实现结构元素对输入图像一些对象敏感、另外一些对象不敏感,这样就会让敏感的对象改变而不敏感的对象保留输出;
膨胀:输出的像素值是结构元素覆盖下输入图像的最大像素值;
腐蚀:输出的像素值是结构元素覆盖下输入图像的最小像素值;
(2)提取步骤是什么:(主要用于提取一张图像中的关键部分,去除一些图像干扰,让图像看起来更干净)
输入图像彩色图像imread;
转换为灰度图像—cvtColor;
转换为二值图像—adaptiveThreshold;
定义结构元素;
开操作(腐蚀+膨胀)提取水平与垂直线;
(3)实例代码:
第十三课、图像上采样和降采样
(1)图像金字塔是什么:
一个图像金字塔是一系列图像组成,最底下一张是图像尺寸最大,最上方图像尺寸最小,从上往下看就像一个古代的金字塔;
高斯金字塔是用来对图像进行降采样;
拉普拉斯金字塔用来重建一张图片根据它的上层降采样图片;
(2)高斯金字塔是什么:
从底向上逐层降采样得到;
降采样之后图像大小是原图像MxN的M/2 x N/2,就是对原图像删除偶数行与列,即得到降采样之后上一层的图片;
高斯金字塔的生成过程分为 对当前层的偶数行与列,删除当前层的偶数行与列;
即可得到上一层的图像,这样上一层跟下一层相比,都只有它的1/4大小;
(3)高斯不同是什么:
把同一张图像在不同的参数下做高斯模糊之后的结果相减,得到的输出图像;
高斯不同是图像的内在特征,在灰度图像增强、角点检测中经常用到;
(4)采样相关API是什么:
上采样:(cv::pyrUp)—zoom in放大
降采样:(cv::pyrDown)—zoom out缩小
pyrUp(Mat src, Mat dst, Size(src.cols2, src.rows2))生成的图像是原图在宽与高各放大两倍;
pyrDown(Mat src, Mat dst, Size(src.cols/2, src,rows/2));生成的图像是原图在宽与高各缩小1/2;
(5)示例代码:
第十四课、基本阈值操作
22、图像阈值是什么:
图像分割的标尺
23、阈值类型是什么:
(1)阈值二值化(threshold binary)
下方的图表示图像像素点Src(x, y)值分布情况,蓝色水平线表示阈值;
(2)阈值反二值化(threshold binary Inverted)
左下方的图表示图像像素点Src(x,y)值分布情况,蓝色水平线表示阈值
(3)截断(truncate)
左下方的图表示图像像素点Src(x,y)值分布情况,蓝色水平线表示阈值
(4)阈值取0(threshold to zero)
左下方的图表示图像像素点Src(x,y)值分布情况,蓝色水平线表示阈值
(5)阈值反取零 (threshold to zero inverted)
左下方的图表示图像像素点Src(x,y)值分布情况,蓝色水平线表示阈值
24、示例代码:
第十五课、自定义线性滤波
25、卷积概念是什么:
卷积是图像处理中的一个操作,是kernel在图像的每个像素上的操作;
Kernel本质上一个固定大小的矩阵数组,其中心点称为锚点(anchor point);
卷积和也可以称为算子;
把Kernel放到像素数组之上,求锚点周围覆盖的像素乘积之和(包括锚点),用来替换锚点覆盖下像素点值称为卷积处理,数学表达式如下:
Sum = 8x1+6x1+6x1+2x1+8x1+6x1+2x1+2x1+8x1
New pixel = sum / (m*n)
26、常见的算子有哪些:
Robert算子:
Sobel:
拉普拉斯算子:
27、自定义卷积模糊:(模糊图像的目的是降噪)
filter2D方法filter2D(Mat src, //输入图像
Mat dst, // 模糊图像
int depth, // 图像深度32/8
Mat kernel, // 卷积核/模板
Point anchor, // 锚点位置
double delta // 计算出来的像素+delta
)
其中 kernel是可以自定义的卷积核
卷积的作用是什么:
模糊图像
提取边缘
图像锐化
28、代码演示:
第十六课、边缘处理
29、为什么要边缘处理:
图像卷积的时候边界像素,不能被卷积操作,原因在于边界像素没有完全跟kernel重叠,所以当3X3滤波时候有1个像素的边缘没有被处理,5X5时有2个像素的边缘没有被处理;
30、边缘处理的方法是什么:
在卷积开始之前增加边缘像素,填充的像素值为0或者RGB黑色,比如3X3在四周各填充1个像素的边缘,这样可以确保图像的边缘能够被处理,在卷积处理之后去掉这些边缘;
openCV默认处理方法是:BORDER_DEFAULT
BORDER_CONSTANT—填充边缘用指定像素值
BORDER_REPLICATE—填充边缘像素用已知的边缘像素值
BORDER_WRAP—用另外一边的像素来补偿填充;
API函数:copyMakeBorder(
- Mat src, // 输入图像
- Mat dst, // 添加边缘图像
- int top, // 边缘长度,一般上下左右都取相同值,
- int bottom,
- int left,
- int right,
- int borderType // 边缘类型
- Scalar value )
31、代码演示:
第十七课、Sobel算子
32、卷积应用—图像边缘处理是什么:
边缘是像素值发生跃迁的地方,是图像的显著特征之一,在图像特征提取、对象检测、模式识别等方面都有重要作用;
如何捕捉/提取边缘—对图像求它的一阶导数 delta = f(x) = f(x-1),delta越大,说明像素在x方向变化越大,边缘信号越强;
33、Sobel算子是什么:
离散微分算子(dicrete differentiation operator),用来计算图像灰度的近似梯度;
Sobel算子功能集合高斯平滑和微分求导;
又称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像X方法与Y方法梯度图像;
水平梯度:
垂直梯度:
最终图像梯度:
求取导数的近似值,kernel=3时不是很准确,OpenCV使用改进版本Scharr函数,算子如下:
应用步骤:
高斯模糊图像
把图像变为灰度图像
用Sobel算子求x和y方向的图像
调用addWeight混合两张图像
34、相关API说明:
相关API说明:cv::Sobel (InputArray Src // 输入图像
OutputArray dst// 输出图像,大小与输入图像一致
int depth // 输出图像深度.
Int dx. // X方向,几阶导数
int dy // Y方向,几阶导数.
int ksize, SOBEL算子kernel大小,必须是1、3、5、7、
double scale = 1
double delta = 0
int borderType = BORDER_DEFAULT )
API说明::cv::Scharr
cv::Scharr (InputArray Src // 输入图像
OutputArray dst// 输出图像,大小与输入图像一致
int depth // 输出图像深度.
Int dx. // X方向,几阶导数
int dy // Y方向,几阶导数.
double scale = 1
double delta = 0
int borderType = BORDER_DEFAULT )
其他API说明:
GaussianBlur(src, dst, Size(3, 3), 0, 0, BORDER_DEFAULT);
cvtColor(src, gray, COLOR_RGB2GRAY);
addWeighted(A, 0.5, B, 0.5, 0, AB);
converScaleAbs(A, B); //计算图像A的像素绝对值,输出到图像B
35、代码演示:
第十八课、Laplance算子
36、Laplance算子是什么:
在二阶求导时,最大变化处的值为0即边缘是0,通过二阶导数计算,依据此理论可以计算图像二阶导数,提取边缘;
37、拉普拉斯算子相关的API是什么:
相关API:cv::Laplance
Laplacian(InputArray src,
OutputArray dst,
int depth, //深度CV_16S
int kisze, // 3
double scale = 1,
double delta =0.0,
int borderType = 4 )
处理步骤:高斯模糊—去噪声GaussianBlur()
转换为灰度图像cvtColor()
拉普拉斯—二阶导数计算Laplacian()
取绝对值convertScaleAbs()
显示结果
38、示例代码:
第十九课、Canny边缘检测
39、Canny算法是什么:
Canny是边缘检测算法, 是一个很好的边缘检测
实用的图像处理方法
40、Canny算法实现步骤:
高斯模糊—GaussianBlur
灰度转换—cvtColor
计算梯度—Sobel/Scharr
非最大信号抑制
高低阈值输出二值图像
41、非最大信号抑制是什么:
42、高低阈值输出二值图像
TI、R2为阈值,凡是高于T2的都保留,凡是小于T1都丢弃,从高于T2的像素出发,凡是大于T1而且相互连接的,都保留,最终得到一个输出二值图像;
推荐的高低阈值比值为T2:T1 = 3:/2:1,其中T2为高阈值,T1为低阈值;
43、相关API
Canny(InputArray src, // 8-bit的输入图像
OutputArray edges,// 输出边缘图像, 一般都是二值图像,背景是黑色
double threshold1,// 低阈值,常取高阈值的1/2或者1/3
double threshold2,// 高阈值
int aptertureSize,// Soble算子的size,通常3x3,取值3
bool L2gradient // 选择 true表示是L2来归一化,否则用L1归一化 )
44、代码演示:
第二十课、霍夫变换—直线
45、霍夫直线变换是什么:
Hough Line Transform用来做直线检测
前提条件—边缘检测已经完成
平面空间到极坐标空间转换
对于任意一条直线上的所有点来说,变换到极坐标中,从[0~360]空间可以得到r的大小,属于同一条直线上点在极坐标空(r,theta),必然在一个点上有最强的信号出现,根据此反算到平面坐标中就可以得到直线上各点的像素坐标,从而得到直线;
46、从平面坐标变换到霍夫空间(极坐标)
47、相关API:
标准的霍夫变换cv::HoughLines从平面坐标转换到霍夫空间,最终输出是表示极坐标空间
霍夫变换直线概率cv::HoughLinesP最终输出是直线的两个点
cv::HoughLines(InputArray src, // 输入图像,必须8-bit的灰度图像
OutputArray lines, // 输出的极坐标来表示直线
double rho, // 生成极坐标时候的像素扫描步长
double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180
int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线
double srn=0;// 是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换
double stn=0;//是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换
double min_theta=0; // 表示角度扫描范围 0 ~180之间, 默认即可
double max_theta=CV_PI ) // 一般情况是有经验的开发者使用,需要自己反变换到平面空间
cv::HoughLinesP(InputArray src, // 输入图像,必须8-bit的灰度图像
OutputArray lines, // 输出的极坐标来表示直线
double rho, // 生成极坐标时候的像素扫描步长
double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180
int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线
double minLineLength=0;// 最小直线长度
double maxLineGap=0;// 最大间隔 )
HoughLinesP检测效果
48、代码演示:
先进行单元检测:
霍夫直线检测:
第二十一课、霍夫圆变换
49、霍夫圆检测原理是什么:
从平面坐标到极坐标转换三个参数
假设平面坐标的任意一个圆上的点,转换到极坐标中:处有最大值,霍夫变换正式利用这个原理实现圆的检测;
50、相关API:
cv::HoughCircles
HoughCircles(InputArray image, // 输入图像 ,必须是8位的单通道灰度图像
OutputArray circles, // 输出结果,发现的圆信息
Int method, // 方法 - HOUGH_GRADIENT
Double dp, // dp = 1;
Double mindist, // 10 最短距离-可以分辨是两个圆的,否则认为是同心圆- src_gray.rows/8
Double param1, // canny edge detection low threshold
Double param2, // 中心点累加器阈值 – 候选圆心
Int minradius, // 最小半径
Int maxradius//最大半径 )
因为霍夫圆检测对噪声比较敏感,所以首先要对图像做中值滤波;
基于效率考虑,OpenCV中实现的霍夫变换圆检测是基于图像梯度的实现,分为两步:
(1)检测边缘,发现可能的圆心;
(2)基于第一步的基础上从候选圆心开始计算最佳半径大小
51、代码演示:
第二十二课、像素重映射
52、像素重映射是什么:
把输入图像中各个像素按照一定的规则映射到另外一张图像的对应位置上去,形成一张新的图像;
g(x,y)是重映射之后的图像,h(x,y)是功能函数,f是源图像
53、相关API:
Remap(InputArray src,// 输入图像
OutputArray dst,// 输出图像
InputArray map1,// x 映射表 CV_32FC1/CV_32FC2
InputArray map2,// y 映射表
int interpolation,// 选择的插值方法,常见线性插值,可选择立方等
int borderMode,// BORDER_CONSTANT
const Scalar borderValue// color )
缩小一半
X方向对调
Y方向对调
XY方向同时对调
54、代码演示:
第二十三课、直方图均衡化
55、直方图(Histogram)是什么:
图像直方图是指堆整个图像在灰度范围内的像素值(0~255)统计出现频率次数,据此生成的直方图,称为图像直方图-直方图,反映了图像灰度的分布情况,是图像的统计学特征;
57、直方均衡化是什么:
一种提高图像对比度的方法,拉伸图像灰度值范围;
将图像灰度分布从一个分布映射到另外一个分布,然后再得到映射后的像素值即可;
58、相关API:
cv::equalizeHist
equalizeHist(InputArray src,//输入图像,必须是8-bit的单通道图像
OutputArray dst// 输出结果 )
59、代码演示:
第二十四课、直方图计算
60、直方图是什么:
上述直方图概念是基于图像像素值,其实对图像梯度,每个像素的角度,等一切图像的属性值,我们都可以建立直方图,基于图像像素灰度直方图是最常见的;
直方图常见的几个属性:
dims—表示维度,对灰度图像来说只有一个通道值dims=1
dins—表示在维度中子区域大小划分,bins=256,划分为256个级别
range—表示值的范围,灰度值范围为[0-255]之间;
61、相关API
split(// 把多通道图像分为多个单通道图像
const Mat &src, //输入图像
Mat* mvbegin)// 输出的通道图像数组
calcHist(
const Mat* images,//输入图像指针
int images,// 图像数目
const int* channels,// 通道数
InputArray mask,// 输入mask,可选,不用
OutputArray hist,//输出的直方图数据
int dims,// 维数
const int* histsize,// 直方图级数
const float* ranges,// 值域范围
bool uniform,// true by default
bool accumulate// false by defaut )
62、代码演示:
第二十五课、直方图比较
63、直方图比较方法是什么:
对输入的两张图像计算得到直方图H1与H2,归一化到相同的尺度空间然后可以通过计算H1与H2之间的距离得到两个直方图的相似程度进而比较图像本身的相似程度,OpenCV提供的比较方法有四种:
Correlation相关性比较
Chi-Square卡方比较
Intersection十字交叉性
Bhattacharyya distance巴氏距离
64、相关性计算(CV_COMP_CORREL)
其中,其中N是直方图的BIN个数,
65、卡方计算(CV_COMP_CHISQR)
H1,H2分别表示两个图像直方图数据
66、十字计算(CV_COMP_INTERSECT)
H1,H2分别表示两个图像的直方图数据
67、巴氏距离计算(CV_COMP_BHATTACHARYYA)
68、相关API:
首先把图像从RGB色彩空间转换到HSV色彩空间 cvtColor
计算图像的直方图,然后归一化到[0-1]之间calcHist和normalize
使用上述四种比较方法之一进行比较compareHist
compareHist(InputArray h1, // 直方图数据,下同
InputArray H2,
int method// 比较方法,上述四种方法之一 )
69、演示代码:
加载图像数据:
从RGB空间转换到HSV空间:
计算直方图并归一化
比较直方图,并返回值
第二十六课、直方图反向投影(Back Project)
70、反向投影是什么:
反向投影是反映直方图模型在目标图像中的分布情况
简单点说就是用直方图模型去目标图像中寻找是否相似的对象,通常用HSV色彩空间的HS两个通道直方图模型
71、反向投影的步骤是什么:
建立直方图模型
计算待测图像直方图并映射到模型中
从模型反向计算生成图像
72、反射投影的实现步骤与相关API
加载图片imread
将图像从RGB色彩空间转换到HSV色彩空间cvtColor
计算直方图和归一化calcHist与normalize
Mat与MatND其中Mat表示二维数组,MatND表示三维或者多维数据,此处均可以用Mat表示;
计算反向投影图像—calcBackProject
73、演示代码:
第二十七课、模板匹配(Template Match)
74、模板匹配是什么:
在整个图像区域发现与给定子图像匹配的小块区域
所以模板匹配首先需要一个模板图像T(给定的子图像)
另外需要一个待检测的图像—源图像S
工作方法,在带检测图像上,从左到右,从上向下计算模板图像与重叠子图像的匹配度,匹配程度越大,两者相同的可能性越大
75、匹配算法有哪些:
计算平方不同
计算相关性
计算相关系数
计算归一化平方不同
计算归一化相关性
计算归一化相关系数
76、相关API:
matchTemplate( InputArray image,// 源图像,必须是8-bit或者32-bit浮点数图像
InputArray templ,// 模板图像,类型与输入图像一致
OutputArray result,// 输出结果,必须是单通道32位浮点数,假设源图像WxH,模板 //图像wxh, 则结果必须为W-w+1, H-h+1的大小。
int method,//使用的匹配方法
InputArray mask=noArray()//(optional)
)
77、代码演示
第二十八课、轮廓发现(find contour in your image)
78、轮廓发现是什么:
基于图像边缘提取的基础寻找对象轮廓的方法,所以边缘提取的阈值选定会影响最终轮廓发现结果
79、相关API:
findContours发现轮廓
drawContours绘制轮廓
在二值图像上发现轮廓使用API cv::findContours(InputOutputArray binImg, // 输入图像,非0的像素被看成1,0的 //像素值保持不变,8-bit
OutputArrayOfArrays contours,// 全部发现的轮廓对象 OutputArray, hierachy// 图该的拓扑结构,可选,该轮廓发现算法正是基于图像拓扑结构实现。
int mode, // 轮廓返回的模式 int method,// 发现方法
Point offset=Point()// 轮廓像素的位移,默认(0, 0)没有位移 )
在二值图像上发现轮廓使用API cv::findContours之后对发现的轮廓数据进行绘制显示
drawContours( InputOutputArray binImg, // 输出图像
OutputArrayOfArrays contours,// 全部发现的轮廓对象
Int contourIdx// 轮廓索引号
const Scalar & color,// 绘制时候颜色
int thickness,// 绘制线宽
int lineType ,// 线的类型LINE_8
InputArray hierarchy,// 拓扑结构图
int maxlevel,// 最大层数, 0只绘制当前的,1表示绘制绘制当前及其内嵌的轮廓
Point offset=Point()// 轮廓位移,可选
80、使用步骤:
输入图像转为灰度图像cvtColor
使用Canny进行边缘提取,得到二值图像
使用findContours寻找轮廓
使用drawContours绘制轮廓
81、代码演示
第二十八课、凸包(Convex Hull)
82、凸包是什么:
在一个多边形边缘或者内部任意两个点的连线都包含再多边形边界或者内部
包含点集合S中所有点的最小凸多边形
检测算法,Graham扫描法
83、
Graham扫描算法是什么:
首先选择Y方向最低的点作为起始点p0
从P0开始极坐标扫描,依次添加p1…pn(排序顺序是根据极坐标的角度大小,逆时针方向)
对每个点pi来说,如果添加pi点到凸包中导致一个左转向(逆时针方法)则添加该点到凸包,反之如果导致一个右转向(顺时针方向)删除该点从凸包,反之如果到孩子一个右转向(顺时针方向)删除该点从凸包中
84、API说明
convexHull(InputArray points,// 输入候选点,来自
findContours OutputArray hull,// 凸包
bool clockwise,// default true, 顺时针方向
bool returnPoints)// true 表示返回点个数,如果第二个参数是
//vector则自动忽略
首先把图像从RGB转为灰度
然后再转为二值图像
在通过发现轮廓得到候选点
凸包API调用
绘制显示
85、代码显示:
第二十九课、轮廓周围绘制矩形框和圆形框
86、相关API
approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)
基于RDP算法实现,目的是减少多边形轮廓点数
87、轮廓周围绘制矩形相关API
cv::boundingRect(InputArray points)得到轮廓周围最小矩形左上交点坐标和右下角点坐标,绘制一个矩形
cv::minAreaRect(InputArray points)得到一个旋转的矩形,返回旋转矩形
88、轮廓周围绘制圆和椭圆
cv::minEnclosingCircle(InputArray points, //得到最小区域圆形
Point2f& center, // 圆心位置
float& radius)// 圆的半径
cv::fitEllipse(InputArray points)得到最小椭圆
首先将图像变为二值图像
发现轮廓,找到图像轮廓
通过相关API在轮廓点上找到最小包含矩形和圆,旋转矩形与椭圆
绘制它们
89、代码演示:
第三十一课、图像矩(Image Moments)
90、矩是什么:
几何矩:
中心矩:
中心归一矩:
图像中心Center(x0, y0)
91、相关API:
moments{
InputArray array; //输入数据
bool binaryimage = false; //是否为二值图像
}
contourArea{
InputArray contout; //输入轮廓数据
bool oriented; //默认false、返回绝对值
}
arcLength{
InputArray curve; //输入曲线数据
bool closed; //是否是封闭曲线
}
92、实现步骤:
提取图像边缘
发现轮廓
计算每个轮廓对象的矩
计算每个对象的中心、弧长、面积
93、代码演示: