opencv学习(5)图像像素的访问、颜色通道的分离和融合

代码都是源于毛星云的《opencv3.0编程入门》

1、计时函数

getTickCount()和getTickFrequency()函数;

getTickCount()函数返回CPU自某个事件以来走过的时钟周期;

getTickFrequency()函数 返回CPU一秒所走的周期数;

事例:

double time0=static_cast< double>(getTickCount()); //记录起始时间
// 事件的处理操作
time0=((double)getTickCount()-time0)/getTickFrequency();
cout<<"此方法的运行时间为:"<< time0<<"秒"<< endl;

2、访问图像像素中的三类方法:

1)【方法一】指针访问:C操作符[ ];

2)【方法二】迭代器iterator;

3)【方法三】动态地址计算;

主程序代码:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;  

void colorReduce(Mat& inputImage, Mat& outputImage, int div);

int main( )
{
    //【1】创建原始图并显示
    Mat srcImage = imread("1.jpg");
    imshow("原始图像",srcImage);  

    //【2】按原始图的参数规格来创建创建效果图
    Mat dstImage;
    dstImage.create(srcImage.rows,srcImage.cols,srcImage.type());//效果图的大小、类型与原图片相同 

    //【3】记录起始时间
    double time0 = static_cast<double>(getTickCount());  

    //【4】调用颜色空间缩减函数
    colorReduce(srcImage,dstImage,32);  

    //【5】计算运行时间并输出
    time0 = ((double)getTickCount() - time0)/getTickFrequency();
    cout<<"\t此方法运行时间为: "<<time0<<"秒"<<endl;  //输出运行时间

    //【6】显示效果图
    imshow("效果图",dstImage);
    waitKey(0);
}

【方法一】指针访问:C操作符[ ];

速度最快,但有点抽象;

void colorReduce(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;
            // ----------【处理结束】---------------------
        }  //行处理结束
    }
}  

Mat类中:公有成员变量cols和rows给出了图像的宽和高;成员函数channels()用于返回图像的通道数;

