零cpp基础的小白探索OpenCV从从入门到放弃的摸鱼记录从这里开始。
参考书:《OpenCV3编程入门》毛星云、冷雪飞 等编著 电子工业出版社
一个开源的机器视觉、图像处理的SDK(Software Development Kit / 软件开发工具包),支持C、C++、Python、Ruby等多种编程语言。
OpenCV核心组件,核心功能模块。包含基本数据结构(如Mat、Rect等)、基本绘图操作、像素操作、ROI设置、图像混合、DFT(Discrete Fourier Transform)等
OpenCV图像处理组件。包括图像滤波、直方图、特征检测、图像变换等等
OpenCV高层GUI图形用户界面模块。包括图像载入、显示、写入、滑动条、鼠标操作等
此头文件定义包括以上三个在内的多个头文件,为了简化代码使用。本小白入门被建议不使用它。
OpenCV中图像储存的类,实为矩阵。由矩阵头(包括矩阵尺寸、存储方法、存储地址等信息)和一个指向存储所有像素的矩阵的指针两个部分组成。因此 Mat类在复制上有一个需要注意的点,赋值运算符和拷贝构造函数只复制信息头,并不复制图像本身储存信息。如
Mat A,C;
A = imread("1.jpg",CV_LOAD_IMAGE_COLOR);
Mat B (A); //拷贝构造函数
C = A; //赋值运算符
以上A、B、C最终都指向同一个也是唯一一个数据矩阵。虽然信息头不同,但通过任何一个对象所做的改变也会影响其他对象。真想要复制应使用Mat的成员函数,如下
Mat F = A.clone();
Mat G;
A.copyTo(G);
这样使用,改变F或者G就不会影响Mat信息头所指向的矩阵了。
Mat有多个非常有用的常用成员函数:
M.cols 返回矩阵列数
M.rows 返回矩阵行数
M.total() 返回矩阵元素数(不考虑多通道)
M.channels() 返回矩阵通道数
M.size() 以size类返回矩阵的尺寸
M.at 对矩阵元素进行访问
包括上面提及的.clone()和.copyTo等等,更多实用成员函数有待深入了解。
表示坐标中一个点的类型。Point2i和Point_
//方法一
Point point;
point.x = 10;
point.y = 8;
//方法二
Point point = Point(10,8);
表示具有四个元素的数组,在OpenCV中用于传递像素值。
Scalar(a,b,c,d);
其中a、b、c分别表示BGR分量(就是反过来的),d表示alpha通道分量。
在OpenCV中用于表示尺寸的一个类,其两个重要的数据成员:width、heght 两个分表表示宽度和高度。
表示一个矩形的类。成员变量有x、y、width、height分别表示左上角的点横坐标、纵坐标、矩形的宽度、高度。
Rect类常用的成员函数有:
rect.Size() //返回矩形的尺寸
rect.area() //返回矩形的面积
rect.contains(Point) //判断点是否在矩形内
rect.inside(Rect) //判断矩形是否在该矩形内
rect.tl //返回左上角坐标
rect.br //返回右下角坐标
矩形交集并集操作:
Rect rect = rect1 | rect2; //并集
Rect rect = rect1 & rect2; //交集
矩形平移操作:
Rect rectShift = rect + point;
矩形缩放操作:
Rect rectScale = rect + size;
颜色空间转换函数,使用格式:
cvtColor(inimg,outimg,CV_GRAY2BRG)
第一个参数为输入图像,第二个参数为输出图像,第三个参数为标识符,表示转换的目标颜色空间,查表可得。
任务:背景虚化功能。实时处理操作,圆圈外背景模糊,圆圈内保持清晰不变,圆圈位置和大小可以改变。
个人思路:鼠标操作确定圆心,满足在半径范围内的点像素值不变,其他的像素值用均值滤波后的数值替代。
#include //OpenCV核心组件(Mat Point Rect etc.)
#include //读写展示图像 、窗口组件
#include //图像处理组件
#include //cin、cout头文件
#include //包含clock_t类头文件
using namespace cv; //指定OpenCV的命名空间
Mat img,temp;
int radius = 80,value = 5,k; //初始化半径80个像素,平均滤波算子size为5
clock_t t1,t2;
void on_Trackbar(int,void*) //滑条回调函数
{
k = value;
}
Mat my_blur(int x,int y) //圈外虚化处理函数
{
Mat imgblur;
img.copyTo(imgblur);
blur(img,imgblur,Size(k,k));
//GaussianBlur(img,imgblur,Size(5,5),25,25);
Point center(x,y); //定义点center 赋初值x,y
for(int m = 1; m <= img.cols; m++)
for (int n = 1; n <= img.rows; n++) //m为列/x坐标,n为行/y坐标
{
if( ((m-x) * (m-x) + (n-y) * (n-y))<= (radius * radius)) //圈内用原像素值替换
{
// imgblur.at(Point(m, n))[0] = temp.at(Point(m, n))[0] ; // B分量
// imgblur.at(Point(m, n))[1] = temp.at(Point(m, n))[1] ; // G分量(用法1) point(x坐标/列,y坐标/行)
// imgblur.at(Point(m, n))[2] = temp.at(Point(m, n))[2] ; // R分量
imgblur.at(n,m)[0] = temp.at(n,m)[0] ; // B分量
imgblur.at(n,m)[1] = temp.at(n,m)[1] ; // G分量(用法2)
imgblur.at(n,m)[2] = temp.at(n,m)[2] ; // R分量
}
}
circle(imgblur,center,radius,Scalar(255,255,255));//circle(图,圆心点(Point),半径,填充颜色(Scaler),线粗)画圆函数,线粗缺省默认为1
return imgblur;
}
void function(int event,int x,int y, int flags, void* param) //鼠标操作回调函数
{
Point center = Point(x,y);
if ((flags & CV_EVENT_FLAG_CTRLKEY) && event == EVENT_LBUTTONDOWN) //ctrl+左键,则半径+10后显示
{
t1 = clock();
img.copyTo(temp);
radius += 10;
temp = my_blur(x,y);
t2 = clock(); //计时 clock()程序开始到调用次函数经过的计时单元数
std::cout<<(double)(t2-t1)/CLOCKS_PER_SEC<
平均滤波模板8X8
平均滤波模板20X20,明显变得更模糊
平均滤波模板20X20,半径变大
平均滤波模板20X20,半径变小