一.概念

1.图像本质上面是由数值组成的矩阵。矩阵中的一个元素相应一个像素。

2.对于灰度图像(黑白图像),像素是8位无符号数(CV_8U)。0表示黑色,255表示白色。对于彩色图像,是用三原色数据合成彩色。3个8位(CV_8UC3)的数值组成矩阵的一个元素。并且顺序是BGR

3.一般来说8位的通道够用了。可是有些特殊的需要16位。

4.经验之谈:矩阵能够有非常多种类型,可是大部分操作能够使用不论什么类型的矩阵来完毕。可是还是有一些操作必须使用特性的类型或者特定的通道数量。有时候留个心积累那些图用什么矩阵来处理。

以下废话不多说。先来一个启示性的样例(能够临时不用知道当中所有的细节,稍后会说到这些东西)

代码:



结果:

在原来的图片上面生成了非常多非常多的点。



上面这段代码的原理非常easy:就是随机生成坐标值,然后把这些坐标处的灰度值改为255(白色).

大概有这些就已经算是一个訪问像素的完整过程了.以下就具体讲一些訪问像素的细节.

二.訪问像素的三种方法

1.at方法(cv::Mat::at(…..)).

at方法顾名思义,就是在某个位置.其有用at能够直接訪问到某个位置的像素.在OpenCV中,at方法为一个模板方法且有非常多的变种,以下仅仅讲最基本经常使用的两种方法.(各自是传入坐标传入点的方法)

at方法是一个模板函数,在官方文档中抽取最简单的写法:

at <类型> (行,列) [通道(假设有通道的话)]

at<类型>(行,列)就能够訪问到一幅图片中的一个像素了,每一个像素的chanel用[]来提取.是不是非常easy.

由于这是模板方法,选择类型成了重要的一步,并且类型的选择是与图片元素的类型要相应起来,at方法不负责转化类型.以下给出一个具体的类型相应表.(要是如今不知道什么是图像元素的类型.那么点击以下的链接转到之前的core组件,有具体的类型介绍.)

http://blog.csdn.net/xierhacker/article/details/52457907

首先,OpenCV中有一个主要的向量模板类,一些主要的”N个元素”向量能够由这个模板类来定义,简单地能够写为cv::Vec

uchar类型(分别为2元素,3元素,4元素):
typedef Vec<uchar, 2> cv::Vec2b typedef Vec<uchar, 3> cv::Vec3b typedef Vec<uchar, 4> cv::Vec4b Short类型
typedef Vec<short, 2> cv::Vec2s typedef Vec<ushort, 2> cv::Vec2w
typedef Vec<short, 3> cv::Vec3s typedef Vec<ushort, 3> cv::Vec3w
typedef Vec<short, 4> cv::Vec4s typedef Vec<ushort, 4> cv::Vec4w Int类型(同上):
typedef Vec<int, 2> cv::Vec2i typedef Vec<int, 3> cv::Vec3i
typedef Vec<int, 4> cv::Vec4i typedef Vec<int, 6> cv::Vec6i
typedef Vec<int, 8> cv::Vec8i float类型:
typedef Vec<float, 2> cv::Vec2f typedef Vec<float, 3> cv::Vec3f typedef Vec<float, 4> cv::Vec4f typedef Vec<float, 6> cv::Vec6f double类型:
typedef Vec<double, 2> cv::Vec2d typedef Vec<double, 3> cv::Vec3d
typedef Vec<double, 4> cv::Vec4d typedef Vec<double, 6> cv::Vec6d

由此,能够得到一个经常使用的訪问像素的时候模板中放类型的表:

像素类型(模板传入关键字):

CV_8U(uchar)
CV_8UC1 (uchar) CV_8UC2 (Vec2b) CV_8UC3 (Vec3b) CV_8UC4(Vec4b) CV_8S(char)
CV_8SC1 (1通道) CV_8SC2 (2通道) CV_8SC3 (3通道) CV_8SC4 (4通道) CV_16U (ushort)
CV_16UC1 (ushort) CV_16UC2 (Vec2w) CV_16UC3 (Vec3w) CV_16UC4 (Vec4w) CV_16S (short)
CV_16SC1(short) CV_16SC2(Vec2s) CV_16SC3(Vec3s) CV_16SC4(Vec4s) CV_32S (int)
CV_32SC1(int) CV_32SC2(Vec2i) CV_32SC3(Vec3i) CV_32SC4(Vec4i) CV_32F (float)
CV_32FC1(float) CV_32FC2(Vec2f) CV_32FC3(Vec3f) CV_32FC4(Vec4f) CV_64F(double)
CV_64FC1(double) CV_64FC2(Vec2d) CV_64FC3(Vec3d) CV_64FC4(Vec4d)

