计算机视觉
计算机视觉是一门研究如何使机器“看”的科学,指用摄影机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉,并进一步做图形处理,使电脑处理成为更适合人眼观察或传送给仪器检测的图像。因为感知可以看作是从感官信号中提 取信息,所以计算机视觉也可以看作是研究如何使人工系统从图像或多维数据中“感知”的科学。
OpenCV
开发源代码的计算机视觉类库OpenCV(Inter Open Source ComputerVision Library)由英特尔公司开发,它是一套可免费获得的由一些C函数和C++类所组成的库,用来实现一些常用的图像处理及计算机视觉算法。OpenCV主要用于对图像进行一些高级处理,比如说特征检测与追踪、运动分析、目标分割与识别以及3D重建等。
OpenCV是Inter公司开发的图像处理和计算机视觉函数库,它有以下几个特点:开发C源码,基于Inter处理器指令集开发的优化代码,统一的结构和功能定义,强大的图像和矩阵运算能力,方便灵活的用户接口,同时支持WINDOWS,LINUX平台等。
将图像写入文件,可使用 imwrite()函数,该函数的声明如下:
bool imwrite(const string& filename, InputArray image,const vector<int>& params=vector<int>())
下面例程展示了如何读入一副图像,然后对图像进行 Canny 边缘操作,最后
将结果保存到图像文件中。
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
//读入图像,并将之转为单通道图像
Mat im = imread("lena.jpg", 0);
//请一定检查是否成功读图
if( im.empty() )
{
cout << "Can not load image." << endl;
return -1;
}
//进行 Canny 操作,并将结果存于 result
Mat result;
Canny(im, result, 50, 150);
//保存结果
imwrite("lena-canny.png", result);
return 0;
}
将 lena.jpg 文件放在当前目录,运行该例程后,lena-canny.png 将会出现在当前目录。lena-canny.png 图像如图所示,是 lena.jpg 的边缘提取结果。
迭代器可以方便地遍历所有元素。
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
Mat grayim(600, 800, CV_8UC1);
Mat colorim(600, 800, CV_8UC3);
//遍历所有像素,并设置像素值
MatIterator_<uchar> grayit, grayend;
for( grayit = grayim.begin<uchar>(), grayend = grayim.end<uchar>(); grayit != grayend;++grayit)
*grayit = rand()%255;
//遍历所有像素,并设置像素值
MatIterator_<Vec3b> colorit, colorend;
for( colorit = colorim.begin<Vec3b>(), colorend =colorim.end<Vec3b>(); colorit != colorend; ++colorit)
{
(*colorit)[0] = rand()%255; //Blue
(*colorit)[1] = rand()%255; //Green
(*colorit)[2] = rand()%255; //Red
}
//显示结果
imshow("grayim", grayim);
imshow("colorim", colorim);
waitKey(0);
return 0;
}
VideoCapture 既可以从视频文件读取图像,也可以从摄像头读取图像。可以
使用该类的构造函数打开视频文件或者摄像头。如果 VideoCapture 对象已经创
建,也可以使用 VideoCapture::open()打开,VideoCapture::open()函数会自动调用
VideoCapture::release()函数,先释放已经打开的视频,然后再打开新视频。
如果要读一帧,可以使用 VideoCapture::read()函数。VideoCapture 类重载了>>
操作符,实现了读视频帧的功能。下面的例程演示了使用 VideoCapture 类读视
频。
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
//打开第一个摄像头
//VideoCapture cap(0);
//打开视频文件
VideoCapture cap("video.short.raw.avi");
//检查是否成功打开
if(!cap.isOpened())
{
cerr << "Can not open a camera or file." << endl;
return -1;
}
Mat edges;
//创建窗口
namedWindow("edges",1);
for(;;)
{
Mat frame;
//从 cap 中读一帧,存到 frame
cap >> frame;
//如果未读到图像
if(frame.empty())
break;
//将读到的图像转为灰度图
cvtColor(frame, edges, CV_BGR2GRAY);
//进行边缘提取操作
Canny(edges, edges, 0, 30, 3);
//显示结果
imshow("edges", edges);
//等待 30 秒,如果按键则推出循环
if(waitKey(30) >= 0)
break;
}
//退出时会自动释放 cap 中占用资源
return 0;
}
傅立叶变换,表示能将满足一定条件的某个函数表示成三角函数(正弦和/或余弦函数)或者它们的积分的线性组合。在不同的研究领域,傅立叶变换具有多种不同的变体形式,如连续傅立叶变换和离散傅立叶变换。最初傅立叶分析是作为热过程的解析分析的工具被提出的。
图像滤波
图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。
图像求导
卷积定理指出,函数卷积的傅里叶变换是函数傅里叶变换的乘积。即,一个域中的卷积相当于另一个域中的乘积,例如时域中的卷积就对应于频域中的乘积。
F(g(x)*f(x)) = F(g(x))F(f(x))
其中F表示的是傅里叶变换。
高斯模糊Gaussian Blur,也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NET等图像处理软件中广泛使用的处理效果,通常用它来减少图像噪声以及降低细节层次。这种模糊技术生成的图像,其视觉效果就像是经过一个半透明屏幕在观察图像,这与镜头焦外成像效果散景以及普通照明阴影中的效果都明显不同。高斯平滑也用于计算机视觉算法中的预先处理阶段,以增强图像在不同比例大小下的图像效果。
#include<iostream>
#include<opencv2/opencv.hpp>
#define PI 3.1415926
using namespace std;
using namespace cv;
int main(int argc, char ** argv)
{
Mat src = imread("C:/Users/lenovo/Desktop/asd/lena.jpg", 1);
cvtColor(src, src, COLOR_BGR2GRAY);
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
//高斯模糊5*5 以下为5*5的卷积
Mat model = Mat(5, 5, CV_64FC1);
double sigma = 80;
for (int i = -2; i <= -2; i++)
{
for (int j = -2; j <= -2; j++)
{
model.at<double>(i + 2, j + 2) = exp(-(i * i + j * j) / (2 * sigma * sigma)) / (2 * PI * sigma * sigma);
}
}
double gaussSum = 0;
gaussSum = sum(model).val[0];
for (int i = 0; i < model.rows; i++)
{
for (int j = 0; j < 5; j++)
{
model.at<double>(i, j) = model.at<double>(i, j) / gaussSum;
}
}
Mat dst = Mat(src.rows - 4, src.cols - 4, CV_8UC1);
for (int i = 2; i < src.rows - 2; i++)
{
for (int j = 2; j < src.cols - 2; j++)
{
double sum = 0;
for (int m = 0; m < model.rows; m++)
{
for (int n = 0; n < model.cols; n++)
{
sum += (double)src.at<double>(i + m - 2, j + n - 2) * model.at<double>(m, n);
}
}
dst.at<uchar>(i - 2, j - 2) = (uchar)sum;
}
}
namedWindow("gaussBlur", WINDOW_AUTOSIZE);
imshow("gaussBlur", dst);
waitKey(0);
}
高斯金字塔从底向上,逐层降采样取得,不能跨域越层;
对当前层删除偶数行与列就得到降采样后上一层的图片;
降采样后的图像大小是之前图像大小的1414;
高斯金字塔生成步骤:
①进行高斯模糊;
②删除偶数行与列。
void PyrDownTest(){
Mat src,dest1,dest2;
src = imread("dog.jpg");
if(!src.data){
cout << "图像打开失败!" << endl;
return ;
}
namedWindow("原图",CV_WINDOW_AUTOSIZE);
imshow("原图",src);
//降采样
pyrDown(src,dest1,Size(src.cols/2,src.rows/2));
pyrDown(dest1,dest2,Size(dest1.cols/2,dest1.rows/2));
namedWindow("降采样后1",CV_WINDOW_AUTOSIZE);
imshow("降采样后1",dest1);
namedWindow("降采样后2",CV_WINDOW_AUTOSIZE);
imshow("降采样后2",dest2);
cvWaitKey();
}