一:调用摄像头的操作。
#include <opencv.hpp>//opencv 的头文件
#include <iostream>
using namespace cv;
using namespace std;
void main(){
Mat Frame;//创建一个Mat 对象,是一个矩阵。
VideoCapture cap(0);//读摄像头文件,0代表电脑摄像头,1,2,代表USB的。也可以是路径,表示一个文件位置。
while(true)
{
cap>>Frame;//cap类似c++中的cin,cap读取一帧图像保存在frame中,后一个参数为0表示可以调节窗口大小。若为1表示不可以。
imshow("frame",Frame);//把Frame矩阵中的内容显示出来。第一个参数表示窗口名称
waitKey(10);//等待10毫秒,为0表示无限延迟。
}
二:使用opencv读取一张图片。图片要放在工程文件夹里。
Mat impgrag=imread("124.jpg",1);//读一张名为“123”的图片,存入矩阵中。后一个参数为1表示RGB三通道,为0为灰度图。
cvtColor(impgrag,impgrag,CV_RGB2GRAY);//用于转换颜色,有四个参数,第一个为读取的矩阵名称,第二个为输出矩阵名称,第三个表示转换为灰度图。
imshow("124",impgrag);//显示图片
waitKey(0);
cout<<(int)impgrag.at<uchar>(1,1)<<endl;//读取第一行第一列的像素值,并转化为int输出。
注:
关于灰度图和彩色图:
灰度图是单通道存储,值为0~255
- 彩色图是三通道存储,即 R(red) G(green) B(blue)
- 需要注意的是在图像矩阵中,列数为行数的三倍,并且是以 B G R 的顺序存储的
-
-
三:创建Mat 矩阵。类似Matlab的用法
Mat image=Mat::ones(5,5,CV_64FC1);//动态二维数组,ones表示元素全为1,行数,列数可以是变量。创建一个5*5的浮点型矩阵
Mat image=Mat::eyes(5,5,CV_64FC1);//单位矩阵
cout<<image<<endl;//cout 用于输出5*5的全1矩阵。
image.inv();//矩阵转置
image.copyTo();//矩阵拷贝
注:CV_64FC1即单通道double型
F即float浮点型,是32位的,那么64位的double表示方法即64F_(注意在opencv中没有D的表示)_,类似的还有8位无符号字符 uchar – 8U
C 即 Channel,即通道
VideoCapture cap(0);
while(true)
{
Mat frame;
cvtColor(frame,frame,CV_RGB2GRAY);//用于转换颜色,有四个参数,第一个为读取的矩阵名称,第二个为输出矩阵名称,第三个表示转换为灰度图。
cout<<"row"<<frame.rows<<"col"<<frame.cols<<endl;//输出行和列
Mat dimg=Mat(frame.rows,frame.cols-2,CV_8UC1);
for(int i=0;i<frame.rows;i++)
{
for(int j=1;j<frame.cols-1;j++)
{
dimg.at<uchar>(i,j-1)=frame.at<uchar>(i,j-1)-frame.at<uchar>(i,j+1);
}
}
五:利用卷积的方法
卷积就是加权求和。
形象的说: 利用卷积可以实现对图像模糊处理,边缘检测,产生轧花效果的图像。首先,我们有一个二维的滤波器矩阵(有个高大上的名字叫卷积核)和一个要处理的二维图像。然后,对于图像的每一个像素点,计算它的邻域像素和滤波器矩阵的对应元素的乘积,然后加起来,作为该像素位置的值。这样就完成了滤波过程。
卷积的作用是什么呢:利用卷积可以实现对图像的模糊处理和边缘检测。
接下来还是对上述的菊花照片进行卷积处理。思路就是先是两个for循环遍历图像矩阵中的每一个元素,但每一行两边的元素无法处理。
while (true) {
Mat frame=imread("124.jpg",1);
Mat model = Mat(1, 3, CV_64FC1);//创建1*3大小的求导卷积核 model.at<double>(0, 0) = -1; model.at<double>(0, 1) = 0; model.at<double>(0, 2) = 1; Mat dimg = Mat(frame.rows, frame.cols-2, CV_8UC1); //存放加权后的像素点 for (int i = 0; i < frame.rows; i++){ for (int j = 1; j < frame.cols - 1; j++){ //外两层用于遍历所有像素点,但是每一行边上的两个不遍历 int half = model.cols / 2; double sum = 0; for (int m = 0; m < model.rows; m++){ for (int n = -half; n < model.cols-half; n++){ sum += (double)frame.at<uchar>(i + m, j + n)*model.at<double>(m, n + half);//内层求加权和放在sum中 } } dimg.at<uchar>(i, j - 1) = (uchar)sum; //把sum值放在dimg矩阵中 } } imshow("123", dimg); //输出矩阵 waitKey(10); } 处理后的结果如图所示:cvtColor(frame, frame, CV_RGB2GRAY);
给出的卷积核不同,对图像的处理效果就不同。
接下来介绍图像处理中广泛应用的高斯模糊
六:利用高斯卷积和进行高斯模糊。首先必须理解高斯模糊的概念,推荐看一下百度百科。http://baike.baidu.com/link?url=Hjew2I6o5g5eeJPzvjx5WQWgf99cGuao2el3SPXqgBgLP_a1POLKyRXbyX1C6vqv28rRrXWC4FRZrHb25cWf-XQq8ytpLOQx7zRb9A5AHGDGVPda5kcbfs0Itx3OE1D6
高斯模糊的实质是利用了正态分布去生成对应的权值矩阵(卷积核);下面的代码实现了调取摄像头并对图像进行高斯模糊。
//创建高斯模糊卷积核,实质是利用正态分布。 double sigma=0.5;//标准差simga Mat gauss(5,5,CV_64FC1); for(int i=-2;i<3;i++)//正态分布公式。 { for(int j=-2;j<3;j++) { gauss.at<double>(i+2,j+2)=exp(-(i*i+j*j)/(2*sigma*sigma)); } } //对卷积核归一化 ,保证图像的亮度。 double gssum=sum(gauss).val[0];//sum这个函数返回的是scale类 这个类本身有4个通道 sum函数把值放在了0通道 val[0]是0通道的值 for(int i=-2;i<3;i++) { for(int j=-2;j<3;j++) { gauss.at<double>(i+2,j+2)/gssum; } }
cout << gauss << endl; VideoCapture cap(0); while (true) { Mat frame; cap >> frame; cvtColor(frame, frame, CV_RGB2GRAY); Mat dimg = Mat(frame.rows - 4, frame.cols - 4, CV_8UC1); for (int i = 2; i < frame.rows - 2; i++){ for (int j = 2; j < frame.cols-2; j++){ double sum = 0; for (int m = 0; m < gauss.rows; m++){ for (int n = 0; n < gauss.cols; n++){ sum += (double)frame.at<uchar>(i + m - 2, j + n - 2)*gauss.at<double>(m,n); } } dimg.at<uchar>(i - 2, j - 2) = (uchar)sum; } } imshow("gauss", dimg); imshow("123", frame); waitKey(10); }
这里就不贴图表示效果了。
七:调用opencv的内部方法实现高斯模糊,以及边缘检测。
GaussianBlur(image, image, cvSize(5, 5), 10, 10); // 高斯模糊
这个函数实现的效果如图:Canny(image, image, 100, 100); // candy算子
Sobel(image, image, 0, 1, 1); // sobel 算子