OpenCv 2.4.9 (二) 核心函数
前言
经过前面一节的怎样读取图片,我们可以做一些有趣的图像变换,下面我们首先介绍使用遍历的方法实现,然后我们使用内置的函数实现。
矩阵掩码实现
矩阵掩码,和卷积神经网络中的卷积类似。一个例子如下:

现在我们看看怎么实现:
void Sharpen(const Mat& myImage, Mat& Result)
{
CV_Assert(myImage.depth() == CV_8U); Result.create(myImage.size(), myImage.type());
const int nChannels = myImage.channels(); for (int j=; j<myImage.rows-; ++j) { // 忽略第一和最后一行,防止数组越界
const uchar * previous = myImage.ptr<uchar>(j-);
const uchar * current = myImage.ptr<uchar>(j);
const uchar * next = myImage.ptr<uchar>(j+); uchar * output = Result.ptr<uchar>(j); // 用连续存储的索引方法,所以每个点有三个uchar值
// saturate_cast溢出保护
for (int i=nChannels; i < nChannels * (myImage.cols-); ++i) {
*output++ = saturate_cast<uchar>( * current[i]
- current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);
} // 四周设置为0
Result.row().setTo(Scalar());
Result.row(Result.rows-).setTo(Scalar());
Result.col().setTo(Scalar());
Result.col(Result.cols-).setTo(Scalar());
}
}
我们看看结果:

因为掩码是增强中间,削弱四周,下面如果我们换掩码,使用内置函数看看效果:
void SharpenUseFilter2D(const Mat& src, Mat& dst) {
Mat kern = (Mat_<char>(, ) << ,-,,
-,-1,5,
,-,);
filter2D(src, dst, src.depth(), kern);
}
下面是增强右边元素,减弱左边元素的效果(类似浮雕的效果,大家可以换着掩码来玩):

图片混合
下面是线性混合操作:
这个可以实现幻灯片的淡入淡出,通过修改alpha值。
resize(src1, src1, cv::Size(, ));
resize(src2, src2, cv::Size(, )); namedWindow(""); beta = 1.0 - alpha;
// dst = alpha * src1 + beta * src2 + gamma
// 这里gamma设置为0.0
addWeighted(src1, alpha, src2, beta, 0.0, dst);
下面看看结果:

自己实现的简陋版本,除去错误检查等:
void addWeight(Mat& src1, double w1, Mat& src2, double w2, Mat& dst)
{
dst.create(src1.size(), src2.type()); Mat_<Vec3b> _src1 = src1;
Mat_<Vec3b> _src2 = src2;
Mat_<Vec3b> _dst = dst; for (int i=; i<src1.rows; ++i) {
for (int j=; j<src1.cols; ++j) {
for (int c=; c<; ++c)
_dst(i, j)[c] = w1 * _src1(i, j)[c] + w2 * _src2(i, j)[c];
}
}
}
改变图片的对比度和亮度

Mat new_image = Mat::zeros(image.size(), image.type());
alpha = 1.2; // 1.0-3.0
beta = ; // 0-100
for (int y=; y<image.rows; ++y) {
for (int x=; x<image.cols; ++x) {
for (int c=; c<; ++c)
// Vec3b = [R, G, B]
new_image.at<Vec3b>(y, x)[c] = saturate_cast<uchar>
(alpha * (image.at<Vec3b>(y, x)[c]) + beta);
}
}
Mat new_image_2 = Mat::zeros(image.size(), image.type());
// -1 代表输入输出类型一样
image.convertTo(new_image_2, -, alpha, beta);
结果如下:

基本绘图
而产生随机数可以使用 RNG rng( 0xFFFFFFFF ); 这样就可以生成符合一定分布的数,例如高斯分布 rng.uniform(1, 10);
快速傅里叶变换

