1 cv::Mat

cv::Mat是一个n维矩阵类,声明在<opencv2/core/core.hpp>中。

 
class CV_EXPORTS Mat
{
public:
//a lot of methods
/*! includes several bit-fields:
- the magic signature
- continuity flag
- depth
- number of channels
*/
int flags;
//! the matrix dimensionality, >= 2
int dims;
//! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
int rows, cols;
//! pointer to the data
uchar* data; //! pointer to the reference counter;
// when matrix points to user-allocated data, the pointer is NULL
int* refcount;
//ohter members

};
 

由于OpenCV 2对代码结构做了重新部署,所有的类和方法都定义在名字空间cv中,可以预定义名字空间:

using namespace cv

跟一般的cpp程序一样,对于类的参数传递都采用引用传递方式,获得较好的效率。类都有自己的构造函数和析构函数,防止内存的泄漏。并且默认的拷贝构造函数采用的是shallow copy(浅拷贝),若需要deap copy(深拷贝)可求助于cv::Mat的copyTo()方法。这些东西都是cpp的基础知识

2 cv::Mat_

cv::Mat_是一个模板类,声明在<opencv2/core/core.hpp>中。

template<typename _Tp> class CV_EXPORTS Mat_ : public Mat
{
public:
    //some specific methods
};

由于cv::Mat类中含有很多模板方法,这些参数类型要到运行期才能确定,但是这种灵活性却使得简单的调用代码复杂,因此就有了cv::Mat_类来简化代码。如

cv::Mat image = cv::imread('img.jpg');
image.at<uchar>(j, i) = 255; cv::Mat_<uchar> im2 = image;
im2(j, i) = 255;

代码明显好看了。

3 Scanning an image

以color Reduction操作为例,指针方式代码如下:

 
/**
* An example of color reduction for scanning an image with pointers
* div = 2^n
*
*/
void colorReduce(const cv::Mat& image, cv::Mat& result, int div)
{
int nl = image.rows;
int nc = image.cols * image.channels(); if (image.isContinuous()) {
nc = nc * nl;
nl = 1;
} int n = static_cast<int>(
log(static_cast<double>(div)) / log(2.0)); for (int j = 0; j < nl; j++) {
// get the addresses of input and output row
const uchar *data_in = image.ptr<uchar>(j); //give you the address of an image row
uchar *data_out = result.ptr<uchar>(j); for (int i = 0; i < nc; i++) { //slowest
data[i] = data[i] - data[i] % div + div / 2;
//middle
data[i] = data[i] / div * div + div / 2;
//best
uchar mask = 0xFF << n; //div = 16, n = 4, mask = 0xF0
data_out[i] = (data_in[i] & mask) + div / 2; //data[i] - data[i] % div + div / 2
}
}
}
 

(1)上面是采用Pointer方式进行遍历。调用cv::Mat类的模板方法ptr(int)获得图像矩阵的行指针。(2)三种不同效率的调用方式:slowest是由于两次读内存操作增加了时间;best通过位运算进行去尾操作,效率自然更高,但是必须限制为2的n次方。(3)由于是引用传递,若要保留输入图像image,则在输入参数中增加一个result用于保存输出图像。

以下是更快的方式:

 
void colorReduce_f(cv::Mat& image, int div)
{
int nl = image.rows;
int nc = image.cols; if (image.isContinuous()) {
nc = nc * nl;
nl = 1;
} int n = static_cast<int>(
log(static_cast<double>(div)) / log(2.0)); uchar mask = 0xff << n; for (int j = 0; j < nl; j++) {
uchar *data = image.ptr<uchar>(j); for (int i = 0; i < nc; i++) {
*data++ = *data & mask + div / 2;
*data++ = *data & mask + div / 2;
*data++ = *data & mask + div / 2;
}
}
}
 

其中,isContinuous()方法判断有没有额外的补零(如fft补零到2^n),如果是连续的,就可以直接当作一维数组来处理。另外,在每一个循环里连续执行三次以提高效率。(忘细里讲应该跟时空局部性原理有关)

以下是迭代器方式:

 
void colorReduce_2(cv::Mat& image, int div)
{
//obtain iterator
cv::Mat_<cv::Vec3b>::iterator iter =
image.begin<cv::Vec3b>(); //a template method
cv::Mat_<cv::Vec3b>::iterator iterd =
image.end<cv::Vec3b>(); //a template method //do not use template method, more efficient
cv::Mat_<cv::Vec3b> cimage = image;
cv::Mat_<cv::Vec3b>::iterator iter = cimage.begin();
cv::Mat_<cv::Vec3b>::iterator iterd = cimage.end(); for (; iter != iterd; ++iter) {
(*iter)[0] = (*iter)[0] / div * div + div / 2;
(*iter)[1] = (*iter)[1] / div * div + div / 2;
(*iter)[2] = (*iter)[2] / div * div + div / 2;
}
}
 

