【openCV入门之四】 Core组件进阶

Core组件进阶

 

1.        访问图像中的像素

1.1.       图像在内存中的存储方式

图像在内存中一般在内存足够大的系统中可以连续存储,连续存储有助于提升图像扫描速度,可以用isContinuous()来判断矩阵是否是连续存储的。

另外OpenCV的矩阵中包含很多子列,子列的个数与通道数相等,通道顺序是反过来的BGR而不是RGB.

1.2.       颜色空间缩减

三通道的图像,像素颜色最多有1600,0000种,如此之多的颜色格式,在很多系统中是不必要的,所以需要用到颜色空间缩减– color space reduction。

 

颜色空间缩减通过当前颜色空间值除以某个输入值实现,即把对颜色空间值抽取一些值。而不是每个都要。

通过缩减运算公式:

在处理图像是以上的公式的每次的运算本身就要耗费很多开销,如果把像素值预先做成表,在后续图像的处理中通过查表方式会快一些。

1.3.       LUT函数:Look uptable

 

1.4.       计时函数

函数名

功能

实例

GetTickCount()

返回某个时间到当前的时钟周期数

double time0 = static_cast<double>(getTickCount());  

time0 = ((double)getTickCount() - time0)/getTickFrequency();

GetTickFrequency()

返回CPU一秒钟所走的周期数

 

1.5.       访问图像中像素的三类方法

1.5.1.      用指针操作像素

用指针的方法特点是速度比较快:

voidcolorReduce(Mat& inputImage, Mat& outputImage, int div) 

         //参数准备

         outputImage = inputImage.clone();  //拷贝实参到临时变量

         int rowNumber = outputImage.rows;  //行数

         int colNumber =outputImage.cols*outputImage.channels(); //列数 x 通道数=每一行元素的个数

 

         //双重循环,遍历所有的像素值

         for(int i = 0;i < rowNumber;i++)  //行循环

         { 

                   uchar* data =outputImage.ptr<uchar>(i);  //获取第i行的首地址

                   for(int j = 0;j <colNumber;j++)   //列循环

                   {    

                            // ---------【开始处理每个像素】-------------    

                            data[j] =data[j]/div*div + div/2; 

                            // ----------【处理结束】---------------------

                   }  //行处理结束

         } 

1.5.2.      用迭代器操作像素

用迭代器操作像素的特点是安全。

voidcolorReduce(Mat& inputImage, Mat& outputImage, int div) 

         //参数准备

         outputImage = inputImage.clone();  //拷贝实参到临时变量

         //获取迭代器

         Mat_<Vec3b>::iterator it =outputImage.begin<Vec3b>();  //初始位置的迭代器

         Mat_<Vec3b>::iterator itend =outputImage.end<Vec3b>();  //终止位置的迭代器

         //存取彩色图像像素

         for(;it != itend;++it) 

         { 

                   // ------------------------【开始处理每个像素】--------------------

                   (*it)[0] = (*it)[0]/div*div +div/2; 

                   (*it)[1] = (*it)[1]/div*div +div/2; 

                   (*it)[2] = (*it)[2]/div*div +div/2; 

                   // ------------------------【处理结束】----------------------------

         } 

}

1.5.3.      动态地址计算

动态地址运算配合at方法:

Vec3b向量:彩色图像的Mat,返回一个有三个8位数组成的向量。

image.at<Vec3b>(i,j)[channel]= value;

 

voidcolorReduce(Mat& inputImage, Mat& outputImage, int div) 

         //参数准备

         outputImage = inputImage.clone();  //拷贝实参到临时变量

         int rowNumber = outputImage.rows;  //行数

         int colNumber = outputImage.cols;  //列数

 

         //存取彩色图像像素

         for(int i = 0;i <rowNumber;i++) 

         { 

                   for(int j = 0;j <colNumber;j++) 

                   {    

                            // ------------------------【开始处理每个像素】--------------------

                            outputImage.at<Vec3b>(i,j)[0]= outputImage.at<Vec3b>(i,j)[0]/div*div + div/2;  //蓝色通道

                            outputImage.at<Vec3b>(i,j)[1]= outputImage.at<Vec3b>(i,j)[1]/div*div + div/2;  //绿色通道

                            outputImage.at<Vec3b>(i,j)[2]= outputImage.at<Vec3b>(i,j)[2]/div*div + div/2;  //红是通道

                            //-------------------------【处理结束】----------------------------

                   }  // 行处理结束    

         } 