如今再来看上面的那个添加白色噪点的样例,是不是豁然开朗,知道是怎么用的了.

一个改变某点像素来画线的样例:

代码:

#include <iostream>
#include <cmath>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp> int main()
{
cv::Mat pic1(300, 300, CV_8UC3, cv::Scalar(255, 0, 0));
cv::Mat pic2(10, 3, CV_32F, 20.3); //訪问像素
//pic1上面画出一条直线
for (int i = 0; i <300; i++)
{
int j = i;
//訪问像素改变颜色CV_8UC3相应的就是Vec3b.
pic1.at<cv::Vec3b>(i, j)[0] = 0;
pic1.at<cv::Vec3b>(i, j)[2] = 255; }
cv::imshow("test", pic1);
cv::waitKey(0);
return 0;
}

结果:



代码的意义非常easy懂,就是建立一个80*80的图片,初始化为蓝色,然后依据一个直线方程把某点的颜色改为红色,那么终于就得到了一条红色的直线.

2.指针(cv::Mat::ptr(….))

http://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html#a5a9ffc908ac90604f36a8b6a1038747d

用指针訪问的话。OpcnCV提供了一个方法,cv::Mat::ptr()。以下是这种方法的几种经常使用的定义。

定义一:

_Tp* cv::Mat::ptr (int  i0 = 0)
返回mat的某行的一个地址,地址的类型与你之前在mat中选择的类型有关(模板函数),因此,要非常注意选择正确的返回以及模板參数的类型.
i0代表0轴,或者通俗一点理解就是矩阵的一行.(索引是从0開始,要小心)

定义二:

_Tp* cv::Mat::ptr ( int  i0,int  i1 )
返回mat某个位置元素的地址,还是老话,地址的类型与你之前在mat中选择的类型有关(模板函数),因此,要非常注意选择正确的返回以及模板參数的类型.
i0代表0轴,或者通俗一点理解就是矩阵的一行.(索引是从0開始,要小心)
I1代表1轴,或者通俗一点理解就是矩阵的一列,(索引是从0開始,要小心)

例一(仅仅有一个通道):

代码:

#include <iostream>
#include <cmath>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp> int main()
{
cv::Mat pic2(10, 3, CV_32F, 20.3);
//每行元素数量
int numOfRow = pic2.cols; //訪问像素
for (int row = 0; row < pic2.rows; row++)
{
//获得该行的地址
float *data = pic2.ptr<float>(row);
//訪问该行元素
for (int col = 0; col < numOfRow; col++)
{
std::cout << data[col] << " ";
} std::cout << std::endl;
}
cv::imshow("test", pic2);
cv::waitKey(0);
return 0;
}

结果:



这里的Mat中的数据类型选择的是CV_32F,是float的单通道类型.选择这样的类型就是要展示接下来的指针的模板中应该选择的參数.

例二(多个通道):

代码:

#include <iostream>
#include <cmath>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp> int main()
{
cv::Mat pic1(10, 3, CV_8UC3, cv::Scalar(255, 0, 0));
// cv::Mat pic2(10, 3, CV_32F, 20.3);
//每行元素数量
int numOfRow = pic1.cols; //訪问像素
for (int row = 0; row < pic1.rows; row++)
{
//获得该行的地址
cv::Vec3b *data = pic1.ptr<cv::Vec3b>(row);
//訪问该行元素
for (int col = 0; col < numOfRow; col++)
{
data[col][0] = 0;
data[col][2] = 255;
} //std::cout << std::endl;
}
std::cout << cv::format(pic1, cv::Formatter::FMT_PYTHON) << std::endl;
cv::imshow("test", pic1);
cv::waitKey(0);
return 0;
}

结果:

例三(两个索引):

代码:

#include <iostream>
#include <cmath>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp> int main()
{
cv::Mat pic1(10, 3, CV_8UC3, cv::Scalar(255, 0, 0));
// cv::Mat pic2(10, 3, CV_32F, 20.3);
//每行元素数量
int numOfRow = pic1.cols; //返回1行3列的地址(索引从0開始)
cv::Vec3b *pixel = pic1.ptr<cv::Vec3b>(0, 2);
//0通道改为128
pixel[0] = 128;
//输出
std::cout << *pixel << std::endl;
cv::imshow("test", pic1);
cv::waitKey(0);
return 0;
}

结果:



也就是说,能够同一时候使用两个索引来得到一个具体位置的地址.

三.感兴趣区域(Region Of Interest,ROI)

有时候我们并不想在一整张图片上面做文章..我们仅仅想选择某一个小区域上面完毕一些操作.

OpenCV能够让我们仅仅选择一些子区域,并且把这个子区域当做普通的图像来操作.这就引出了感兴趣区域(ROI)这个话题.

使用ROI通常能够降低处理时间,添加精度,因此是一个必需要掌握的”技能”.

定义ROI区域方式:

方式一:使用矩形(Rect)类

Mat  ROI;
ROI=image(Rect_ (_Tp _x, _Tp _y, _Tp _width, _Tp _height));
x,y这两个參数就是矩形区域左上角的坐标
width,height这两个參数就是矩形局域的宽和高