这里给出了两种获得迭代器的方法:一种是直接调用cv::Mat的模板方法begin()和end();另一种是通过cv::Mat_的begin()和end()。这一点跟stl库是兼容的。注意对于彩色图像,迭代器指向的cv::Vec3b类型的三元组。

4 Scanning an image with neighbor access

方法还是用的指针,因为效率高,但基本的东西还是不变的,代码如下:

 
/**
*An example of Sharpen for scanning an image with neighbor access
*/
void sharpen(const cv::Mat& image2, cv::Mat& result)
{
cv::Mat image;
cv::cvtColor(image2, image, CV_BGR2GRAY);
result.create(image.size(), image.type()); for (int j = 1; j < image.rows - 1; j++) { const uchar* previous =
image.ptr<const uchar>(j - 1);
const uchar* current =
image.ptr<const uchar>(j);
const uchar* next =
image.ptr<const uchar>(j + 1); uchar* output = result.ptr<uchar>(j); for (int i = 1; i < image.cols - 1; i++) { *output++ = cv::saturate_cast<uchar> (
5 * current[i] - current[i - 1]
-current[i + 1] - previous[i] - next[i]);
}
} result.row(0).setTo(cv::Scalar(0));
result.row(result.rows - 1).setTo(cv::Scalar(0));
result.col(0).setTo(cv::Scalar(0));
result.col(result.cols - 1).setTo(cv::Scalar(0));
}
 

这是一个基于拉普拉斯算子的空间域锐化工作,模板(kernel)为一个3阶矩阵。这里用到了cv::cvtColor()函数,用于图像颜色空间的转换,在<opencv2/imgproc/imgproc.hpp>中声明。这里还用到了cv::saturate_cast()模板方法,保证得到的值是在有意义的值域范围内,比如消除滤波中的振铃效应等等。

opencv中还提供了cv::filter2D()函数来实现二维滤波,估计采用的是fft2()的方法,当模板(kernel)较大时采用这个函数,代码如下:

 
void sharpen2D(const cv::Mat& image2, cv::Mat& result)
{
cv::Mat image;
cv::cvtColor(image2, image, CV_BGR2GRAY);
result.create(image.size(), image.type()); cv::Mat kernel(3, 3, CV_32F, cv::Scalar(0)); kernel.at<float>(1, 1) = 5.0;
kernel.at<float>(0, 1) = -1.0;
kernel.at<float>(2, 1) = -1.0;
kernel.at<float>(1, 0) = -1.0;
kernel.at<float>(1, 2) = -1.0; //filter the image
cv::filter2D(image, result, image.depth(), kernel);
}
 

这里把模板就当成是一个图像(实际上负值是没有意义的)。关于滤波就有各种各样的点,只能到频域滤波在复习了。

5 Simple image arithmetic

这里其实是opencv2提供的一些矩阵操作的函数。

算术运算:cv::add(), cv::addWeighted(), cv::scaleAdd(); cv::subtract, cv::absdiff; cv::multiply; cv::divide, 还可以通过mask参数来掩模不需要处理的位。

位运算:cv::bitwise_and, cv::bitwise_or, cv::bitwise_xor, cv::bitwise_not

cv::max, cv::min

其他运算:cv::sqrt, cv::pow, cv::abs, cv::cuberoot, cv::exp, cv::log

上面这些函数都是针对矩阵的每一个元素对应操作的。更方便的是,矩阵的加减乘除、bitwise operators….都被重载了。inv()求逆、t()求转置、determinant()求行列式、norm()求范数、cross()求两个向量的叉乘、dot()求两个向量的点乘。

当需要将一个多通道图像分离时,调用cv::split()方法,用一个std::vector来保存中间量,最后又可以调用cv::merge()方法合成,代码如下:

std::vector<cv::Mat> planes;
cv::split(image1, planes);
planes[0] += image2;
cv::merge(planes, result);

6 Region of interest

直接上代码吧:

 
void addROI(cv::Mat& image, cv::Mat& logo)
{
cv::Mat imageROI;
imageROI = image(cv::Rect(385, 270, logo.cols, logo.rows)); //基本的相加方式
cv::addWeighted(imageROI, 1.0, logo, 3.0, 0., imageROI);
//掩模方式,将logo有值的位置上的image值置零
cv::Mat mask = cv::imread("..\\images\\logo.bmp", 0);
logo.copyTo(imageROI, mask);
}
 

在获取ROI时使用了cv::Rect类表示一个矩形框,包括偏移、大小属性。imageROI当然是in-place的引用方式,会改变输入图像的值。还有通过定义两个方向上的cv::Range来实现,都差不多。显然,操作符“()”是被重载的,返回一个子块。还可以通过行、列方式来指定,通过调用cv::Mat的rowRange()和colRange()方法。