2.        ROI区域图像叠加和图像混合

2.1.       感兴趣的区域: ROI

ROI, region of interest.

l  ROI的好处

圈定区域并在这个区域做一些操作可以减少处理时间,增加精度。

l  定义ROI区域的方法

1)   矩形区域Rect

Mat imageROI;

ImageROI =image(Rect(500,250,logo.cols,logo.rows));

其中Rect的:

第一个参数和第二个参数指定矩形的左上角坐标

第二个参数和第三个参数指定矩形的长度

2)   行或列的范围Range

ImageROI=image(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

起始索引到终止索引的一段连续序列。

l  ROI 实例

利用感兴趣区域实现图像叠加:

bool  ROI_AddImage()

{

      // 【1】读入图像

      Mat srcImage1=imread("dota_pa.jpg");

      Mat logoImage=imread("dota_logo.jpg");

      if( !srcImage1.data ) { printf("读取srcImage1错误~! \n");return false; }

      if( !logoImage.data ) { printf("读取logoImage错误~! \n"); returnfalse; }

      // 【2】定义一个Mat类型并给其设定ROI区域

      Mat imageROI=srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));

      // 【3】加载掩模(必须是灰度图)

      Mat mask=imread("dota_logo.jpg",0);

      //【4】将掩膜拷贝到ROI

      logoImage.copyTo(imageROI,mask);

      // 【5】显示结果

      namedWindow("<1>利用ROI实现图像叠加示例窗口");

      imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);

      return true;

}

 

2.2.       线性混合操作

线性混合操作是一种典型的二元(两个输入)的像素操作,公式:

(x)

(x) 分别表示两幅图像或是两段视频产生时间上的叠化效果

Cross-dissolve。

2.3.       计算数组加权和:addWeighted()函数

void addWeighted(InputArray src1, double alpha, InputArray src2,

                              double beta, doublegamma, OutputArray dst, int                       dtype=-1)

参数列表

描述

src1

表示要加权的第一个数组,常常填一个Mat

alpha

表示第一个数组的权重

src2

表示第二个数组,它需要和第一个数组有相同的尺寸和通道数

beta

第二个数组的权重值

gamma

一个加到权重综合上的标量值

dst

输出的数组,它和输入的两个数组拥有相同的尺寸和通道数

dtype

输出阵列的可选深度,当两个输入数组具有相同的深度时,这个参数设置为-1,即等同于src1.depth()

 

下面公式表示函数计算的两个数组的加权和,结果输出给第四个参数。

公式:dst = src1[I] * alpha + src2[I]*beta + gamma;

I 为多维数组的索引值。

多通道数组每个通道需要独立的进行处理。

深度CV_32S是,函数不适用,回导致溢出或是结果不对。

例子,    addWeighted函数实现图像的线性混合:

bool  LinearBlending()

{

         //【0】定义一些局部变量

         double alphaValue = 0.1;

         double betaValue;

         Mat srcImage2, srcImage3, dstImage;

 

         // 【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )

         srcImage2 = imread("mogu.jpg");

         srcImage3 = imread("rain.jpg");

 

         if( !srcImage2.data ) { printf("读取srcImage2错误!\n"); return false; }

         if( !srcImage3.data ) { printf("读取srcImage3错误!\n"); return false; }

 

         // 【2】进行图像混合加权操作

         betaValue = ( 1.0 - alphaValue );

         addWeighted( srcImage2, alphaValue, srcImage3, betaValue,0.0, dstImage);

 

         // 【3】显示原图窗口

         imshow( "<2>线性混合示例窗口【原图】", srcImage2 );

         imshow( "<3>线性混合示例窗口【效果图】", dstImage );

         return true;

}

2.4.       初级图像混合

利用addWeighted()函数结合定义感兴趣区域ROI,实现自定义区域的线性混合

bool ROI_LinearBlending()

{

 

//【1】读取图像

MatsrcImage4= imread("dota_pa.jpg",1);

MatlogoImage= imread("dota_logo.jpg");

 

if(!srcImage4.data ) { printf("读取srcImage4错误~!\n"); return false; }

if(!logoImage.data ) { printf("读取logoImage错误~!\n"); return false; }

 

//【2】定义一个Mat类型并给其设定ROI区域

MatimageROI;

//方法一

imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));

//方法二

//imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

 

//【3】将logo加到原图上

addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);

 

//【4】显示结果

imshow("<4>区域线性图像混合示例窗口",srcImage4);

 

returntrue;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值