(上图来源:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.html)
// 当图片大小是2,3,5的倍数的时候,傅里叶变换表现最高
// 所以先获得最好的尺寸 m,n
// 然后再进行填充
Mat padded;
int m = getOptimalDFTSize(I.rows);
int n = getOptimalDFTSize(I.cols);
copyMakeBorder(I, padded, m-I.rows, , n-I.cols, , BORDER_CONSTANT, Scalar::all()); // 对于每个原图,结果是两个图像值
// 因为需要储存复数部分,所以需要添加一个额外通道
// 存到complexI中
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
Mat complexI;
merge(planes, , complexI); dft(complexI, complexI); // 将复数转化成幅度
split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
magnitude(planes[], planes[], planes[]); // planes[0] = sqrt([0]**2 + [1]**2)
Mat magI = planes[]; // 为了使变化可以观察,高低连续变换,需要尺度缩放
magI += Scalar::all();
log(magI, magI); // 剪切和重分布图像象限
magI = magI(Rect(, , magI.cols & -, magI.rows & -)); int cx = magI.cols/;
int cy = magI.rows/; Mat q0(magI, Rect(, , cx, cy)); // 上左
Mat q1(magI, Rect(cx, , cx, cy));// 上右
Mat q2(magI, Rect(, cy, cx, cy));// 下左
Mat q3(magI, Rect(cx, cy, cx, cy));// 下右 Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3); q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2); // 归一化
normalize(magI, magI, , , CV_MINMAX);
输出为XML或者YAML文件
输出为XML或者YAML需要借助 FileStorage 和 FileNode 。
首先声明文件名
string filename = "store.xml";
对于写入:
FileStorage fs(filename, FileStorage::WRITE); // 记得释放, fs.release();
对于读取:
FileStorage fs;
fs.open(filename, FileStorage::READ);
内置对象的写入读取
// 写入
fs << "iterationNr" << ; //读取
int itNr;
itNr = (int) fs["iterationNr"];
存储效果如下:
序列的写入读取
// 序列写入需要使用[]
fs << "strings" << "[";
fs << "image1.jpg" << "Awesoneness" << "babonn.jpg";
fs << "]"; // 读取需要迭代器
FileNode n = fs["strings"];
if (n.type() != FileNode::SEQ) {
cerr << "string is not a sequence!" << endl;
return ;
}
FileNodeIterator it = n.begin(), it_end = n.end();
for (; it != it_end; ++it)
cout << (string)*it << endl;
存储效果:
Map的写入读取
// map的写入需要{}
fs << "Mapping";
fs << "{" << "One" << ;
fs << "Two" << << "}";
// 读取
n = fs["Mapping"];
cout << "Two " << (int)(n["Two"]) << ";";
cout << "One " << (int)(n["One"]) << endl << endl;
存储效果:
矩阵的写入读取
Mat R = Mat_<uchar>::eye(, );
fs << "R" << R; Mat R;
fs["R"] >> R;
存储效果:
自定义对象的写入和读取
首先自定义对象:
class MyData
{
public:
MyData(): A(), X(), id() {}; explicit MyData(int): A(), X(CV_PI), id("mydata1234") {}; void write(FileStorage& fs) const {
fs << "{" << "A" << A << "X" << X <<"id" << id << "}"; // 自定义写入
} void read(const FileNode& node) { // 自定义读取
A = (int)node["A"];
X = (double)node["X"];
id = (string)node["id"];
}
public:
int A;
double X;
string id;
};
然后还要重载全局的读取和写入函数:
static void write(FileStorage& fs, const std::string&, const MyData& x) {
x.write(fs);
}
static void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()) {
if (node.empty())
x = default_value;
else
x.read(node);
}
这样就可以写入和读取:
MyData m();
fs << "MyData" << m; fs["MyData"] >> m;
存储效果如下:
和OpenCV1混合
OpenCv 2.4.9 (二) 核心函数的更多相关文章
- OpenCV使用FindContours进行二维码定位
我使用过FindContours,而且知道有能够直接寻找联通区域的函数.但是我使用的大多只是"最大轮廓"或者"轮廓数目"这些数据.其实轮廓还有另一个很重要的性质 ...
- opencv学习笔记(二)寻找轮廓
opencv学习笔记(二)寻找轮廓 opencv中使用findContours函数来查找轮廓,这个函数的原型为: void findContours(InputOutputArray image, O ...
- 【OpenCV入门教程之二】 一览众山小:OpenCV 2.4.8组件结构全解析
转自: http://blog.csdn.net/poem_qianmo/article/details/19925819 本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:ht ...
- 【OpenGL游戏开发之三】OpenGl核心函数库汇总
OpenGl核心函数库 glAccum 操作累加缓冲区 glAddSwapHintRectWIN 定义一组被SwapBuffers拷贝的三角形 glAlphaFunc允许设置alpha检测功能 glA ...
- zepto学习之路--核心函数$()的实现
$()可以说是jquery的精华了,为dom操作带来了极大的灵活和方便.zepto号称“移动版的jquery”,那么它是怎么来实现这个核心函数呢?我们来详细探讨下. 1.首先,我们看下zepto中它是 ...
- Ext.Js核心函数( 三)
ExtJs 核心函数简介 1.ExtJs提供的常用函数2.get.fly.getCmp.getDom.getBody.getDoc3.query函数和select函数4.encode函数和decode ...
- 【OpenCV入门教程之二】 一览众山小:OpenCV 2.4.8 or OpenCV 2.4.9组件结构全解析
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/19925819 作者:毛星云 ...
- 基于Opencv识别,矫正二维码(C++)
参考链接 [ 基于opencv 识别.定位二维码 (c++版) ](https://www.cnblogs.com/yuanchenhui/p/opencv_qr.html) OpenCV4.0.0二 ...
- 解密jQuery内核 DOM操作的核心函数domManip
domManip是什么 dom即Dom元素,Manip是Manipulate的缩写,连在一起就是Dom操作的意思. .domManip()是jQuery DOM操作的核心函数 对封装的节点操作做了参数 ...
随机推荐
- 【Xilinx-Petalinux学习】-01-开发环境搭建与PetaLinux的安装
开发环境 VMware12, Ubuntu 16.04 64 bit 在VMware中安装Ubuntu,用户名:xilinx-arm 密码:root step1: VMware Tools问题 不知道 ...
- Git和Github的配合使用
Git教程 http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 Git 本地仓库详解 ...
- iOS 之 线性布局
本来想自己写一个线性布局的类,看来不用了 ,网上已经有了,我先试试好不好用. https://github.com/youngsoft/MyLinearLayout 线性布局MyLinearLayou ...
- UVa 10057 - A mid-summer night's dream
题目大意:给n个数,找一个数A使得A与这n个数的差的绝对值最小.输出A最小的可能值,n个数中满足A的性质的数的个数以及满足A性质的不同的数的个数(不必从这n个数中挑选). 看见绝对值就想到了数轴上点之 ...
- apue- chapter 1 UNIX基础知识
1.C++实现ls命令 #include<dirent.h> #include<stdlib.h> #include<iostream> #include &quo ...
- OC 优化目录
把 main. info 和 appdelegate 放到自己的新建目录 1.去掉info.plist的警告 在build phases->copy Bundle Resources中去掉inf ...
- LNMP 快速安装
网址是:http://lnmp.org/install.html 值得注意的是:它基本上把所有的扩展都装上了,有点冗余 安装完成后,根目录的位置是 /home/wwwroot/default LNMP ...
- CFD-post的奇技淫巧
此处记录两个后处理美化的技巧:1.关于contour显示的美化:2.关于legend的显示美化 1. 直接举例说明,现在cfd-post里导入了一个二维case,先建立一个plane: apply以后 ...
- HDU-1995-汉诺塔V
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1995 这题不知道该说水还是不水,对于这题我看到题目数据,就有了想法,因为题目数据给的好 所以我直接 假 ...
- node源码详解 (一)
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource1 本博客同步在https://cnodejs.o ...