学习opencv day3

操作像素

1、访问像素值

1、at方法

image.at<uchar>(j,i)= 255;//灰度
image.at<cv::Vec3b>(j,i)[channel]= value;//彩色像素

随机数生成器

 // C++11 的随机数生成器
 std::default_random_engine generator;
 std::uniform_int_distribution<int>
			  randomRow(0, image.rows - 1);
 std::uniform_int_distribution<int>
			  randomCol(0, image.cols - 1); 

随机数由生成器和分布器结合产生
  生成器generator:能够产生离散的等可能分布数值
  分布器distributions: 能够把generator产生的均匀分布值映射到其他常见分布,如均匀分布uniform,正态分布normal,二项分布binomial,泊松分布poisson
  种子:相当于外部传给随机数生成器的诱因,如果每次传入的种子一样,则每次生成的随机数还是一样
  
cv::Mat_模板类
因为每次调用都必须在模板参数中指明返回类型,所以 cv::Mat 类的 at 方法有时会显得冗长。如果已经知道矩阵的类型,就可以使用 cv::Mat_类(cv::Mat 类的模板子类)。cv::Mat_类定义了一些新的方法,但没有定义新的数据属性,因此这两个类的指针或引用可以直接互相转换。
新方法中有一个 operator(),可用来直接访问矩阵的元素。因此可以这样写代码(其中 image是一个对应 uchar 矩阵的 cv::Mat 变量):

// 用 Mat 模板操作图像
cv::Mat_<uchar> img(image);
img(50,100)= 0; // 访问第 50 行、第 100 列处那个值

CV_Assert函数

// 限制图像为灰度图像
	CV_Assert(image.type() == CV_8UC1);

2、.ptr和[]操作符

为了简化指针运算的计算过程,Mat最直接的访问方法是通过.ptr<>函数得到一行的指针,并用[]操作符访问某一列的像素值。

//返回第 j 行的地址:
uchar* data= image.ptr<uchar>(j); 

用 cols和 rows 属性可得到图像的宽度和高度。与之类似,用 step 数据属性可得到单位是字节的有效宽度。即使图像的类型不是 uchar,step 仍然能提供行的字节数。我们可以通过 elemSize方法(例如一个三通道短整型的矩阵 CV_16SC3,elemSize 会返回 6)获得像素的大小,通过 nchannels 方法(灰度图像为 1,彩色图像为 3)获得图像中通道的数量,最后用 total方法返回矩阵中的像素(即矩阵的条目)总数。
用下面的代码可获得每一行中像素值的个数:

int nc= image.cols * image.channels(); 

示例代码:

//减色函数,利用整数除法的特性,即取不超过又最接近结果的整数
//处理过程很简单,只要创建一个二重循环遍历所有像素值,代码如下所示:
void colorReduce(cv::Mat image, int div=64) {
 int nl= image.rows; // 行数
 // 每行的元素数量
 int nc= image.cols * image.channels();
 for (int j=0; j<nl; j++) {
 	// 取得行 j 的地址
 	uchar* data= image.ptr<uchar>(j);
 	for (int i=0; i<nc; i++) {
	// 处理每个像素 ---------------------
		data[i]= data[i]/div*div + div/2;
	// 像素处理结束 ----------------
 	} // 一行结束
 }
}

我们也可以在处理语句中采用另一种等价的做法,即利用指针运算从一列移到下一列。

*data++= *data/div*div + div2;

减色计算也可以使用取模运算符,它可以直接得到 div 的倍数,代码如下所示:

data[i]= data[i] – data[i]%div + div/2; 

另外还可以使用位运算符。如果把减色因子限定为 2 的指数,即 div=pow(2,n),那么把像素值的前 n 位掩码后就能得到最接近的 div 的倍数。可以用简单的位移操作获得掩码,代码如下所示:

// 用来截取像素值的掩码
uchar mask= 0xFF<<n; // 如 div=16,则 mask= 0xF0
//可用下面的代码实现减色运算:
*data &= mask; // 掩码
*data++ += div>>1; // 加上 div/2
// 这里的+也可以改用“按位或”运算符
//*data++ |= div>>1;

一般来说,使用位运算的代码运行效率很高,因此在效率为重时,位运算是不二之选。

检查
为确保完整性,测试时还需要检查矩阵是否只有一行;如果是,这个矩阵就是连续的。但是不管哪种情况,都可以用 isContinuous 方法检查矩阵的连续性。

if (image.isContinuous()) {
 // 没有填充的像素
 nc= nc*nl;
 nl= 1; // 它现在成了一个一维数组
 } 
 //或者使用reshape
 if (image.isContinuous())
{
 // 没有填充像素
 image.reshape(1, // 新的通道数
 1); // 新的行数
} 

一些需要注意的东西

1、

uchar div2 = div >> 1; // div2 = div/2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值