(Rect类不熟悉的话:转到之前的core组件:http://blog.csdn.net/xierhacker/article/details/52457907)

方式二:手动指定感兴趣的行和列的范围

Mat  ROI;
ROI=image(Rect_ (range(row_start,row_end),range(col_strat,col_end)));
range(row_start,row_end):行的開始和结束
range(col_strat,col_end):列的開始和结束

说了这么多,就要讲具体怎么用了,以下图像运算的第一个实例图像叠加就使用了ROI的概念,能够看下实例是怎么用的.

四.简单图像运算

首先,标题是简单图像运算,是由于接下来的样例都是非常easy非常基础的.可是也是非常综合的,综合使用了之前接触到的一些编程以及理论知识.

这部分有必要消化,由于这些实例中包括了一些非常主要的概念,这些概念会在这些样例中非常形象的展示出来.比死记硬背一些理论好多了.

Ⅰ图像叠加

图像叠加是一个非常主要的样例,通过这个样例能够联系ROI的使用.

我们这里有两个图片,一个是主图片例如以下



一个是非常小的logo例如以下.



任务就是要将logo叠加到主图片上面去.不啰嗦了,上代码

代码:

#include <iostream>
#include <cmath>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp> int main()
{
//读主图片
cv::Mat image = cv::imread("1.jpg");
//读logo
cv::Mat logo = cv::imread("logo.png");
//在主图片上面定义"感兴趣"区域
cv::Mat ROI = image(cv::Rect(200, 200, logo.cols, logo.rows));
//logo拷贝到感兴趣区域
logo.copyTo(ROI); cv::imshow("test", image);
cv::waitKey(0);
return 0;
}

效果:



上面的代码非常easy,所以这里不给出解释,看凝视完全然全能够懂.

还有内容,稍后更新……

OpenCV从入门到放弃(五):像素!的更多相关文章

  1. openCV从入门到放弃

    与图像处理之间的关系,opencv的简介和使用定位 如题...因为偶然的机会需要用到图像处理,像我这么爱学习 并且动手能力又强的人怎么能没有心得笔记呢,哇哈哈哈.非要说的low逼点这玩意儿这玩意儿就是 ...

  2. OpenCV从入门到放弃系列之——如何扫描图像、利用查找表和计时

    目的 如何遍历图像中的每一个像素? OpenCV的矩阵值是如何存储的? 如何测试我们所实现算法的性能? 查找表是什么?为什么要用它? 测试用例 颜色空间缩减.具体做法就是:将现有颜色空间值除以某个输入 ...

  3. OpenCV从入门到放弃系列之——core模块.核心功能(一)

    Mat - 基本图像容器 世间的图像是各种各样的,但是到了计算机的世界里所有的图像都简化为了数值矩以及矩阵信息.作为一个计算视觉库,OpenCV的主要目的就是处理和操作这些信息,来获取更高级的信息,也 ...

  4. OpenCV从入门到放弃系列之——图像的基本操作

    读取.修改.保存图像 图像读取函数imread(); 图像颜色空间的转换cvtColor(); 图像保存至硬盘imwrite(); /********************************* ...

  5. MyBatis从入门到放弃五:调用存储过程(SQLServer2012)

    前言 如果是相对于复杂的SQL逻辑我们肯定是基于存储过程开发,这篇学习下执行存储过程,调用存储过程如果参数较多我们可以创建parameterMap. 搭建开发环境 开发环境和上篇文章保持相同 创建存储 ...

  6. 【图像处理】OpenCV+Python图像处理入门教程(五)阈值处理

    这篇随笔介绍使用OpenCV进行图像处理的第五章 阈值处理. 5  阈值处理 阈值是指像素到达某临界值.阈值处理表示像素到达某临界值后,对该像素点进行操作和处理. 例如:设定一幅图像素阈值为200,则 ...

  7. OpenStack从入门到放弃

    OpenStack从入门到放弃 目录: 为何选择云计算/云计算之前遇到的问题 什么是云计算 云服务模式 云应用形式 传统应用与云感知应用 openstack及其相关组件介绍 flat/vlan/gre ...

  8. 绕过校园网的共享限制 win10搭建VPN服务器实现--从入门到放弃

    一.开篇立论= =.. 上次说到博主在电脑上搭建了代理服务器来绕过天翼客户端的共享限制,然而经过实际测试还不够完美,所以本着生命不息,折腾不止的精神,我又开始研究搭建vpn服务器= =... (上次的 ...

  9. opencv编程入门技巧

    opencv编程入门技巧 最近在项目中负责图像处理模块的编程工作,主要分为两个板块,一是视频图像去雾,二是可视.红外图像融合.为了提升开发效率,遂开始学习并使用opencv图像类库,效果很好的说~因为 ...

随机推荐

  1. SASS常用方法

    cnpm install --save-dev sass-loader //sass-loader依赖于node-sass cnpm install --save-dev node-sass //实现 ...

  2. POJ 题目1145/UVA题目112 Tree Summing(二叉树遍历)

    Tree Summing Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 8132   Accepted: 1949 Desc ...

  3. 10.查看npm安装信息和版本号

    转自:http://www.runoob.com/nodejs/nodejs-express-framework.html 你可以使用以下命令来查看所有全局安装的模块: $ npm list -g ├ ...

  4. Android JSON数据解析(GSON方式)

    要创建和解析JSON数据,也可以使用GSON来完成.GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库.使用GSON,可以很容易的将一串JSON数据转换为一个Jav ...

  5. ORA-16055: FAL request rejected

    主库频繁报错如下: ORA-16055: FAL request rejected   解决办法: ALTER SYSTEM SET log_archive_dest_state_2='DEFER' ...

  6. php基础篇之一

    1.PHP是什么 官方文档:超文本预处理器 2.PHP能够做一些什么? PHP主要应用在一下领域: (1)服务器端脚本,需要:PHP解析器,PHP服务器,PHP浏览器. (2)命令行脚本,只需要PHP ...

  7. 洛谷—— P1162 填涂颜色

    https://www.luogu.org/problem/show?pid=1162 题目描述 由数字0 组成的方阵中,有一任意形状闭合圈,闭合圈由数字1构成,围圈时只走上下左右4个方向.现要求把闭 ...

  8. 洛谷——P1042 乒乓球

    https://www.luogu.org/problem/show?pid=1042 题目背景 国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及.其中11分制改 ...

  9. Arch Linux实体机安装记录

    下面将记录笔者在戴尔笔记本安装arch linux的过程,用于记录,以便下次使用. 本文的内容参考arch linux官方Wiki. 首先,使用Power ISO把镜像安装到U盘,使用U盘安装. 通过 ...

  10. StartCoroutine的使用

    StartCoroutine在unity3d的帮助中叫做协程,意思就是启动一个辅助的线程. 在C#中直接有Thread这个线程,可是在unity中有些元素是不能操作的.这个时候能够使用协程来完毕. 使 ...