每行的像素个数:`int colNumber=outputImage.cols*outputImage.channels();

Mat 类提供了ptr函数可以得到图像任意行的首地址。ptr是一个模板函数,返回第i行的首地址;

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

【方法二】迭代器iterator;

void colorReduce(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;
        // ------------------------【处理结束】----------------------------
    }
}  

在迭代器中我们需要的仅仅是获取图像矩阵的begin和end,将*操作符添加在迭代器指针前,即可访问当前指向的内容;

3)【方法三】动态地址计算;

void colorReduce(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;  //红是通道
            // -------------------------【处理结束】----------------------------
        }  // 行处理结束
    }
}  

动态地址运算配合at方法的colorReduce函数;

3、分离颜色通道、多通道图像的混合

1)通道分离:split( )函数;

split( )函数的C++版本有两个原型;分别是:

void split(const Mat& src,Mat* mvbegin);

void split(InputArray m,OutputArrayOfArrays mv);

第一个参数,InputArray类型的m或者const Mat&类型的src,是需要进行分离的多通道数组;

第二个参数,OutputArrayOfArrays类型的mv,填函数的输出数组或者输出的vector容器。

我们一起看一个示例。

vector<Mat> channels;
Mat imageBlueChannel;
Mat imageGreenChannel;
Mat imageRedChannel;
srcImage4= imread("dota.jpg");
// 把一个 3 通道图像转换成 3 个单通道图像
split(srcImage4,channels);//分离色彩通道
imageBlueChannel = channels.at(0);
imageGreenChannel = channels.at(1);
imageRedChannel = channels.at(2);

上面的代码先做了相关的类型声明,然后把载入的 3 通道图像转换成 3 个单通道图像,放到vector类型的 channels 中,接着进行引用赋值。

根据 OpenCV 的 BGR 色彩空间(Blue、Green、Red,蓝绿红),其中 channels.at(0)就表示引用取出 channels 中的蓝色分量,channels.at(1)就表示引用取出 channels 中的绿色色分量,channels.at(2)就表示引用取出 channels 中的红色分量。

将一个多通道数组分离成几个单通道数组的 split()函数的内容大概就是以上这些了,下面我们来看一下和它关系密切的 merge()函数。

2)通道合并:merge( )函数;

依然是一个示例,综合了 split()函数和 merge()函数的使用,先将图像的通道进行拆分,再将通道合并。具体代码如下所示。

//定义一些 Mat 对象
Mat srcImage=imread("1.jpg");
Mat imageBlueChannel, imageGreenChannel, imageRedChannel,mergeImage;
//定义 Mat 向量容器保存拆分后的数据
vector<Mat> channels;
//通道的拆分
split(srcImage,channels);
//提取三色的通道的数据
imageBlueChannel = channels.at(0);
imageGreenChannel = channels.at(1);
imageRedChannel = channels.at(2);
//对拆分的通道数据合并
merge(channels,mergeImage);
//显示最终的合并效果
imshow("mergeImage",mergeImage);

一对做相反操作的 split()函数和 merge()函数和用法就是这些。另外提一点,如果我们需要从多通道数组中提取出特定的单通道数组,或者说实现一些复杂的通道组合,可以使用 mixChannels()函数。

以其中的蓝色通道为例:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;
int main()
{
    Mat srcImage;
    Mat logoImage;
    vector<Mat> channels;

    Mat  imageBlueChannel;
    Mat  imageGreenChannel;
    Mat  imageRedChannel;

    //=================【蓝色通道部分】=================
    // 【1】读入图片
    logoImage = imread("dota_logo.jpg", 0);
    srcImage = imread("dota_jugg.jpg");

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

    //【2】把一个3通道图像转换成3个单通道图像
    split(srcImage, channels);//分离色彩通道

    //【3】将原图的蓝色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
    imageBlueChannel = channels.at(0);
    //【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中。简单讲就是原图的蓝色通道加上了logo替换了原始的蓝色通道。
    addWeighted(imageBlueChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0,
        logoImage, 0.5, 0, imageBlueChannel(Rect(500, 250, logoImage.cols, logoImage.rows)));

    //【5】将三个单通道重新合并成一个三通道
    merge(channels,srcImage);

    //【6】显示效果图
    namedWindow(" <1>游戏原画+logo蓝色通道");
    imshow(" <1>游戏原画+logo蓝色通道", srcImage);
    waitKey(0);
    return 0;
}

时间: 2024-08-06 20:04:39

opencv学习(5)图像像素的访问、颜色通道的分离和融合的相关文章

OpenCV 基础知识------图像创建、访问、转换

cvCreateImage函数-- Cxcore数组操作 创建头并分配数据 IplImage* cvCreateImage( CvSize size, int depth, int channels ); size 图像宽.高. depth 图像元素的位深度,可以是下面的其中之一: IPL_DEPTH_8U - 无符号8位整型 IPL_DEPTH_8S - 有符号8位整型 IPL_DEPTH_16U - 无符号16位整型 IPL_DEPTH_16S - 有符号16位整型 IPL_DEPTH_32

OpenCV基础(二)---图像像素操作

图像像素操作 通过访问图像的像素,对灰度图像和RGB图像进行反差. 例如,在灰度图像中,某一个像素值为,pixel_value. 那么反差后的pixel_value = 255 - pixel_value. 对RGB图像处理类似,差别在于要对每一个颜色通道进行反差. 方法1: 1 #include <opencv2/opencv.hpp> 2 #include <iostream> 3 4 using namespace cv; 5 using namespace std; 6 7

opencv学习笔记-图像叠加、混合

在图像处理中,目标区域定义为感兴趣区域ROI(region of Interest),这是后期图像处理的基础,在获取ROI后,进行一些列的处理.ROI区域在Opencv中就是Rect,先构建Rect,然后给予ROI一些特点,形成了图像掩膜. 一.ROI创建 //定义一个Mat类型并给其设定ROI区域 Mat imageROI; //方法一 imageROI=image(Rect(500,250,logo.cols,logo.rows)); //方法二 imageROI=Image(Range(2

Python下的OpenCV学习 02 —— 图像的读取与输出

OpenCV提供了众多对图片操作的函数,其中最基本的就是图片的读取与输出了. 一.读取图片 利用OpenCV读取一张图片是非常容易的,只需要用到 imread() 函数,我们进入IPython,输入help(cv2.imread)获取该函数的文档,得到: imread(...)     imread(filename[, flags]) -> retval 可见, imread需要提供两个参数,第一个是图片的路径,第二个是图片读取的模式(flags),函数返回一个存储着图片像素数据的矩阵. fl

OpenCV学习:图像的载入和显示

一.使用IplImage结构读取并显示图像文件: 运行结果: 二.使用Mat类读取并显示图像文件: 使用 Mat 类,内存管理变得简单,不再像使用 IplImage 那样需要自己申请和释放内存,而且一些函数,如imread.imshow以及imwrite等与之前用过的matlab图像处理工具箱同名,使用起来非常方便. 运行结果:

OpenCV默认颜色通道

网上查了一下,OpenCV读取图片之后Mat默认的颜色通道都说是BGR,有点不信,试了一下,先用PS做一张纯色的图片,还有颜色的RGB值       然后用OpenCV读取图片之后读取RGB值逐一显示出来: 1 // OpenCV_default_color_channel.cpp : 定义控制台应用程序的入口点. 2 // 3 4 5 #include "opencv2/core/core.hpp" 6 #include "opencv2/highgui/highgui.h

opencv高效访问图像像素(遍历像素的方法总结)

一.Accessingpixel values访问像素值.(用类自带的方法:方便,但效率不高) 1.      cv::Mat has the a templatemethod at(int y, int x) 用法image.at<cv::Vec3b>(j,i)[channel]= value; 注意事项:the programmer needs to specify the return type that is expected(需认为指定返回值类型),一般使用type cv::Vec3

opencv 访问图像像素的三种方式

访问图像中的像素 访问图像像素有三种可行的方法方法一:指针访问指针访问访问的速度最快,Mat类可以通过ptr函数得到图像任意一行的首地址,同时,Mat类的一些属性也可以用到公有属性 rows和cols 表示行和列通道数可以通过channels()函数获得:void visitPix1(){ Mat srcImg = imread("jpg/1.jpeg"); Mat dstImg; srcImg.copyTo(dstImg); int rowNum = dstImg.rows; int

opencv学习笔记(01)——操作图像的像素

1 #include <opencv2\core\core.hpp> 2 #include <opencv2\highgui\highgui.hpp> 3 #include <opencv2\imgproc\imgproc.hpp> 4 #include <iostream> 5 6 7 void salt(cv::Mat& image, int n) 8 { 9 10 for(int k=0; k<n; k++) 11 { 12 13 int