opencv Mat 像素操作的更多相关文章

  1. python opencv:像素操作

    图片的像素 像素:组成图片的单位 RGB:颜色由 RGB三种颜色组成 颜色深度:对于8bit的颜色深度来说,它可以表示的颜色范围是 0 ~ 255,对于RGB图片来说,8位颜色深度可以表示 (2^8) ...

  2. 【OpenCV】像素操作的数字图像处理

    之前几天捣鼓matlab,用来处理数字图像,矩阵操作什么的,如果忘记线性代数就真的GG了. 在用了matlab被深深地吐槽之后,决定改用opencv,C++貌似也是处理数字图像的很好的工具 1. 在u ...

  3. Opencv Mat的操作

    cout << mat 有错误的原因 You are using OpenCV built with VS10. The ostream operator << in the ...

  4. opencv MAT数据操作

    1.存取单个像素值 最通常的方法就是 img.at<uchar>(i,j) = 255; img.at<Vec3b>(i,j)[0] = 255; 2.用指针扫描一幅图像 对于 ...

  5. OpenCv图像像素操作

    1:像素 有两种直接操作像素点的方法: 第一种: 将其转化为numpy.array格式,直接进行操作. 第二种:使用Opencv提供的Get1D,Get2D等函数. 2:获取行和列像素 有一下四个函数 ...

  6. Opencv Mat矩阵操作注意事项

    矩阵操作通常不会进行元素复制,应注意: Mat a=Mat(100,100,CV_32S); Mat b=Mat(100,100,CV_32S); b=a.col(8);//此时并未进行元素赋值,而只 ...

  7. Opencv中图像的遍历与像素操作

    Opencv中图像的遍历与像素操作 OpenCV中表示图像的数据结构是cv::Mat,Mat对象本质上是一个由数值组成的矩阵.矩阵的每一个元素代表一个像素,对于灰度图像,像素是由8位无符号数来表示(0 ...

  8. opencv中对图像的像素操作

    1.对灰度图像的像素操作: #include<iostream> #include<opencv2/opencv.hpp> using namespace std; using ...

  9. OpenCV像素操作和图形绘制

    像素操作 #include<iostream> #include<opencv2/opencv.hpp> using namespace std; using namespac ...

随机推荐

  1. hit-testing机制介绍

    1.简介 寻找处理触摸事件的view的过程为hit-testing,找到的能够处理触摸事件的view叫做hit-test view. 2.机制介绍 假设下图为我们的手机屏幕,当我们假设点击了view ...

  2. CentOS下配置FTP

    http://www.cnblogs.com/zhenmingliu/archive/2012/04/25/2470646.html 常见错误: 1.FTP服务器已经拒绝 解决方案 # setenfo ...

  3. js cookies的使用及介绍 (非常详细)

    设置cookie 每个cookie都是一个名/值对,可以把下面这样一个字符串赋值给document.cookie:document.cookie="userId=828";如果要一 ...

  4. MYSQL表中设置字段类型为TIMESTAMP时的注意事项

    在MYSQL中,TIMESTAMP类型是用来表示日期的,但是和DATETIME不同,不同点就不再这里说明了. 当我们在使用TIMESTAMP类型设置表中的字段时,我们应该要注意一点,首先我们在表中新增 ...

  5. Redis -- 过期时间 和 缓存 例子

    1.设置 key的生存时间,过期自动删除 exprire key  seconds    设置过期时间 秒数 ttl key   查询剩余时间 如果 设置了过期时间.对key进行 set 操作,会清除 ...

  6. 几条学习python的建议

    熟悉python语言, 以及学会python的编码方式. 熟悉python库, 遇到开发任务的时候知道如何去找对应的模块. 知道如何查找和获取第三方的python库, 以应付开发任务. 学习步骤 安装 ...

  7. mysql性能分析-------profiling和explain

    1. profiling之性能分析 MySQL5.0.37版本以上支持了Profiling – 官方手册.此工具可用来查询 SQL 会执行多少时间,System lock和Table lock 花多少 ...

  8. js字符串与Unicode编码互相转换

    ).toString() "597d" 这段代码的意思是,把字符'好'转化成Unicode编码,toString()就是把字符转化成16进制了 看看charCodeAt()是怎么个 ...

  9. 关于k8s里的service互访,有说法

    昨天,测试了一个项目的接入.明白了以下几个坑: 1,traefik有可能有性能问题,如果daemonset安装,可重建.也需要通过8580端口查看性能. 2,集群中的service访问自己时,好像性能 ...

  10. [Bootstrap]modal弹出框

    写在前面 在实际开发中,为了友好,更需要一种美观的弹出框,js原生的alert,很难满足需求.这里推荐一个bootstrap的弹出框. 一个例子 先看效果吧 代码: <!DOCTYPE html ...